Changeset 87de70a2 in rtems for cpukit/posix


Ignore:
Timestamp:
Mar 15, 2017, 6:31:00 PM (3 years ago)
Author:
Gedare Bloom <gedare@…>
Branches:
master
Children:
6130a47
Parents:
8290f95
git-author:
Gedare Bloom <gedare@…> (03/15/17 18:31:00)
git-committer:
Gedare Bloom <gedare@…> (05/05/17 14:34:08)
Message:

posix/mman: add mmap support for shm objects

Update #2859.

Location:
cpukit/posix
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • cpukit/posix/include/rtems/posix/mmanimpl.h

    r8290f95 r87de70a2  
    1717#define _RTEMS_POSIX_MMANIMPL_H
    1818
    19 #include <rtems/chain.h>
     19#include <rtems/libio_.h>
     20#include <rtems/chain.h> /* FIXME: use score chains for proper layering? */
    2021
    2122#ifdef __cplusplus
    2223extern "C" {
    2324#endif
     25
     26/* FIXME: add Doxygen */
    2427
    2528/**
     
    3134  size_t           len;   /**< The length of memory mapped */
    3235  int              flags; /**< The mapping flags */
     36  rtems_libio_t   *iop;   /**< The mapped object's file descriptor pointer */
     37  bool             is_shared_shm; /**< True if MAP_SHARED of shared memory */
    3338} mmap_mapping;
    3439
  • cpukit/posix/include/rtems/posix/shm.h

    r8290f95 r87de70a2  
    9292   */
    9393  int ( *object_read ) ( POSIX_Shm_Object *shm_obj, void *buf, size_t count );
     94
     95  /**
     96   * @brief Maps a shared memory object.
     97   *
     98   * Establishes a memory mapping between the shared memory object and the
     99   * caller.
     100   *
     101   * Returns the mapped address of the object.
     102   */
     103  void * ( *object_mmap ) ( POSIX_Shm_Object *shm_obj, size_t len, int prot, off_t off);
    94104};
    95105
     
    145155
    146156/**
     157 * @brief object_mmap operation for shm objects stored in RTEMS Workspace.
     158 */
     159extern void * _POSIX_Shm_Object_mmap_from_workspace(
     160  POSIX_Shm_Object *shm_obj,
     161  size_t len,
     162  int prot,
     163  off_t off
     164);
     165
     166/**
    147167 * @brief object_create operation for shm objects stored in C program heap.
    148168 */
     
    172192  void *buf,
    173193  size_t count
     194);
     195
     196/**
     197 * @brief object_mmap operation for shm objects stored in C program heap.
     198 */
     199extern void * _POSIX_Shm_Object_mmap_from_heap(
     200  POSIX_Shm_Object *shm_obj,
     201  size_t len,
     202  int prot,
     203  off_t off
    174204);
    175205
  • cpukit/posix/include/rtems/posix/shmimpl.h

    r8290f95 r87de70a2  
    9797}
    9898
     99static inline int POSIX_Shm_Attempt_delete(
     100    POSIX_Shm_Control* shm
     101)
     102{
     103  Objects_Control       *obj;
     104  ISR_lock_Context       lock_ctx;
     105  int err;
     106
     107  err = 0;
     108
     109  _Objects_Allocator_lock();
     110  --shm->reference_count;
     111  if ( shm->reference_count == 0 ) {
     112    if ( (*shm->shm_object.ops->object_delete)( &shm->shm_object ) != 0 ) {
     113      err = EIO;
     114    }
     115  }
     116  /* check if the object has been unlinked yet. */
     117  obj = _Objects_Get( shm->Object.id, &lock_ctx, &_POSIX_Shm_Information );
     118  if ( obj == NULL ) {
     119    /* if it was unlinked, then it can be freed. */
     120    _POSIX_Shm_Free( shm );
     121  } else {
     122    /* it will be freed when it is unlinked. */
     123    _ISR_lock_ISR_enable( &lock_ctx );
     124  }
     125  _Objects_Allocator_unlock();
     126  return err;
     127}
     128
    99129/** @} */
    100130
  • cpukit/posix/src/mmap.c

    r8290f95 r87de70a2  
     1/**
     2 * @file
     3 */
     4
    15/*
    26 * Copyright (c) 2012 Chris Johns (chrisj@rtems.org)
     7 * Copyright (c) 2017 Gedare Bloom (gedare@rtems.org)
    38 *
    49 * The license and distribution terms for this file may be
     
    2025#include "rtems/libio_.h"
    2126
    22 #include <rtems/posix/mmanimpl.h>
     27#include <rtems/posix/mmanimpl.h>
     28#include <rtems/posix/shmimpl.h>
    2329
    2430#define RTEMS_MUTEX_ATTRIBS \
     
    5056   * present we create the mapping lock then release libio lock.
    5157   */
     58  /* FIXME: double-checked locking anti-pattern. */
    5259  if ( mmap_mappings_lock == 0 ) {
    5360    rtems_status_code sc = RTEMS_SUCCESSFUL;
     
    5562    rtems_semaphore_obtain( rtems_libio_semaphore,
    5663                            RTEMS_WAIT, RTEMS_NO_TIMEOUT );
     64    /* FIXME: account for semaphore in confdefs, or maybe just use the
     65     * rtems_libio_semaphore? */
    5766    if ( mmap_mappings_lock == 0 )
    5867      sc = rtems_semaphore_create( rtems_build_name( 'M', 'M', 'A', 'P' ),
     
    99108}
    100109
     110/* Helper function only gets called for mmap mappings of shared memory objects
     111 * with the MAP_SHARED flag.
     112 */
     113static void *shm_mmap( rtems_libio_t *iop, size_t len, int prot, off_t off)
     114{
     115  POSIX_Shm_Control *shm = iop_to_shm( iop );
     116  void *m;
     117
     118  _Objects_Allocator_lock();
     119
     120  m = (*shm->shm_object.ops->object_mmap)( &shm->shm_object, len, prot, off);
     121  if ( m != NULL ) {
     122    /* Keep a reference in the shared memory to prevent its removal. */
     123    ++shm->reference_count;
     124
     125    /* Update atime */
     126    _POSIX_Shm_Update_atime(shm);
     127  }
     128
     129  _Objects_Allocator_unlock();
     130
     131  return m;
     132}
     133
    101134void *mmap(
    102135  void *addr, size_t len, int prot, int flags, int fildes, off_t off
    103136)
    104137{
    105   struct stat   sb;
    106   mmap_mapping* mapping;
    107   ssize_t       r;
    108  
    109   /*
    110    * Clear errno.
    111    */
     138  struct stat     sb;
     139  mmap_mapping   *mapping;
     140  ssize_t         r;
     141  rtems_libio_t  *iop;
     142  bool            map_fixed;
     143
     144  map_fixed = (flags & MAP_FIXED) == MAP_FIXED;
     145
     146  /* Clear errno. */
    112147  errno = 0;
    113  
     148
    114149  /*
    115150   * Get a stat of the file to get the dev + inode number and to make sure the
     
    123158  }
    124159
     160  /* fstat ensures we have a good file descriptor. Hold on to iop. */
     161  iop = rtems_libio_iop( fildes );
     162
    125163  if ( len == 0 ) {
    126164    errno = EINVAL;
     
    128166  }
    129167
    130   /*
    131    * Check the type of file we have and make sure it is supported.
    132    */
     168  /* Check the type of file we have and make sure it is supported. */
    133169  if ( S_ISDIR( sb.st_mode ) || S_ISLNK( sb.st_mode )) {
    134170    errno = ENODEV;
    135171    return MAP_FAILED;
    136172  }
    137  
     173
    138174  /*
    139175   * We can provide read, write and execute because the memory in RTEMS does
     
    141177   */
    142178  if ( prot == PROT_NONE ) {
     179    errno = ENOTSUP;
     180    return MAP_FAILED;
     181  }
     182
     183  /* Either MAP_SHARED or MAP_PRIVATE must be defined, but not both */
     184  if ( (flags & MAP_SHARED) == MAP_SHARED ) {
     185    if ( (flags & MAP_PRIVATE) == MAP_PRIVATE ) {
     186      errno = EINVAL;
     187      return MAP_FAILED;
     188    }
     189  } else if ( (flags & MAP_PRIVATE != MAP_PRIVATE) ) {
    143190    errno = EINVAL;
    144191    return MAP_FAILED;
    145192  }
    146  
    147   /*
    148    * Check to see if the mapping is valid for the file.
    149    */
     193
     194  /*
     195   * We can not normally provide restriction of write access. Reject any
     196   * attempt to map without write permission, since we are not able to
     197   * prevent a write from succeeding.
     198   */
     199  if ( PROT_WRITE != (prot & PROT_WRITE) ) {
     200    errno = ENOTSUP;
     201    return MAP_FAILED;
     202  }
     203
     204  /* Check to see if the mapping is valid for a regular file. */
    150205  if ( S_ISREG( sb.st_mode )
     206  /* FIXME: Should this be using strict inequality (>) comparisons? It would
     207   * be valid to map a region exactly equal to the st_size, e.g. see below. */
    151208       && (( off >= sb.st_size ) || (( off + len ) >= sb.st_size ))) {
    152209    errno = EOVERFLOW;
     
    155212
    156213  /*
    157    * Obtain the mmap lock. Sets errno on failure.
    158    */
     214   * Check to see if the mapping is valid for other file/object types.
     215   * Does this satisfy for devices?
     216   */
     217  if ( sb.st_size < off + len ) {
     218    errno = ENXIO;
     219    return MAP_FAILED;
     220  }
     221
     222  /* Do not seek on character devices, pipes, sockets, or memory objects. */
     223  if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) {
     224    if ( lseek( fildes, off, SEEK_SET ) < 0 ) {
     225      return MAP_FAILED;
     226    }
     227  }
     228
     229  /* Create the mapping */
     230  mapping = malloc( sizeof( mmap_mapping ));
     231  if ( !mapping ) {
     232    errno = ENOMEM;
     233    return NULL;
     234  }
     235  memset( mapping, 0, sizeof( mmap_mapping ));
     236  mapping->len = len;
     237  mapping->flags = flags;
     238  mapping->iop = iop;
     239
     240  /*
     241   * HACK: We should have a better generic way to distinguish between
     242   * shm objects and other mmap'd files. We need to know at munmap time
     243   * if the mapping is to a shared memory object in order to refcnt shms.
     244   * We could do this by providing mmap in the file operations if needed.
     245   */
     246  if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ||
     247       S_ISCHR( sb.st_mode ) || S_ISFIFO( sb.st_mode ) ||
     248       S_ISSOCK( sb.st_mode ) ) {
     249    mapping->is_shared_shm = false;
     250  } else {
     251    mapping->is_shared_shm = true;
     252  }
     253
     254  /*
     255   * MAP_SHARED currently is only supported for shared memory objects.
     256   */
     257  if ( (MAP_SHARED == (flags & MAP_SHARED)) && (mapping->is_shared_shm == false) ) {
     258    free( mapping );
     259    errno = ENOTSUP;
     260    return MAP_FAILED;
     261  }
     262
     263  if ( map_fixed ) {
     264    mapping->addr = addr;
     265  } else if ( MAP_PRIVATE == (flags & MAP_PRIVATE) ) {
     266    /* private mappings of shared memory do not need special treatment. */
     267    mapping->is_shared_shm = false;
     268    mapping->addr = malloc( len );
     269    if ( !mapping->addr ) {
     270      free( mapping );
     271      errno = ENOMEM;
     272      return MAP_FAILED;
     273    }
     274  }
     275
     276  /* MAP_FIXED is not supported for shared memory objects with MAP_SHARED. */
     277  if ( map_fixed && mapping->is_shared_shm ) {
     278    free( mapping );
     279    errno = ENOTSUP;
     280    return MAP_FAILED;
     281  }
     282
     283  /* Lock access to mmap_mappings. Sets errno on failure. */
    159284  if ( !mmap_mappings_lock_obtain( ) )
    160285    return MAP_FAILED;
    161286
    162   if (( flags & MAP_FIXED ) == MAP_FIXED ) {
     287  if ( map_fixed ) {
    163288    rtems_chain_node* node = rtems_chain_first (&mmap_mappings);
    164289    while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
     
    166291       * If the map is fixed see if this address is already mapped. At this
    167292       * point in time if there is an overlap in the mappings we return an
    168        * error.
     293       * error. POSIX allows us to also return successfully by unmapping
     294       * the overlapping prior mappings.
    169295       */
    170296      mapping = (mmap_mapping*) node;
    171297      if ( ( addr >= mapping->addr ) &&
    172298           ( addr < ( mapping->addr + mapping->len )) ) {
     299        free( mapping );
    173300        mmap_mappings_lock_release( );
    174301        errno = ENXIO;
     
    179306  }
    180307
    181   mapping = malloc( sizeof( mmap_mapping ));
    182   if ( !mapping ) {
    183     mmap_mappings_lock_release( );
    184     errno = ENOMEM;
    185     return NULL;
    186   }
    187 
    188   memset( mapping, 0, sizeof( mmap_mapping ));
    189 
    190   mapping->len = len;
    191   mapping->flags = flags;
    192  
    193   if (( flags & MAP_FIXED ) != MAP_FIXED ) {
    194     mapping->addr = malloc( len );
    195     if ( !mapping->addr ) {
     308  /* Populate the data */
     309  if ( MAP_PRIVATE == (flags & MAP_PRIVATE) ) {
     310    /*
     311     * Use read() for private mappings. This updates atime as needed.
     312     * Changes to the underlying object will NOT be reflected in the mapping.
     313     * The underlying object can be removed while the mapping exists.
     314     */
     315    r = read( fildes, mapping->addr, len );
     316
     317    if ( r != len ) {
    196318      mmap_mappings_lock_release( );
     319      if ( !map_fixed ) {
     320        free( mapping->addr );
     321      }
    197322      free( mapping );
    198       errno = ENOMEM;
     323      errno = ENXIO;
    199324      return MAP_FAILED;
    200325    }
    201 
    202     /*
    203      * Do not seek on character devices, pipes or sockets.
    204      */
    205     if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) {
    206       if ( lseek( fildes, off, SEEK_SET ) < 0 ) {
    207         mmap_mappings_lock_release( );
    208         free( mapping->addr );
    209         free( mapping );
    210         return MAP_FAILED;
    211       }
    212     }
    213   }
    214 
    215   r = read( fildes, mapping->addr, len );
    216 
    217   if ( r != len ) {
    218     mmap_mappings_lock_release( );
    219     free( mapping->addr );
    220     free( mapping );
    221     errno = ENXIO;
    222     return MAP_FAILED;
    223   }
     326  } else if ( MAP_SHARED == (flags & MAP_SHARED) ) {
     327    /* Currently only shm objects can be MAP_SHARED. */
     328    mapping->addr = shm_mmap(iop, len, prot, off);
     329  }
     330
     331  /* add an extra reference to the file associated with fildes that
     332   * is not removed by a subsequent close().  This reference shall be removed
     333   * when there are no more mappings to the file. */
     334  rtems_libio_increment_mapping_refcnt(iop);
    224335
    225336  rtems_chain_append( &mmap_mappings, &mapping->node );
    226337
    227338  mmap_mappings_lock_release( );
    228  
     339
    229340  return mapping->addr;
    230341}
  • cpukit/posix/src/munmap.c

    r8290f95 r87de70a2  
    11/*
    22 * Copyright (c) 2012 Chris Johns (chrisj@rtems.org)
     3 * Copyright (c) 2017 Gedare Bloom (gedare@rtems.org)
    34 *
    45 * The license and distribution terms for this file may be
     
    1718
    1819#include <rtems/posix/mmanimpl.h>
     20#include <rtems/posix/shmimpl.h>
    1921
    20 int munmap(
    21   void *addr, size_t len
    22 )
     22static void shm_munmap( rtems_libio_t *iop )
    2323{
    24   mmap_mapping*     mapping;
    25   rtems_chain_node* node;
     24  POSIX_Shm_Control *shm = iop_to_shm( iop );
     25
     26  /* decrement mmap's shm reference_count and maybe delete the object */
     27  POSIX_Shm_Attempt_delete(shm);
     28}
     29
     30int munmap(void *addr, size_t len)
     31{
     32  mmap_mapping      *mapping;
     33  rtems_chain_node  *node;
     34  uint32_t           refcnt;
    2635 
    2736  /*
     
    4655  node = rtems_chain_first (&mmap_mappings);
    4756  while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
    48     /*
    49      * If the map is fixed see if this address is already mapped. At this
    50      * point in time if there is an overlap in the mappings we return an
    51      * error.
    52      */
    5357    mapping = (mmap_mapping*) node;
    5458    if ( ( addr >= mapping->addr ) &&
    5559         ( addr < ( mapping->addr + mapping->len )) ) {
    5660      rtems_chain_extract( node );
     61      /* FIXME: generally need a way to clean-up the backing object, but
     62       * currently it only matters for MAP_SHARED shm objects. */
     63      if ( mapping->is_shared_shm == true ) {
     64        shm_munmap(mapping->iop);
     65      }
     66      refcnt = rtems_libio_decrement_mapping_refcnt(mapping->iop);
     67      if ( refcnt == 0 ) {
     68        rtems_libio_check_deferred_free(mapping->iop);
     69      }
     70      /* only free the mapping address for non-fixed mapping */
    5771      if (( mapping->flags & MAP_FIXED ) != MAP_FIXED ) {
    58         free( mapping->addr );
    59         free( mapping );
     72        /* only free the mapping address for non-shared mapping, because we
     73         * re-use the mapping address across all of the shared mappings, and
     74         * it is memory managed independently... */
     75        if (( mapping->flags & MAP_SHARED ) != MAP_SHARED ) {
     76          free( mapping->addr );
     77        }
    6078      }
     79      free( mapping );
    6180      break;
    6281    }
  • cpukit/posix/src/shmheap.c

    r8290f95 r87de70a2  
    7171}
    7272
     73/* This is identical to _POSIX_Shm_Object_read_from_wkspace */
    7374int _POSIX_Shm_Object_read_from_heap(
    7475  POSIX_Shm_Object *shm_obj,
     
    8990}
    9091
     92/* This is identical to _POSIX_Shm_Object_mmap_from_wkspace */
     93void * _POSIX_Shm_Object_mmap_from_heap(
     94  POSIX_Shm_Object *shm_obj,
     95  size_t len,
     96  int prot,
     97  off_t off
     98)
     99{
     100  if ( shm_obj == NULL || shm_obj->handle == NULL )
     101    return 0;
     102
     103  /* This is already checked by mmap. Maybe make it a debug assert? */
     104  if ( shm_obj->size < len + off ) {
     105    return NULL;
     106  }
     107
     108  return &(shm_obj->handle[off]);
     109}
     110
  • cpukit/posix/src/shmopen.c

    r8290f95 r87de70a2  
    9494{
    9595  POSIX_Shm_Control *shm = iop_to_shm( iop );
    96   Objects_Control       *obj;
    97   ISR_lock_Context       lock_ctx;
    9896  int err;
    9997
    10098  err = 0;
    10199
    102   _Objects_Allocator_lock();
    103 
    104   --shm->reference_count;
    105   if ( shm->reference_count == 0 ) {
    106     /* TODO: need to make sure this counts mmaps too! */
    107     if ( (*shm->shm_object.ops->object_delete)( &shm->shm_object ) != 0 ) {
    108       err = EIO;
    109     }
    110     /* check if the object has been unlinked yet. */
    111     obj = _Objects_Get( shm->Object.id, &lock_ctx, &_POSIX_Shm_Information );
    112     if ( obj == NULL ) {
    113       /* if it was unlinked, then it can be freed. */
    114       _POSIX_Shm_Free( shm );
    115     } else {
    116       /* it will be freed when it is unlinked. */
    117       _ISR_lock_ISR_enable( &lock_ctx );
    118     }
    119   }
     100  POSIX_Shm_Attempt_delete(shm);
    120101  iop->pathinfo.node_access = NULL;
    121 
    122   _Objects_Allocator_unlock();
    123102
    124103  if ( err != 0 ) {
  • cpukit/posix/src/shmunlink.c

    r8290f95 r87de70a2  
    4141      _Objects_Close( &_POSIX_Shm_Information, &shm->Object );
    4242      if ( shm->reference_count == 0 ) {
    43         /* TODO: need to make sure this counts mmaps too! */
    44         /* only remove the shm object if no references exist to it. */
     43        /* Only remove the shm object if no references exist to it. Otherwise,
     44         * the shm object will be freed later in _POSIX_Shm_Attempt_delete */
    4545        _POSIX_Shm_Free( shm );
    4646      }
  • cpukit/posix/src/shmwkspace.c

    r8290f95 r87de70a2  
    7676}
    7777
     78void * _POSIX_Shm_Object_mmap_from_workspace(
     79  POSIX_Shm_Object *shm_obj,
     80  size_t len,
     81  int prot,
     82  off_t off
     83)
     84{
     85  if ( shm_obj == NULL || shm_obj->handle == NULL )
     86    return 0;
    7887
     88  /* This is already checked by mmap. Maybe make it a debug assert? */
     89  if ( shm_obj->size < len + off ) {
     90    return NULL;
     91  }
     92
     93  return &(shm_obj->handle[off]);
     94}
     95
Note: See TracChangeset for help on using the changeset viewer.