Flesh out basic logic for shmget()

This commit is contained in:
Gregory Nutt 2014-09-23 10:42:18 -06:00
parent ba1f9c01d7
commit 5efd5738e9
4 changed files with 344 additions and 20 deletions

View file

@ -48,11 +48,12 @@
* Pre-Processor Definitions
****************************************************************************/
/* Mode bits: */
/* Mode bits: The lower order 9-bit bits are the standard mode bits */
#define IPC_CREAT 0x01 /* Create entry if key does not exist */
#define IPC_EXCL 0x02 /* Fail if key exists */
#define IPC_NOWAIT 0x04 /* Error if request must wait */
#define IPC_MODE 0x01ff /* Mode bit mask */
#define IPC_CREAT (1 << 10) /* Create entry if key does not exist */
#define IPC_EXCL (1 << 11) /* Fail if key exists */
#define IPC_NOWAIT (1 << 12) /* Error if request must wait */
/* Keys: */

View file

@ -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 */

View file

@ -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
}

View file

@ -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
/****************************************************************************
@ -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(&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;
}