mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-30 08:43:31 +08:00
@@ -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; /* ... */
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+166
-55
@@ -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,54 +157,146 @@ 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 ( sb.st_size < off + len ) {
|
||||
errno = ENXIO;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
/* 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 ) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
memset( mapping, 0, sizeof( mmap_mapping ));
|
||||
mapping->len = len;
|
||||
mapping->flags = flags;
|
||||
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 ) {
|
||||
free( mapping );
|
||||
errno = ENOMEM;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (( flags & MAP_FIXED ) == MAP_FIXED ) {
|
||||
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.
|
||||
* 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;
|
||||
@@ -178,53 +305,37 @@ void *mmap(
|
||||
}
|
||||
}
|
||||
|
||||
mapping = malloc( sizeof( mmap_mapping ));
|
||||
if ( !mapping ) {
|
||||
mmap_mappings_lock_release( );
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
/* 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 );
|
||||
|
||||
memset( mapping, 0, sizeof( mmap_mapping ));
|
||||
|
||||
mapping->len = len;
|
||||
mapping->flags = flags;
|
||||
|
||||
if (( flags & MAP_FIXED ) != MAP_FIXED ) {
|
||||
mapping->addr = malloc( len );
|
||||
if ( !mapping->addr ) {
|
||||
if ( r != len ) {
|
||||
mmap_mappings_lock_release( );
|
||||
if ( !map_fixed ) {
|
||||
free( mapping->addr );
|
||||
}
|
||||
free( mapping );
|
||||
errno = ENOMEM;
|
||||
errno = ENXIO;
|
||||
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 );
|
||||
free( mapping );
|
||||
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);
|
||||
}
|
||||
|
||||
r = read( fildes, mapping->addr, len );
|
||||
|
||||
if ( r != len ) {
|
||||
mmap_mappings_lock_release( );
|
||||
free( mapping->addr );
|
||||
free( mapping );
|
||||
errno = ENXIO;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
+32
-13
@@ -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 );
|
||||
if (( mapping->flags & MAP_FIXED ) != MAP_FIXED ) {
|
||||
free( mapping->addr );
|
||||
free( mapping );
|
||||
/* 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 ) {
|
||||
/* 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 );
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user