From c163691f9446061dbab259c62fb86b8c0ced0cff Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 23 Sep 2014 10:42:18 -0600 Subject: Flesh out basic logic for shmget() --- nuttx/mm/shm/shm.h | 12 +- nuttx/mm/shm/shm_initialize.c | 10 +- nuttx/mm/shm/shmget.c | 333 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 339 insertions(+), 16 deletions(-) (limited to 'nuttx/mm') diff --git a/nuttx/mm/shm/shm.h b/nuttx/mm/shm/shm.h index 0a05dce29..09f7ebd67 100644 --- a/nuttx/mm/shm/shm.h +++ b/nuttx/mm/shm/shm.h @@ -54,12 +54,11 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Bit definitions for the struct shm_region_s sr_flags field */ -/* IPC_PRIVATE is the only value for the the SHM key that is guaranteed to - * be invalid. - */ - -#define SHM_INVALID_KEY IPC_PRIVATE +#define SRFLAG_AVAILABLE 0 /* Available if no flag bits set */ +#define SRFLAG_INUSE (1 << 0) /* Bit 0: Region is in use */ +#define SRFLAG_UNLINKED (1 << 1) /* Bit 1: Region perists while references */ /**************************************************************************** * Public Types @@ -72,7 +71,8 @@ struct shm_region_s { struct shmid_ds sr_ds; /* Region info */ - key_t sr_key; /* Lookup key. IPC_PRIVATE means unused */ + bool sr_flags; /* See SRFLAGS_* definitions */ + key_t sr_key; /* Lookup key */ sem_t sr_sem; /* Manages exclusive access to this region */ /* List of physical pages allocated for this memory region */ diff --git a/nuttx/mm/shm/shm_initialize.c b/nuttx/mm/shm/shm_initialize.c index 1da2d4e2e..2b7d7d406 100755 --- a/nuttx/mm/shm/shm_initialize.c +++ b/nuttx/mm/shm/shm_initialize.c @@ -83,7 +83,7 @@ struct shm_info_s g_shminfo; void shm_initialize(void) { -#if SHM_INVALID_KEY != 0 +#if 0 FAR struct shm_region_s *region; int i; #endif @@ -92,18 +92,14 @@ void shm_initialize(void) sem_init(&g_shminfo.si_sem, 0, 1); -#if SHM_INVALID_KEY != 0 +#if 0 /* Initialize each shared memory region */ for (i = 0; i < CONFIG_ARCH_SHM_NPAGES; i++) { region = &g_shminfo.si_region[i]; - /* Markk the key invalid for each region. The invalid key is an - * indication that the region is not in use. - */ - - region->sr_key = SHM_INVALID_KEY; + /* Nothing to be done */ } #endif } diff --git a/nuttx/mm/shm/shmget.c b/nuttx/mm/shm/shmget.c index 3df1dd763..1790f8e53 100755 --- a/nuttx/mm/shm/shmget.c +++ b/nuttx/mm/shm/shmget.c @@ -41,8 +41,15 @@ #include #include +#include +#include #include +#include +#include + +#include "shm/shm.h" + #ifdef CONFIG_MM_SHM /**************************************************************************** @@ -61,6 +68,223 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: shm_find + * + * Description: + * Find the shared memory region with matching key + * + * Input parameters: + * key - The value that uniquely identifies a shared memory region. + * + * Returned value: + * On success, an index in the range of 0 to CONFIG_ARCH_SHM_MAXREGIONS-1 + * is returned to identify the matching region; -ENOENT is returned on + * failure. + * + ****************************************************************************/ + +static int shm_find(key_t key) +{ + int i; + + for (i = 0; i < CONFIG_ARCH_SHM_MAXREGIONS; i++) + { + if (g_shminfo.si_region[i].sr_key == key) + { + return i; + } + } + + return -ENOENT; +} + +/**************************************************************************** + * Name: shm_reserve + * + * Description: + * Allocate an unused shared memory region. That is one with a key of -1 + * + * Input parameters: + * None + * + * Returned value: + * On success, an index in the range of 0 to CONFIG_ARCH_SHM_MAXREGIONS-1 + * is returned to identify the matching region; -ENOSPC is returned on + * failure. + * + ****************************************************************************/ + +static int shm_reserve(key_t key, int shmflg) +{ + FAR struct shm_region_s *region; + int i; + + for (i = 0; i < CONFIG_ARCH_SHM_MAXREGIONS; i++) + { + /* Is this region in use? */ + + region = &g_shminfo.si_region[i]; + if (region->sr_flags == SRFLAG_AVAILABLE) + { + /* No... reserve it for the caller now */ + + memset(region, 0, sizeof(struct shm_region_s)); + region->sr_key = key; + region->sr_flags = SRFLAG_INUSE; + + sem_init(®ion->sr_sem, 0, 1); + + /* Set the low-order nine bits of shm_perm.mode to the low-order + * nine bits of shmflg. + */ + + region->sr_ds.shm_perm.mode = shmflg & IPC_MODE; + + /* The value of shm_segsz is left equal to zero for now because no + * memory has yet been allocated. + * + * The values of shm_lpid, shm_nattch, shm_atime, and shm_dtime are + * set equal to 0. + */ + + /* The value of shm_ctime is set equal to the current time. */ + + region->sr_ds.shm_ctime = time(NULL); + return i; + } + } + + return -ENOSPC; +} + +/**************************************************************************** + * Name: shm_extend + * + * Description: + * Extend the size of a memory regions by allocating physical pages as + * necessary + * + * Input parameters: + * shmid - The index of the region of interest in the shared memory region + * table. + * size - The new size of the region. + * + * Returned value: + * Zero is returned on success; -ENOMEM is returned on failure. + * (Should a different error be returned if the region is just too big?) + * + ****************************************************************************/ + +static int shm_extend(int shmid, size_t size) +{ + FAR struct shm_region_s *region = &g_shminfo.si_region[shmid]; + unsigned int pgalloc; + unsigned int pgneeded; + + /* This is the number of pages that are needed to satisfy the allocation */ + + pgneeded = MM_PGALIGNUP(size); + + /* This is the number of pages that have already been allocated */ + + pgalloc = MM_PGALIGNUP(region->sr_ds.shm_segsz); + + /* Loop until all pages have been allocated (or something bad happens) */ + + while (pgalloc < pgneeded && pgalloc < CONFIG_ARCH_SHM_NPAGES) + { + /* Allocate one more physical page */ + + region->sr_pages[pgalloc] = mm_pgalloc(1); + if (region->sr_pages[pgalloc] == 0) + { + shmdbg("mm_pgalloc(1) failed\n"); + break; + } + + /* Increment the number of pages successully allocated */ + + pgalloc++; + } + + /* We get here (1) because all of the pages were successfully, (2) because + * mm_pgalloc() failed, or (3) because any additional pages allocated + * would exceed CONFIG_ARCH_SHM_NPAGES. + */ + + if (pgalloc < pgneeded) + { + /* Set the amount memory available which will be less than the + * requested size. + */ + + region->sr_ds.shm_segsz = pgalloc << MM_PGSHIFT; + return -ENOMEM; + } + + /* Set the new region size and return success */ + + region->sr_ds.shm_segsz = size; + return OK; +} + +/**************************************************************************** + * Name: shm_create + * + * Description: + * Create the shared memory region. + * + * Input parameters: + * key - The key that is used to access the unique shared memory + * identifier. + * size - The shared memory region that is created will be at least + * this size in bytes. + * shmflgs - See IPC_* definitions in sys/ipc.h. Only the values + * IPC_PRIVATE or IPC_CREAT are supported. + * + * Returned value: + * Zero is returned on success; A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +static int shm_create(key_t key, size_t size, int shmflg) +{ + int shmid; + int ret; + + /* Reserve the shared memory region */ + + ret = shm_reserve(key, shmflg); + if (ret < 0) + { + shmdbg("shm_reserve failed: %d\n", ret); + return ret; + } + + /* Save the shared memory ID */ + + shmid = ret; + + /* Then allocate the physical memory (by extending it from the initial + * size of zero). + */ + + ret = shm_reserve(shmid, size); + if (ret < 0) + { + /* Free any partial allocations and unreserve the region */ +#warning "Missing logic" + + return ret; + } + + /* Return the shared memory ID */ + + return shmid; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -136,7 +360,7 @@ * POSIX Deviations: * - The values of shm_perm.cuid, shm_perm.uid, shm_perm.cgid, and * shm_perm.gid should be set equal to the effective user ID and - * effective group ID, respectively, of the calling process. + * effective group ID, respectively, of the calling process. * The NuttX ipc_perm structure, however, does not support these * fields because user and group IDs are not yet supported by NuttX. * @@ -144,8 +368,111 @@ int shmget(key_t key, size_t size, int shmflg) { -#warning Not implemented - set_errno(ENOSYS); + FAR struct shm_region_s *region; + int shmid = -1; + int ret; + + /* Check for the special case where the caller doesn't really want shared + * memory (they why do they bother to call us?) + */ + + if (key == IPC_PRIVATE) + { + /* Not yet implemented */ + + ret = -ENOSYS; + goto errout; + } + + /* Get exclusive access to the global list of shared memory regions */ + + ret = sem_wait(&g_shminfo.si_sem); + if (ret >= 0) + { + /* Find the requested memory region */ + + ret = shm_find(key); + if (ret < 0) + { + /* The memory region does not exist.. create it if IPC_CREAT is + * included in the shmflags. + */ + + if ((shmflg & IPC_CREAT) != 0) + { + /* Create the memory region */ + + ret = shm_create(key, size, shmflg); + if (ret < 0) + { + shmdbg("shm_create failed: %d\n", ret); + goto errout_with_semaphore; + } + + /* Return the shared memory ID */ + + shmid = ret; + } + else + { + /* Fail with ENOENT */ + + goto errout_with_semaphore; + } + } + + /* The region exists */ + + else + { + /* Remember the shared memory ID */ + + shmid = ret; + + /* Is the region big enough for the request? */ + + 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 + * extend it. + * + * REVISIT: We should check the mode bits of the regions + * first + */ + + if ((shmflg & IPC_CREAT) != 0) + { + /* Extend the region */ + + ret = shm_extend(shmid, size); + if (ret < 0) + { + shmdbg("shm_create failed: %d\n", ret); + goto errout_with_semaphore; + } + } + else + { + /* Fail with EINVAL */ + + ret = -EINVAL; + goto errout_with_semaphore; + } + } + } + + /* Release our lock on the shared memory region list */ + + sem_post(&g_shminfo.si_sem); + } + + return shmid; + +errout_with_semaphore: + sem_post(&g_shminfo.si_sem); +errout: + set_errno(-ret); return ERROR; } -- cgit v1.2.3