summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGedare Bloom <gedare@rtems.org>2017-03-15 14:31:00 -0400
committerGedare Bloom <gedare@rtems.org>2017-05-05 10:34:08 -0400
commit87de70a2984cece87db94f4b445589c4e24e5c77 (patch)
tree945d211b09e3b7714a2bba6d06ceae7a601d4116
parentposix: Add mmap/unmap support for mapping files. (diff)
downloadrtems-87de70a2984cece87db94f4b445589c4e24e5c77.tar.bz2
posix/mman: add mmap support for shm objects
Update #2859.
-rw-r--r--cpukit/libcsupport/include/rtems/libio.h1
-rw-r--r--cpukit/libcsupport/include/rtems/libio_.h41
-rw-r--r--cpukit/libcsupport/src/libio.c32
-rw-r--r--cpukit/posix/include/rtems/posix/mmanimpl.h7
-rw-r--r--cpukit/posix/include/rtems/posix/shm.h30
-rw-r--r--cpukit/posix/include/rtems/posix/shmimpl.h30
-rw-r--r--cpukit/posix/src/mmap.c219
-rw-r--r--cpukit/posix/src/munmap.c43
-rw-r--r--cpukit/posix/src/shmheap.c20
-rw-r--r--cpukit/posix/src/shmopen.c23
-rw-r--r--cpukit/posix/src/shmunlink.c4
-rw-r--r--cpukit/posix/src/shmwkspace.c17
-rwxr-xr-xcpukit/sapi/include/confdefs.h3
-rw-r--r--testsuites/psxtests/psxshm02/system.h3
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 <rtems/chain.h>
+#include <rtems/libio_.h>
+#include <rtems/chain.h> /* 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);
};
/**
@@ -144,6 +154,16 @@ extern int _POSIX_Shm_Object_read_from_workspace(
);
/**
+ * @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.
*/
extern int _POSIX_Shm_Object_create_from_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 <rtems/posix/mmanimpl.h>
+#include <rtems/posix/mmanimpl.h>
+#include <rtems/posix/shmimpl.h>
#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 <sys/mman.h>
#include <rtems/posix/mmanimpl.h>
+#include <rtems/posix/shmimpl.h>
-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