From 3edb44ada71e6cba49a0b4d4dfa67fce4756c0f9 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 23 Sep 2014 11:41:05 -0600 Subject: Flesh out shmctl() logic --- nuttx/mm/shm/shm.h | 27 ++++++++ nuttx/mm/shm/shmctl.c | 177 +++++++++++++++++++++++++++++++++++++++++++++----- nuttx/mm/shm/shmget.c | 20 +++++- 3 files changed, 203 insertions(+), 21 deletions(-) (limited to 'nuttx/mm/shm') diff --git a/nuttx/mm/shm/shm.h b/nuttx/mm/shm/shm.h index 09f7ebd67..63ed9e51e 100644 --- a/nuttx/mm/shm/shm.h +++ b/nuttx/mm/shm/shm.h @@ -102,5 +102,32 @@ extern struct shm_info_s g_shminfo; * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: shm_destroy + * + * Description: + * Destroy a memory region. This function is called: + * + * - On certain conditions when shmget() is not successful in instantiating + * the full memory region and we need to clean up and free a table entry. + * - When shmctl() is called with cmd == IPC_RMID and there are no + * processes attached to the memory region. + * - When shmdt() is called after the last process detaches from memory + * region after it was previously marked for deletion by shmctl(). + * + * Input Parameters: + * shmid - Shared memory identifier + * + * Returned Value: + * None + * + * Assumption: + * The caller holds either the region table semaphore or else the + * semaphore on the particular entry being deleted. + * + ****************************************************************************/ + +void shm_destroy(int shmid); + #endif /* CONFIG_MM_SHM */ #endif /* __MM_SHM_SHM_H */ diff --git a/nuttx/mm/shm/shmctl.c b/nuttx/mm/shm/shmctl.c index 9721e88cb..07ed9913b 100755 --- a/nuttx/mm/shm/shmctl.c +++ b/nuttx/mm/shm/shmctl.c @@ -41,7 +41,17 @@ #include #include +#include +#include +#include +#include #include +#include + +#include +#include + +#include "shm/shm.h" #ifdef CONFIG_MM_SHM @@ -78,26 +88,13 @@ * structure associated with shmid into the structure pointed to by * buf. * - IPC_SET - * Set the value of the following members of the shmid_ds data + * Set the value of the shm_perm.mode member of the shmid_ds data * structure associated with shmid to the corresponding value found - * in the structure pointed to by buf: - * - * shm_perm.uid - * shm_perm.gid - * shm_perm.mode Low-order nine bits. - * - * IPC_SET can only be executed by a process that has an effective - * user ID equal to either that of a process with appropriate - * privileges or to the value of shm_perm.cuid or shm_perm.uid in the - * shmid_ds data structure associated with shmid. + * in the structure pointed to by buf. * - IPC_RMID * Remove the shared memory identifier specified by shmid from the * system and destroy the shared memory segment and shmid_ds data - * structure associated with it. IPC_RMID can only be executed by a - * process that has an effective user ID equal to either that of a - * process with appropriate privileges or to the value of - * shm_perm.cuid or shm_perm.uid in the shmid_ds data structure - * associated with shmid. + * structure associated with it. * * Input Parameters: * shmid - Shared memory identifier @@ -124,13 +121,157 @@ * The cmd argument is IPC_STAT and the gid or uid value is too large * to be stored in the structure pointed to by the buf argument. * + * POSIX Deviations: + * - IPC_SET. Does not set the the shm_perm.uid or shm_perm.gid + * members of the shmid_ds data structure associated with shmid + * because user and group IDs are not yet supported by NuttX + * - IPC_SET. Does not restrict the operation to processes with + * appropriate privileges or matching user IDs in shmid_ds data + * structure associated with shmid. Again because user IDs and + * user/group privileges are are not yet supported by NuttX + * - IPC_RMID. Does not restrict the operation to processes with + * appropriate privileges or matching user IDs in shmid_ds data + * structure associated with shmid. Again because user IDs and + * user/group privileges are are not yet supported by NuttX + * ****************************************************************************/ int shmctl(int shmid, int cmd, struct shmid_ds *buf) { -#warning Not implemented - set_errno(ENOSYS); + FAR struct shm_region_s *region; + int ret; + + DEBUGASSERT(shmid >= 0 && shmid < CONFIG_ARCH_SHM_MAXREGIONS); + region = &g_shminfo.si_region[shmid]; + DEBUGASSERT((region->sr_flags & SRFLAG_INUSE) != 0); + + /* Get exclusive access to the region data structure */ + + ret = sem_wait(®ion->sr_sem); + if (ret < 0) + { + shmdbg("sem_wait failed: %d\n", ret); + return ret; + } + + /* Handle the request according to the received cmd */ + + switch (cmd) + { + case IPC_STAT: + { + /* Place the current value of each member of the shmid_ds data + * structure associated with shmid into the structure pointed to + * by buf. + */ + + DEBUGASSERT(buf); + memcpy(buf, ®ion->sr_ds, sizeof(struct shmid_ds)); + } + break; + + case IPC_SET: + { + /* Set the value of the shm_perm.mode member of the shmid_ds + * data structure associated with shmid to the corresponding + * value found in the structure pointed to by buf. + */ + + region->sr_ds.shm_perm.mode = buf->shm_perm.mode; + } + break; + + case IPC_RMID: + { + /* Are any processes attached to the region? */ + + if (region->sr_ds.shm_nattch > 0) + { + /* Yes.. just set the UNLINKED flag. The region will be removed when there are no longer any processes attached to it. + */ + + region->sr_flags |= SRFLAG_UNLINKED; + } + else + { + /* No.. free the entry now */ + + shm_destroy(shmid); + + /* Don't try anything further on the deleted region */ + + return OK; + } + } + break; + + default: + shmdbg("Unrecognized command: %d\n", cmd); + ret = -EINVAL; + goto errout_with_semaphore; + } + + /* Save the process ID of the the last operation */ + + region = &g_shminfo.si_region[shmid]; + region->sr_ds.shm_lpid = getpid(); + + /* Save the time of the last shmctl() */ + + region->sr_ds.shm_ctime = time(NULL); + + /* Release our lock on the entry */ + + sem_post(®ion->sr_sem); + return ret; + +errout_with_semaphore: + sem_post(®ion->sr_sem); + set_errno(-ret); return ERROR; } +/**************************************************************************** + * Name: shm_destroy + * + * Description: + * Destroy a memory region. This function is called: + * + * - On certain conditions when shmget() is not successful in instantiating + * the full memory region and we need to clean up and free a table entry. + * - When shmctl() is called with cmd == IPC_RMID and there are no + * processes attached to the memory region. + * - When shmdt() is called after the last process detaches from memory + * region after it was previously marked for deletion by shmctl(). + * + * Input Parameters: + * shmid - Shared memory identifier + * + * Returned Value: + * None + * + * Assumption: + * The caller holds either the region table semaphore or else the + * semaphore on the particular entry being deleted. + * + ****************************************************************************/ + +void shm_destroy(int shmid) +{ + FAR struct shm_region_s *region = &g_shminfo.si_region[shmid]; + int i; + + /* Free all of the allocated physical pages */ + + for (i = 0; i < CONFIG_ARCH_SHM_NPAGES && region->sr_pages[i] != 0; i++) + { + mm_pgfree(region->sr_pages[i], 1); + } + + /* Reset the region entry to its initial state */ + + sem_destroy(®ion->sr_sem); + memset(region, 0, sizeof(struct shm_region_s)); +} + #endif /* CONFIG_MM_SHM */ diff --git a/nuttx/mm/shm/shmget.c b/nuttx/mm/shm/shmget.c index 1790f8e53..3aa8f0bff 100755 --- a/nuttx/mm/shm/shmget.c +++ b/nuttx/mm/shm/shmget.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -251,6 +252,7 @@ static int shm_extend(int shmid, size_t size) static int shm_create(key_t key, size_t size, int shmflg) { + FAR struct shm_region_s *region; int shmid; int ret; @@ -275,11 +277,16 @@ static int shm_create(key_t key, size_t size, int shmflg) if (ret < 0) { /* Free any partial allocations and unreserve the region */ -#warning "Missing logic" + shm_destroy(shmid); return ret; } + /* Save the process ID of the creator */ + + region = &g_shminfo.si_region[shmid]; + region->sr_ds.shm_cpid = getpid(); + /* Return the shared memory ID */ return shmid; @@ -431,7 +438,7 @@ int shmget(key_t key, size_t size, int shmflg) /* Is the region big enough for the request? */ - region = &g_shminfo.si_region[shmid]; + region = &g_shminfo.si_region[shmid]; if (region->sr_ds.shm_segsz < size) { /* We we asked to create the region? If so we can just @@ -460,6 +467,14 @@ int shmget(key_t key, size_t size, int shmflg) goto errout_with_semaphore; } } + + /* The region is already big enough or else we successfully + * extended the size of the region. If the region was previously + * deleted, but waiting for processes to detach from the region, + * then it is no longer deleted. + */ + + region->sr_flags = SRFLAG_INUSE; } /* Release our lock on the shared memory region list */ @@ -477,4 +492,3 @@ errout: } #endif /* CONFIG_MM_SHM */ - -- cgit v1.2.3