summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src
diff options
context:
space:
mode:
authorGedare Bloom <gedare@rtems.org>2016-08-12 15:25:10 -0400
committerGedare Bloom <gedare@rtems.org>2017-01-13 11:17:30 -0500
commitba77628250ae7158db363fc0d7886ebd43e9cb69 (patch)
tree91a8a5b7d20399c69c5c88223a43ec681451996b /cpukit/posix/src
parentposix: fix typo in mmap arguments (diff)
downloadrtems-ba77628250ae7158db363fc0d7886ebd43e9cb69.tar.bz2
posix: shared memory support
Add POSIX shared memory manager (Shm). Includes a hook-based approach for the backing memory storage that defaults to the Workspace, and a test is provided using the heap. A test is also provided for the basic use of mmap'ing a shared memory object. This test currently fails at the mmap stage due to no support for mmap.
Diffstat (limited to 'cpukit/posix/src')
-rw-r--r--cpukit/posix/src/shm.c48
-rw-r--r--cpukit/posix/src/shmheap.c90
-rw-r--r--cpukit/posix/src/shmopen.c283
-rw-r--r--cpukit/posix/src/shmunlink.c30
-rw-r--r--cpukit/posix/src/shmwkspace.c78
5 files changed, 523 insertions, 6 deletions
diff --git a/cpukit/posix/src/shm.c b/cpukit/posix/src/shm.c
new file mode 100644
index 0000000000..7dca6bbc1d
--- /dev/null
+++ b/cpukit/posix/src/shm.c
@@ -0,0 +1,48 @@
+/**
+ * @file
+ */
+
+/*
+ * Copyright (c) 2016 Gedare Bloom.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <rtems/system.h>
+#include <rtems/config.h>
+#include <rtems/libio.h>
+#include <rtems/sysinit.h>
+#include <rtems/posix/shmimpl.h>
+
+Objects_Information _POSIX_Shm_Information;
+
+static void _POSIX_Shm_Manager_initialization( void )
+{
+ _Objects_Initialize_information(
+ &_POSIX_Shm_Information, /* object information table */
+ OBJECTS_POSIX_API, /* object API */
+ OBJECTS_POSIX_SHMS, /* object class */
+ Configuration_POSIX_API.maximum_shms,
+ /* maximum objects of this class */
+ sizeof( POSIX_Shm_Control ),
+ /* size of this object's control block */
+ true, /* true if names for this object are strings */
+ _POSIX_PATH_MAX, /* maximum length of each object's name */
+ NULL /* Proxy extraction support callout */
+ );
+}
+
+RTEMS_SYSINIT_ITEM(
+ _POSIX_Shm_Manager_initialization,
+ RTEMS_SYSINIT_POSIX_SHM,
+ RTEMS_SYSINIT_ORDER_MIDDLE
+);
diff --git a/cpukit/posix/src/shmheap.c b/cpukit/posix/src/shmheap.c
new file mode 100644
index 0000000000..3449c15cca
--- /dev/null
+++ b/cpukit/posix/src/shmheap.c
@@ -0,0 +1,90 @@
+/**
+ * @file
+ */
+
+/*
+ * Copyright (c) 2016 Gedare Bloom.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems/posix/shmimpl.h>
+
+int _POSIX_Shm_Object_create_from_heap(
+ POSIX_Shm_Object *shm_obj,
+ size_t size
+)
+{
+ void *p = calloc( 1, size ); /* get zero'd memory */
+ if ( p != NULL ) {
+ shm_obj->handle = p;
+ shm_obj->size = size;
+ } else {
+ errno = EIO;
+ }
+ return 0;
+}
+
+int _POSIX_Shm_Object_delete_from_heap( POSIX_Shm_Object *shm_obj )
+{
+ /* zero out memory before releasing it. */
+ memset( shm_obj->handle, 0, shm_obj->size );
+ free( shm_obj->handle );
+ shm_obj->handle = NULL;
+ shm_obj->size = 0;
+ return 0;
+}
+
+int _POSIX_Shm_Object_resize_from_heap(
+ POSIX_Shm_Object *shm_obj,
+ size_t size
+)
+{
+ void *p;
+ int err = 0;
+
+ if ( size < shm_obj->size ) {
+ /* zero out if shrinking */
+ p = (void*)((uintptr_t)shm_obj->handle + (uintptr_t)size);
+ memset( p, 0, shm_obj->size - size );
+ }
+ p = realloc( shm_obj->handle, size );
+ if ( p != NULL ) {
+ shm_obj->handle = p;
+ if ( size > shm_obj->size ) {
+ /* initialize added memory */
+ memset( p, 0, size - shm_obj->size );
+ }
+ shm_obj->size = size;
+ } else {
+ err = EIO;
+ }
+ return err;
+}
+
+int _POSIX_Shm_Object_read_from_heap(
+ POSIX_Shm_Object *shm_obj,
+ void *buf,
+ size_t count
+)
+{
+ if ( shm_obj == NULL || shm_obj->handle == NULL )
+ return 0;
+
+ if ( shm_obj->size < count ) {
+ count = shm_obj->size;
+ }
+
+ memcpy( buf, shm_obj->handle, count );
+
+ return count;
+}
+
diff --git a/cpukit/posix/src/shmopen.c b/cpukit/posix/src/shmopen.c
index abac3f4057..fec443abba 100644
--- a/cpukit/posix/src/shmopen.c
+++ b/cpukit/posix/src/shmopen.c
@@ -16,13 +16,288 @@
#include <sys/mman.h>
#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <rtems/libio_.h>
#include <rtems/seterr.h>
+#include <rtems/posix/shmimpl.h>
+#include <rtems/score/wkspace.h>
+
+static const rtems_filesystem_file_handlers_r shm_handlers;
+
+static int shm_fstat(
+ const rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+)
+{
+ POSIX_Shm_Control *shm = loc_to_shm( loc );
+
+ if ( shm == NULL )
+ rtems_set_errno_and_return_minus_one( EIO );
+
+ /* mandatory for shm objects */
+ buf->st_uid = shm->uid;
+ buf->st_gid = shm->gid;
+ buf->st_size = shm->shm_object.size;
+ buf->st_mode = shm->mode;
+
+ /* optional for shm objects */
+ buf->st_atime = shm->atime;
+ buf->st_mtime = shm->mtime;
+ buf->st_ctime = shm->ctime;
+
+ return 0;
+}
+
+/* read() is unspecified for shared memory objects */
+static ssize_t shm_read( rtems_libio_t *iop, void *buffer, size_t count )
+{
+ Thread_queue_Context queue_context;
+ ssize_t bytes_read;
+ POSIX_Shm_Control *shm = iop_to_shm( iop );
+
+ _Thread_queue_Context_initialize( &queue_context );
+ _POSIX_Shm_Acquire( shm, &queue_context );
+ bytes_read = (*shm->shm_object.ops->object_read)(
+ &shm->shm_object,
+ buffer,
+ count
+ );
+ _POSIX_Shm_Release( shm, &queue_context );
+
+ return bytes_read;
+}
+
+static int shm_ftruncate( rtems_libio_t *iop, off_t length )
+{
+ Thread_queue_Context queue_context;
+ int err;
+ POSIX_Shm_Control *shm = iop_to_shm( iop );
+
+ _Thread_queue_Context_initialize( &queue_context );
+ _POSIX_Shm_Acquire( shm, &queue_context );
+
+ err = (*shm->shm_object.ops->object_resize)( &shm->shm_object, length );
+
+ if ( err != 0 ) {
+ _POSIX_Shm_Release( shm, &queue_context );
+ rtems_set_errno_and_return_minus_one( err );
+ }
+
+ _POSIX_Shm_Update_mtime_ctime( shm );
+
+ _POSIX_Shm_Release( shm, &queue_context );
+ return 0;
+}
+
+static int shm_close( rtems_libio_t *iop )
+{
+ POSIX_Shm_Control *shm = iop_to_shm( iop );
+ Objects_Control *obj;
+ ISR_lock_Context lock_ctx;
+ int err;
+
+ _Objects_Allocator_lock();
+
+ --shm->reference_count;
+ if ( shm->reference_count == 0 ) {
+ /* TODO: need to make sure this counts mmaps too! */
+ if ( (*shm->shm_object.ops->object_delete)( &shm->shm_object ) != 0 ) {
+ err = EIO;
+ }
+ /* check if the object has been unlinked yet. */
+ obj = _Objects_Get( shm->Object.id, &lock_ctx, &_POSIX_Shm_Information );
+ if ( obj == NULL ) {
+ /* if it was unlinked, then it can be freed. */
+ _POSIX_Shm_Free( shm );
+ } else {
+ /* it will be freed when it is unlinked. */
+ _ISR_lock_ISR_enable( &lock_ctx );
+ }
+ }
+ iop->pathinfo.node_access = NULL;
+
+ _Objects_Allocator_unlock();
+
+ if ( err != 0 ) {
+ rtems_set_errno_and_return_minus_one( err );
+ }
+ return 0;
+}
+
+static inline POSIX_Shm_Control *shm_allocate(
+ const char *name_arg,
+ size_t name_len,
+ int oflag,
+ mode_t mode,
+ int *error
+)
+{
+ POSIX_Shm_Control *shm;
+ char *name;
+ struct timeval tv;
+
+ /* Reject any name without a leading slash. */
+ if ( name_arg[0] != '/' ) {
+ *error = EINVAL;
+ return NULL;
+ }
+
+ /* Only create the object if requested. */
+ if ( ( oflag & O_CREAT ) != O_CREAT ) {
+ *error = ENOENT;
+ return NULL;
+ }
+
+ name = _Workspace_String_duplicate( name_arg, name_len );
+ if ( name == NULL ) {
+ *error = ENOSPC;
+ return NULL;
+ }
+
+ shm = _POSIX_Shm_Allocate_unprotected();
+ if ( shm == NULL ) {
+ _Workspace_Free( name );
+ *error = ENFILE;
+ return NULL;
+ }
+
+ gettimeofday( &tv, 0 );
+
+ shm->reference_count = 1;
+ shm->shm_object.handle = NULL;
+ shm->shm_object.size = 0;
+ shm->shm_object.ops = &_POSIX_Shm_Object_operations;
+ shm->mode = mode & ~rtems_filesystem_umask;
+ shm->uid = geteuid();
+ shm->gid = getegid();
+ shm->atime = (time_t) tv.tv_sec;
+ shm->mtime = (time_t) tv.tv_sec;
+ shm->ctime = (time_t) tv.tv_sec;
+
+ _Objects_Open_string( &_POSIX_Shm_Information, &shm->Object, name );
+
+ return shm;
+}
+
+static inline bool shm_access_ok( POSIX_Shm_Control *shm, int oflag )
+{
+ int flags;
+ if ( oflag & O_RDONLY ) {
+ flags = RTEMS_FS_PERMS_READ;
+ } else {
+ flags = RTEMS_FS_PERMS_WRITE;
+ }
+ return rtems_filesystem_check_access( flags, shm->mode, shm->uid, shm->gid );
+}
+
+static inline int shm_check_oflag( int oflag )
+{
+ if ( ( oflag & O_ACCMODE ) != O_RDONLY && ( oflag & O_ACCMODE ) != O_RDWR ) {
+ rtems_set_errno_and_return_minus_one( EACCES );
+ }
+
+ if ( ( oflag & ~( O_RDONLY | O_RDWR | O_CREAT | O_EXCL | O_TRUNC ) ) != 0 ) {
+ rtems_set_errno_and_return_minus_one( EACCES );
+ }
+
+ if ( ( oflag & O_TRUNC ) != 0 && ( oflag & O_ACCMODE ) != O_RDWR ) {
+ rtems_set_errno_and_return_minus_one( EACCES );
+ }
+ return 0;
+}
+
int shm_open( const char *name, int oflag, mode_t mode )
{
- (void) name;
- (void) oflag;
- (void) mode;
+ int err = 0;
+ int fd;
+ rtems_libio_t *iop;
+ POSIX_Shm_Control *shm;
+ size_t len;
+ Objects_Get_by_name_error obj_err;
+
+ if ( shm_check_oflag( oflag ) != 0 ) {
+ return -1;
+ }
+
+ iop = rtems_libio_allocate();
+ if ( iop == NULL ) {
+ rtems_set_errno_and_return_minus_one( EMFILE );
+ }
- rtems_set_errno_and_return_minus_one( EINVAL );
+ _Objects_Allocator_lock();
+ shm = _POSIX_Shm_Get_by_name( name, &len, &obj_err );
+
+ if ( shm == NULL ) {
+ switch ( obj_err ) {
+ case OBJECTS_GET_BY_NAME_INVALID_NAME:
+ err = EINVAL;
+ break;
+
+ case OBJECTS_GET_BY_NAME_NAME_TOO_LONG:
+ err = ENAMETOOLONG;
+ break;
+
+ case OBJECTS_GET_BY_NAME_NO_OBJECT:
+ default:
+ shm = shm_allocate(name, len, oflag, mode, &err);
+ break;
+ }
+ } else { /* shm exists */
+ if ( ( oflag & ( O_EXCL | O_CREAT ) ) == ( O_EXCL | O_CREAT ) ) {
+ /* Request to create failed. */
+ err = EEXIST;
+ } else if ( !shm_access_ok( shm, oflag ) ) {
+ err = EACCES;
+ } else {
+ ++shm->reference_count;
+ }
+ }
+ _Objects_Allocator_unlock();
+ if ( err != 0 ) {
+ rtems_libio_free( iop );
+ rtems_set_errno_and_return_minus_one( err );
+ }
+
+ if ( oflag & O_TRUNC ) {
+ err = shm_ftruncate( iop, 0 );
+ (void) err; /* ignore truncate error */
+ }
+
+ fd = rtems_libio_iop_to_descriptor( iop );
+ iop->flags |= LIBIO_FLAGS_CLOSE_ON_EXEC;
+ if ( oflag & O_RDONLY ) {
+ iop->flags |= LIBIO_FLAGS_READ;
+ } else {
+ iop->flags |= LIBIO_FLAGS_READ_WRITE;
+ }
+ iop->data0 = fd;
+ iop->data1 = shm;
+ iop->pathinfo.node_access = shm;
+ iop->pathinfo.handlers = &shm_handlers;
+ iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
+ rtems_filesystem_location_add_to_mt_entry( &iop->pathinfo );
+
+ return fd;
}
+
+static const rtems_filesystem_file_handlers_r shm_handlers = {
+ .open_h = rtems_filesystem_default_open,
+ .close_h = shm_close,
+ .read_h = shm_read,
+ .write_h = rtems_filesystem_default_write,
+ .ioctl_h = rtems_filesystem_default_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek,
+ .fstat_h = shm_fstat,
+ .ftruncate_h = shm_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};
diff --git a/cpukit/posix/src/shmunlink.c b/cpukit/posix/src/shmunlink.c
index f5599227b1..ab18450dc7 100644
--- a/cpukit/posix/src/shmunlink.c
+++ b/cpukit/posix/src/shmunlink.c
@@ -18,9 +18,35 @@
#include <errno.h>
#include <rtems/seterr.h>
+#include <rtems/posix/shmimpl.h>
+
int shm_unlink( const char *name )
{
- (void) name;
+ Objects_Get_by_name_error obj_err;
+ int err = 0;
+ POSIX_Shm_Control *shm;
+
+ shm = _POSIX_Shm_Get_by_name( name, 0, &obj_err );
+ switch ( obj_err ) {
+ case OBJECTS_GET_BY_NAME_INVALID_NAME:
+ err = ENOENT;
+ break;
+
+ case OBJECTS_GET_BY_NAME_NAME_TOO_LONG:
+ err = ENAMETOOLONG;
+ break;
- rtems_set_errno_and_return_minus_one( ENOENT );
+ case OBJECTS_GET_BY_NAME_NO_OBJECT:
+ default:
+ _Objects_Close( &_POSIX_Shm_Information, &shm->Object );
+ if ( shm->reference_count == 0 ) {
+ /* TODO: need to make sure this counts mmaps too! */
+ /* only remove the shm object if no references exist to it. */
+ _POSIX_Shm_Free( shm );
+ }
+ break;
+ }
+ if ( err != 0 )
+ rtems_set_errno_and_return_minus_one( err );
+ return 0;
}
diff --git a/cpukit/posix/src/shmwkspace.c b/cpukit/posix/src/shmwkspace.c
new file mode 100644
index 0000000000..6d6cd211a5
--- /dev/null
+++ b/cpukit/posix/src/shmwkspace.c
@@ -0,0 +1,78 @@
+/**
+ * @file
+ */
+
+/*
+ * Copyright (c) 2016 Gedare Bloom.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <rtems/score/wkspace.h>
+#include <rtems/posix/shmimpl.h>
+
+int _POSIX_Shm_Object_create_from_workspace(
+ POSIX_Shm_Object *shm_obj,
+ size_t size
+)
+{
+ shm_obj->handle = _Workspace_Allocate_or_fatal_error( size );
+ memset( shm_obj->handle, 0, size );
+ shm_obj->size = size;
+ return 0;
+}
+
+int _POSIX_Shm_Object_delete_from_workspace( POSIX_Shm_Object *shm_obj )
+{
+ /* zero out memory before releasing it. */
+ memset( shm_obj->handle, 0, shm_obj->size );
+ _Workspace_Free( shm_obj->handle );
+ shm_obj->handle = NULL;
+ shm_obj->size = 0;
+ return 0;
+}
+
+int _POSIX_Shm_Object_resize_from_workspace(
+ POSIX_Shm_Object *shm_obj,
+ size_t size
+)
+{
+ int err;
+
+ if ( size == 0 ) {
+ err = _POSIX_Shm_Object_delete_from_workspace( shm_obj );
+ } else if ( shm_obj->handle == NULL && shm_obj->size == 0 ) {
+ err = _POSIX_Shm_Object_create_from_workspace( shm_obj, size );
+ } else {
+ /* Refuse to resize a workspace object. */
+ err = EIO;
+ }
+ return err;
+}
+
+int _POSIX_Shm_Object_read_from_workspace(
+ POSIX_Shm_Object *shm_obj,
+ void *buf,
+ size_t count
+)
+{
+ if ( shm_obj == NULL || shm_obj->handle == NULL )
+ return 0;
+
+ if ( shm_obj->size < count ) {
+ count = shm_obj->size;
+ }
+
+ memcpy( buf, shm_obj->handle, count );
+
+ return count;
+}
+
+