From 87de70a2984cece87db94f4b445589c4e24e5c77 Mon Sep 17 00:00:00 2001 From: Gedare Bloom Date: Wed, 15 Mar 2017 14:31:00 -0400 Subject: posix/mman: add mmap support for shm objects Update #2859. --- cpukit/libcsupport/include/rtems/libio.h | 1 + cpukit/libcsupport/include/rtems/libio_.h | 41 ++++++ cpukit/libcsupport/src/libio.c | 32 +++- cpukit/posix/include/rtems/posix/mmanimpl.h | 7 +- cpukit/posix/include/rtems/posix/shm.h | 30 ++++ cpukit/posix/include/rtems/posix/shmimpl.h | 30 ++++ cpukit/posix/src/mmap.c | 219 +++++++++++++++++++++------- cpukit/posix/src/munmap.c | 43 ++++-- cpukit/posix/src/shmheap.c | 20 +++ cpukit/posix/src/shmopen.c | 23 +-- cpukit/posix/src/shmunlink.c | 4 +- cpukit/posix/src/shmwkspace.c | 17 +++ cpukit/sapi/include/confdefs.h | 3 +- testsuites/psxtests/psxshm02/system.h | 3 +- 14 files changed, 378 insertions(+), 95 deletions(-) diff --git a/cpukit/libcsupport/include/rtems/libio.h b/cpukit/libcsupport/include/rtems/libio.h index a87031ca91..d0824b4e85 100644 --- a/cpukit/libcsupport/include/rtems/libio.h +++ b/cpukit/libcsupport/include/rtems/libio.h @@ -1282,6 +1282,7 @@ struct rtems_libio_tt { rtems_driver_name_t *driver; off_t offset; /* current offset into file */ uint32_t flags; + uint32_t mapping_refcnt; /* current mappings */ rtems_filesystem_location_info_t pathinfo; uint32_t data0; /* private to "driver" */ void *data1; /* ... */ diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index c2fb975bf7..695a4c45a5 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -304,6 +304,47 @@ void rtems_libio_free( rtems_libio_t *iop ); +/** + * Garbage collects the free libio in case it was previously freed but there + * were still references to it. + */ +void rtems_libio_check_deferred_free( rtems_libio_t *iop ); + +/** + * Increment the reference count tracking number of mmap mappings of a file. + * Returns the updated reference count value. + */ +static inline uint32_t rtems_libio_increment_mapping_refcnt(rtems_libio_t *iop) +{ + uint32_t refcnt; + rtems_libio_lock(); + refcnt = ++iop->mapping_refcnt; + rtems_libio_unlock(); + return refcnt; +} + +/** + * Decrement the reference count tracking number of mmap mappings of a file. + * Returns the updated reference count value. + */ +static inline uint32_t rtems_libio_decrement_mapping_refcnt(rtems_libio_t *iop) +{ + uint32_t refcnt; + rtems_libio_lock(); + refcnt = --iop->mapping_refcnt; + rtems_libio_unlock(); + return refcnt; +} + +static inline bool rtems_libio_is_mapped(rtems_libio_t *iop) +{ + bool is_mapped; + rtems_libio_lock(); + is_mapped = iop->mapping_refcnt != 0; + rtems_libio_unlock(); + return is_mapped; +} + /* * File System Routine Prototypes */ diff --git a/cpukit/libcsupport/src/libio.c b/cpukit/libcsupport/src/libio.c index 22be6411a2..e89634f090 100644 --- a/cpukit/libcsupport/src/libio.c +++ b/cpukit/libcsupport/src/libio.c @@ -138,8 +138,36 @@ void rtems_libio_free( rtems_libio_lock(); iop->flags = 0; - iop->data1 = rtems_libio_iop_freelist; - rtems_libio_iop_freelist = iop; + /* If the mapping_refcnt is non-zero, the deferred free will be + * called by munmap. The iop is no longer good to use, but it cannot + * be recycled until the mapped file is unmapped. deferred free knows + * it can recycle the iop in case flags == 0 and iop->data1 == iop, + * since these two conditions are not otherwise satisifed at + * the same time. It may be possible that iop->data1 == iop when + * flags != 0 because data1 is private to the driver. However, flags == 0 + * means a freed iop, and an iop on the freelist cannot store a pointer + * to itself in data1, or else the freelist is corrupted. We can't use + * NULL in data1 as an indicator because it is used by the tail of the + * freelist. */ + if ( iop->mapping_refcnt == 0 ) { + iop->data1 = rtems_libio_iop_freelist; + rtems_libio_iop_freelist = iop; + } else { + iop->data1 = iop; + } rtems_libio_unlock(); } + +void rtems_libio_check_deferred_free( + rtems_libio_t *iop +) +{ + rtems_libio_lock(); + if ( iop->mapping_refcnt == 0 && iop->flags == 0 && iop->data1 == iop) { + /* No mappings and rtems_libio_free already called, recycle the iop */ + iop->data1 = rtems_libio_iop_freelist; + rtems_libio_iop_freelist = iop; + } + rtems_libio_unlock(); +} diff --git a/cpukit/posix/include/rtems/posix/mmanimpl.h b/cpukit/posix/include/rtems/posix/mmanimpl.h index 9743685a57..bb33ac97ed 100644 --- a/cpukit/posix/include/rtems/posix/mmanimpl.h +++ b/cpukit/posix/include/rtems/posix/mmanimpl.h @@ -16,12 +16,15 @@ #ifndef _RTEMS_POSIX_MMANIMPL_H #define _RTEMS_POSIX_MMANIMPL_H -#include +#include +#include /* FIXME: use score chains for proper layering? */ #ifdef __cplusplus extern "C" { #endif +/* FIXME: add Doxygen */ + /** * Every mmap'ed region has a mapping. */ @@ -30,6 +33,8 @@ typedef struct mmap_mappings_s { void* addr; /**< The address of the mapped memory */ size_t len; /**< The length of memory mapped */ int flags; /**< The mapping flags */ + rtems_libio_t *iop; /**< The mapped object's file descriptor pointer */ + bool is_shared_shm; /**< True if MAP_SHARED of shared memory */ } mmap_mapping; extern rtems_chain_control mmap_mappings; diff --git a/cpukit/posix/include/rtems/posix/shm.h b/cpukit/posix/include/rtems/posix/shm.h index dfdd58ed2a..9284b398cf 100644 --- a/cpukit/posix/include/rtems/posix/shm.h +++ b/cpukit/posix/include/rtems/posix/shm.h @@ -91,6 +91,16 @@ struct POSIX_Shm_Object_operations { * Returns the number of bytes read (copied) into @a buf. */ int ( *object_read ) ( POSIX_Shm_Object *shm_obj, void *buf, size_t count ); + + /** + * @brief Maps a shared memory object. + * + * Establishes a memory mapping between the shared memory object and the + * caller. + * + * Returns the mapped address of the object. + */ + void * ( *object_mmap ) ( POSIX_Shm_Object *shm_obj, size_t len, int prot, off_t off); }; /** @@ -143,6 +153,16 @@ extern int _POSIX_Shm_Object_read_from_workspace( size_t count ); +/** + * @brief object_mmap operation for shm objects stored in RTEMS Workspace. + */ +extern void * _POSIX_Shm_Object_mmap_from_workspace( + POSIX_Shm_Object *shm_obj, + size_t len, + int prot, + off_t off +); + /** * @brief object_create operation for shm objects stored in C program heap. */ @@ -173,6 +193,16 @@ extern int _POSIX_Shm_Object_read_from_heap( size_t count ); +/** + * @brief object_mmap operation for shm objects stored in C program heap. + */ +extern void * _POSIX_Shm_Object_mmap_from_heap( + POSIX_Shm_Object *shm_obj, + size_t len, + int prot, + off_t off +); + /** @} */ #ifdef __cplusplus diff --git a/cpukit/posix/include/rtems/posix/shmimpl.h b/cpukit/posix/include/rtems/posix/shmimpl.h index 6d81e5eb27..f16af8123d 100644 --- a/cpukit/posix/include/rtems/posix/shmimpl.h +++ b/cpukit/posix/include/rtems/posix/shmimpl.h @@ -96,6 +96,36 @@ static inline POSIX_Shm_Control* loc_to_shm( return (POSIX_Shm_Control*) loc->node_access; } +static inline int POSIX_Shm_Attempt_delete( + POSIX_Shm_Control* shm +) +{ + Objects_Control *obj; + ISR_lock_Context lock_ctx; + int err; + + err = 0; + + _Objects_Allocator_lock(); + --shm->reference_count; + if ( shm->reference_count == 0 ) { + 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 ); + } + _Objects_Allocator_unlock(); + return err; +} + /** @} */ #ifdef __cplusplus diff --git a/cpukit/posix/src/mmap.c b/cpukit/posix/src/mmap.c index c05a65e078..9f555ade92 100644 --- a/cpukit/posix/src/mmap.c +++ b/cpukit/posix/src/mmap.c @@ -1,5 +1,10 @@ +/** + * @file + */ + /* * Copyright (c) 2012 Chris Johns (chrisj@rtems.org) + * Copyright (c) 2017 Gedare Bloom (gedare@rtems.org) * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -19,7 +24,8 @@ #include "rtems/libio_.h" -#include +#include +#include #define RTEMS_MUTEX_ATTRIBS \ (RTEMS_PRIORITY | RTEMS_SIMPLE_BINARY_SEMAPHORE | \ @@ -49,11 +55,14 @@ bool mmap_mappings_lock_create( * the libio lock is locked and we then test the mapping lock again. If not * present we create the mapping lock then release libio lock. */ + /* FIXME: double-checked locking anti-pattern. */ if ( mmap_mappings_lock == 0 ) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_chain_initialize_empty( &mmap_mappings ); rtems_semaphore_obtain( rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT ); + /* FIXME: account for semaphore in confdefs, or maybe just use the + * rtems_libio_semaphore? */ if ( mmap_mappings_lock == 0 ) sc = rtems_semaphore_create( rtems_build_name( 'M', 'M', 'A', 'P' ), 1, @@ -98,19 +107,45 @@ bool mmap_mappings_lock_release( return true; } +/* Helper function only gets called for mmap mappings of shared memory objects + * with the MAP_SHARED flag. + */ +static void *shm_mmap( rtems_libio_t *iop, size_t len, int prot, off_t off) +{ + POSIX_Shm_Control *shm = iop_to_shm( iop ); + void *m; + + _Objects_Allocator_lock(); + + m = (*shm->shm_object.ops->object_mmap)( &shm->shm_object, len, prot, off); + if ( m != NULL ) { + /* Keep a reference in the shared memory to prevent its removal. */ + ++shm->reference_count; + + /* Update atime */ + _POSIX_Shm_Update_atime(shm); + } + + _Objects_Allocator_unlock(); + + return m; +} + void *mmap( void *addr, size_t len, int prot, int flags, int fildes, off_t off ) { - struct stat sb; - mmap_mapping* mapping; - ssize_t r; - - /* - * Clear errno. - */ + struct stat sb; + mmap_mapping *mapping; + ssize_t r; + rtems_libio_t *iop; + bool map_fixed; + + map_fixed = (flags & MAP_FIXED) == MAP_FIXED; + + /* Clear errno. */ errno = 0; - + /* * Get a stat of the file to get the dev + inode number and to make sure the * fd is ok. The normal libio calls cannot be used because we need to return @@ -122,109 +157,185 @@ void *mmap( return MAP_FAILED; } + /* fstat ensures we have a good file descriptor. Hold on to iop. */ + iop = rtems_libio_iop( fildes ); + if ( len == 0 ) { errno = EINVAL; return MAP_FAILED; } - /* - * Check the type of file we have and make sure it is supported. - */ + /* Check the type of file we have and make sure it is supported. */ if ( S_ISDIR( sb.st_mode ) || S_ISLNK( sb.st_mode )) { errno = ENODEV; return MAP_FAILED; } - + /* * We can provide read, write and execute because the memory in RTEMS does * not normally have protections but we cannot hide access to memory. */ if ( prot == PROT_NONE ) { + errno = ENOTSUP; + return MAP_FAILED; + } + + /* Either MAP_SHARED or MAP_PRIVATE must be defined, but not both */ + if ( (flags & MAP_SHARED) == MAP_SHARED ) { + if ( (flags & MAP_PRIVATE) == MAP_PRIVATE ) { + errno = EINVAL; + return MAP_FAILED; + } + } else if ( (flags & MAP_PRIVATE != MAP_PRIVATE) ) { errno = EINVAL; return MAP_FAILED; } - + /* - * Check to see if the mapping is valid for the file. + * We can not normally provide restriction of write access. Reject any + * attempt to map without write permission, since we are not able to + * prevent a write from succeeding. */ + if ( PROT_WRITE != (prot & PROT_WRITE) ) { + errno = ENOTSUP; + return MAP_FAILED; + } + + /* Check to see if the mapping is valid for a regular file. */ if ( S_ISREG( sb.st_mode ) + /* FIXME: Should this be using strict inequality (>) comparisons? It would + * be valid to map a region exactly equal to the st_size, e.g. see below. */ && (( off >= sb.st_size ) || (( off + len ) >= sb.st_size ))) { errno = EOVERFLOW; return MAP_FAILED; } /* - * Obtain the mmap lock. Sets errno on failure. + * Check to see if the mapping is valid for other file/object types. + * Does this satisfy for devices? */ - if ( !mmap_mappings_lock_obtain( ) ) + if ( sb.st_size < off + len ) { + errno = ENXIO; return MAP_FAILED; + } - if (( flags & MAP_FIXED ) == MAP_FIXED ) { - rtems_chain_node* node = rtems_chain_first (&mmap_mappings); - while ( !rtems_chain_is_tail( &mmap_mappings, node )) { - /* - * If the map is fixed see if this address is already mapped. At this - * point in time if there is an overlap in the mappings we return an - * error. - */ - mapping = (mmap_mapping*) node; - if ( ( addr >= mapping->addr ) && - ( addr < ( mapping->addr + mapping->len )) ) { - mmap_mappings_lock_release( ); - errno = ENXIO; - return MAP_FAILED; - } - node = rtems_chain_next( node ); + /* Do not seek on character devices, pipes, sockets, or memory objects. */ + if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) { + if ( lseek( fildes, off, SEEK_SET ) < 0 ) { + return MAP_FAILED; } } + /* Create the mapping */ mapping = malloc( sizeof( mmap_mapping )); if ( !mapping ) { - mmap_mappings_lock_release( ); errno = ENOMEM; return NULL; } - memset( mapping, 0, sizeof( mmap_mapping )); - mapping->len = len; mapping->flags = flags; - - if (( flags & MAP_FIXED ) != MAP_FIXED ) { + mapping->iop = iop; + + /* + * HACK: We should have a better generic way to distinguish between + * shm objects and other mmap'd files. We need to know at munmap time + * if the mapping is to a shared memory object in order to refcnt shms. + * We could do this by providing mmap in the file operations if needed. + */ + if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) || + S_ISCHR( sb.st_mode ) || S_ISFIFO( sb.st_mode ) || + S_ISSOCK( sb.st_mode ) ) { + mapping->is_shared_shm = false; + } else { + mapping->is_shared_shm = true; + } + + /* + * MAP_SHARED currently is only supported for shared memory objects. + */ + if ( (MAP_SHARED == (flags & MAP_SHARED)) && (mapping->is_shared_shm == false) ) { + free( mapping ); + errno = ENOTSUP; + return MAP_FAILED; + } + + if ( map_fixed ) { + mapping->addr = addr; + } else if ( MAP_PRIVATE == (flags & MAP_PRIVATE) ) { + /* private mappings of shared memory do not need special treatment. */ + mapping->is_shared_shm = false; mapping->addr = malloc( len ); if ( !mapping->addr ) { - mmap_mappings_lock_release( ); free( mapping ); errno = ENOMEM; return MAP_FAILED; } + } - /* - * Do not seek on character devices, pipes or sockets. - */ - if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) { - if ( lseek( fildes, off, SEEK_SET ) < 0 ) { - mmap_mappings_lock_release( ); - free( mapping->addr ); + /* MAP_FIXED is not supported for shared memory objects with MAP_SHARED. */ + if ( map_fixed && mapping->is_shared_shm ) { + free( mapping ); + errno = ENOTSUP; + return MAP_FAILED; + } + + /* Lock access to mmap_mappings. Sets errno on failure. */ + if ( !mmap_mappings_lock_obtain( ) ) + return MAP_FAILED; + + if ( map_fixed ) { + rtems_chain_node* node = rtems_chain_first (&mmap_mappings); + while ( !rtems_chain_is_tail( &mmap_mappings, node )) { + /* + * If the map is fixed see if this address is already mapped. At this + * point in time if there is an overlap in the mappings we return an + * error. POSIX allows us to also return successfully by unmapping + * the overlapping prior mappings. + */ + mapping = (mmap_mapping*) node; + if ( ( addr >= mapping->addr ) && + ( addr < ( mapping->addr + mapping->len )) ) { free( mapping ); + mmap_mappings_lock_release( ); + errno = ENXIO; return MAP_FAILED; } + node = rtems_chain_next( node ); } } - r = read( fildes, mapping->addr, len ); + /* Populate the data */ + if ( MAP_PRIVATE == (flags & MAP_PRIVATE) ) { + /* + * Use read() for private mappings. This updates atime as needed. + * Changes to the underlying object will NOT be reflected in the mapping. + * The underlying object can be removed while the mapping exists. + */ + r = read( fildes, mapping->addr, len ); - if ( r != len ) { - mmap_mappings_lock_release( ); - free( mapping->addr ); - free( mapping ); - errno = ENXIO; - return MAP_FAILED; + if ( r != len ) { + mmap_mappings_lock_release( ); + if ( !map_fixed ) { + free( mapping->addr ); + } + free( mapping ); + errno = ENXIO; + return MAP_FAILED; + } + } else if ( MAP_SHARED == (flags & MAP_SHARED) ) { + /* Currently only shm objects can be MAP_SHARED. */ + mapping->addr = shm_mmap(iop, len, prot, off); } + /* add an extra reference to the file associated with fildes that + * is not removed by a subsequent close(). This reference shall be removed + * when there are no more mappings to the file. */ + rtems_libio_increment_mapping_refcnt(iop); + rtems_chain_append( &mmap_mappings, &mapping->node ); mmap_mappings_lock_release( ); - + return mapping->addr; } diff --git a/cpukit/posix/src/munmap.c b/cpukit/posix/src/munmap.c index d3687dfef4..323a24e6f4 100644 --- a/cpukit/posix/src/munmap.c +++ b/cpukit/posix/src/munmap.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 Chris Johns (chrisj@rtems.org) + * Copyright (c) 2017 Gedare Bloom (gedare@rtems.org) * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -16,13 +17,21 @@ #include #include +#include -int munmap( - void *addr, size_t len -) +static void shm_munmap( rtems_libio_t *iop ) { - mmap_mapping* mapping; - rtems_chain_node* node; + POSIX_Shm_Control *shm = iop_to_shm( iop ); + + /* decrement mmap's shm reference_count and maybe delete the object */ + POSIX_Shm_Attempt_delete(shm); +} + +int munmap(void *addr, size_t len) +{ + mmap_mapping *mapping; + rtems_chain_node *node; + uint32_t refcnt; /* * Clear errno. @@ -45,19 +54,29 @@ int munmap( node = rtems_chain_first (&mmap_mappings); while ( !rtems_chain_is_tail( &mmap_mappings, node )) { - /* - * If the map is fixed see if this address is already mapped. At this - * point in time if there is an overlap in the mappings we return an - * error. - */ mapping = (mmap_mapping*) node; if ( ( addr >= mapping->addr ) && ( addr < ( mapping->addr + mapping->len )) ) { rtems_chain_extract( node ); + /* FIXME: generally need a way to clean-up the backing object, but + * currently it only matters for MAP_SHARED shm objects. */ + if ( mapping->is_shared_shm == true ) { + shm_munmap(mapping->iop); + } + refcnt = rtems_libio_decrement_mapping_refcnt(mapping->iop); + if ( refcnt == 0 ) { + rtems_libio_check_deferred_free(mapping->iop); + } + /* only free the mapping address for non-fixed mapping */ if (( mapping->flags & MAP_FIXED ) != MAP_FIXED ) { - free( mapping->addr ); - free( mapping ); + /* only free the mapping address for non-shared mapping, because we + * re-use the mapping address across all of the shared mappings, and + * it is memory managed independently... */ + if (( mapping->flags & MAP_SHARED ) != MAP_SHARED ) { + free( mapping->addr ); + } } + free( mapping ); break; } node = rtems_chain_next( node ); diff --git a/cpukit/posix/src/shmheap.c b/cpukit/posix/src/shmheap.c index 3449c15cca..47f5b4783a 100644 --- a/cpukit/posix/src/shmheap.c +++ b/cpukit/posix/src/shmheap.c @@ -70,6 +70,7 @@ int _POSIX_Shm_Object_resize_from_heap( return err; } +/* This is identical to _POSIX_Shm_Object_read_from_wkspace */ int _POSIX_Shm_Object_read_from_heap( POSIX_Shm_Object *shm_obj, void *buf, @@ -88,3 +89,22 @@ int _POSIX_Shm_Object_read_from_heap( return count; } +/* This is identical to _POSIX_Shm_Object_mmap_from_wkspace */ +void * _POSIX_Shm_Object_mmap_from_heap( + POSIX_Shm_Object *shm_obj, + size_t len, + int prot, + off_t off +) +{ + if ( shm_obj == NULL || shm_obj->handle == NULL ) + return 0; + + /* This is already checked by mmap. Maybe make it a debug assert? */ + if ( shm_obj->size < len + off ) { + return NULL; + } + + return &(shm_obj->handle[off]); +} + diff --git a/cpukit/posix/src/shmopen.c b/cpukit/posix/src/shmopen.c index bedde1513f..fa1027e30c 100644 --- a/cpukit/posix/src/shmopen.c +++ b/cpukit/posix/src/shmopen.c @@ -93,34 +93,13 @@ static int shm_ftruncate( rtems_libio_t *iop, off_t length ) 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; err = 0; - _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 ); - } - } + POSIX_Shm_Attempt_delete(shm); iop->pathinfo.node_access = NULL; - _Objects_Allocator_unlock(); - if ( err != 0 ) { rtems_set_errno_and_return_minus_one( err ); } diff --git a/cpukit/posix/src/shmunlink.c b/cpukit/posix/src/shmunlink.c index ab18450dc7..f81e234413 100644 --- a/cpukit/posix/src/shmunlink.c +++ b/cpukit/posix/src/shmunlink.c @@ -40,8 +40,8 @@ int shm_unlink( const char *name ) 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. */ + /* Only remove the shm object if no references exist to it. Otherwise, + * the shm object will be freed later in _POSIX_Shm_Attempt_delete */ _POSIX_Shm_Free( shm ); } break; diff --git a/cpukit/posix/src/shmwkspace.c b/cpukit/posix/src/shmwkspace.c index 6d6cd211a5..bcef3531ef 100644 --- a/cpukit/posix/src/shmwkspace.c +++ b/cpukit/posix/src/shmwkspace.c @@ -75,4 +75,21 @@ int _POSIX_Shm_Object_read_from_workspace( return count; } +void * _POSIX_Shm_Object_mmap_from_workspace( + POSIX_Shm_Object *shm_obj, + size_t len, + int prot, + off_t off +) +{ + if ( shm_obj == NULL || shm_obj->handle == NULL ) + return 0; + + /* This is already checked by mmap. Maybe make it a debug assert? */ + if ( shm_obj->size < len + off ) { + return NULL; + } + + return &(shm_obj->handle[off]); +} diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h index 7b7be40985..239ddd939a 100755 --- a/cpukit/sapi/include/confdefs.h +++ b/cpukit/sapi/include/confdefs.h @@ -2586,7 +2586,8 @@ extern rtems_initialization_tasks_table Initialization_tasks[]; _POSIX_Shm_Object_create_from_workspace, _POSIX_Shm_Object_resize_from_workspace, _POSIX_Shm_Object_delete_from_workspace, - _POSIX_Shm_Object_read_from_workspace + _POSIX_Shm_Object_read_from_workspace, + _POSIX_Shm_Object_mmap_from_workspace }; #endif #endif diff --git a/testsuites/psxtests/psxshm02/system.h b/testsuites/psxtests/psxshm02/system.h index d02c87f62c..5ed0f0caf2 100644 --- a/testsuites/psxtests/psxshm02/system.h +++ b/testsuites/psxtests/psxshm02/system.h @@ -31,7 +31,8 @@ const POSIX_Shm_Object_operations _POSIX_Shm_Object_operations = { _POSIX_Shm_Object_create_from_heap, _POSIX_Shm_Object_resize_from_heap, _POSIX_Shm_Object_delete_from_heap, - _POSIX_Shm_Object_read_from_heap + _POSIX_Shm_Object_read_from_heap, + _POSIX_Shm_Object_mmap_from_heap }; #define CONFIGURE_HAS_OWN_POSIX_SHM_OBJECT_OPERATIONS -- cgit v1.2.3