summaryrefslogtreecommitdiff
path: root/nuttx/mm
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-23 10:42:18 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-23 10:42:18 -0600
commitc163691f9446061dbab259c62fb86b8c0ced0cff (patch)
treefa82e0b4658c11c50df504dfd5925a48caf7ba17 /nuttx/mm
parentbf403f3bdf808c5dc5164a56a84074051b531ad8 (diff)
downloadpx4-nuttx-c163691f9446061dbab259c62fb86b8c0ced0cff.tar.gz
px4-nuttx-c163691f9446061dbab259c62fb86b8c0ced0cff.tar.bz2
px4-nuttx-c163691f9446061dbab259c62fb86b8c0ced0cff.zip
Flesh out basic logic for shmget()
Diffstat (limited to 'nuttx/mm')
-rw-r--r--nuttx/mm/shm/shm.h12
-rwxr-xr-xnuttx/mm/shm/shm_initialize.c10
-rwxr-xr-xnuttx/mm/shm/shmget.c333
3 files changed, 339 insertions, 16 deletions
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 <sys/shm.h>
#include <sys/ipc.h>
+#include <semaphore.h>
+#include <string.h>
#include <errno.h>
+#include <nuttx/pgalloc.h>
+#include <nuttx/shm.h>
+
+#include "shm/shm.h"
+
#ifdef CONFIG_MM_SHM
/****************************************************************************
@@ -62,6 +69,223 @@
****************************************************************************/
/****************************************************************************
+ * 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(&region->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;
}