diff options
Diffstat (limited to 'cpukit/posix/src')
-rw-r--r-- | cpukit/posix/src/shm.c | 48 | ||||
-rw-r--r-- | cpukit/posix/src/shmheap.c | 90 | ||||
-rw-r--r-- | cpukit/posix/src/shmopen.c | 283 | ||||
-rw-r--r-- | cpukit/posix/src/shmunlink.c | 30 | ||||
-rw-r--r-- | cpukit/posix/src/shmwkspace.c | 78 |
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; +} + + |