Flesh out basic logic for shmget()
This commit is contained in:
parent
ba1f9c01d7
commit
5efd5738e9
4 changed files with 344 additions and 20 deletions
|
@ -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: */
|
||||
|
||||
|
|
12
mm/shm/shm.h
12
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 */
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
333
mm/shm/shmget.c
333
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
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue