diff options
author | Gedare Bloom <gedare@rtems.org> | 2016-08-12 15:25:10 -0400 |
---|---|---|
committer | Gedare Bloom <gedare@rtems.org> | 2017-01-13 11:17:30 -0500 |
commit | ba77628250ae7158db363fc0d7886ebd43e9cb69 (patch) | |
tree | 91a8a5b7d20399c69c5c88223a43ec681451996b /cpukit/posix/src/shmopen.c | |
parent | 2b442a8e17fa505a57775f1a18010a6dc70cbd12 (diff) |
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/shmopen.c')
-rw-r--r-- | cpukit/posix/src/shmopen.c | 283 |
1 files changed, 279 insertions, 4 deletions
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 +}; |