[rtems commit] posix/mman: add mmap support for shm objects

Gedare Bloom gedare at rtems.org
Fri May 5 15:26:46 UTC 2017


Module:    rtems
Branch:    master
Commit:    87de70a2984cece87db94f4b445589c4e24e5c77
Changeset: http://git.rtems.org/rtems/commit/?id=87de70a2984cece87db94f4b445589c4e24e5c77

Author:    Gedare Bloom <gedare at rtems.org>
Date:      Wed Mar 15 14:31:00 2017 -0400

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 a87031c..d0824b4 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 c2fb975..695a4c4 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 22be641..e89634f 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 9743685..bb33ac9 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 dfdd58e..9284b39 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 6d81e5e..f16af81 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 c05a65e..9f555ad 100644
--- a/cpukit/posix/src/mmap.c
+++ b/cpukit/posix/src/mmap.c
@@ -1,5 +1,10 @@
+/**
+ * @file
+ */
+
 /*
  * Copyright (c) 2012 Chris Johns (chrisj at rtems.org)
+ * Copyright (c) 2017 Gedare Bloom (gedare at 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 d3687df..323a24e 100644
--- a/cpukit/posix/src/munmap.c
+++ b/cpukit/posix/src/munmap.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012 Chris Johns (chrisj at rtems.org)
+ * Copyright (c) 2017 Gedare Bloom (gedare at 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 3449c15..47f5b47 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 bedde15..fa1027e 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 ab18450..f81e234 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 6d6cd21..bcef353 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 7b7be40..239ddd9 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 d02c87f..5ed0f0c 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
 



More information about the vc mailing list