Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r79895 - in trunk/boost/interprocess: . detail
From: igaztanaga_at_[hidden]
Date: 2012-08-07 05:06:45


Author: igaztanaga
Date: 2012-08-07 05:06:43 EDT (Tue, 07 Aug 2012)
New Revision: 79895
URL: http://svn.boost.org/trac/boost/changeset/79895

Log:
Added `shrink_by` and `advise` functions in `mapped_region`.
Text files modified:
   trunk/boost/interprocess/detail/os_file_functions.hpp | 50 ++++----
   trunk/boost/interprocess/detail/win32_api.hpp | 10 +
   trunk/boost/interprocess/mapped_region.hpp | 207 ++++++++++++++++++++++++++++++++++++++-
   3 files changed, 236 insertions(+), 31 deletions(-)

Modified: trunk/boost/interprocess/detail/os_file_functions.hpp
==============================================================================
--- trunk/boost/interprocess/detail/os_file_functions.hpp (original)
+++ trunk/boost/interprocess/detail/os_file_functions.hpp 2012-08-07 05:06:43 EDT (Tue, 07 Aug 2012)
@@ -96,28 +96,28 @@
 
 inline file_handle_t create_new_file
    (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
-{
+{
    unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
    return winapi::create_file
       ( name, (unsigned int)mode, winapi::create_new, attr
- , (winapi::interprocess_security_attributes*)perm.get_permissions());
+ , (winapi::interprocess_security_attributes*)perm.get_permissions());
 }
 
 inline file_handle_t create_or_open_file
    (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
-{
+{
    unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
    return winapi::create_file
       ( name, (unsigned int)mode, winapi::open_always, attr
- , (winapi::interprocess_security_attributes*)perm.get_permissions());
+ , (winapi::interprocess_security_attributes*)perm.get_permissions());
 }
 
 inline file_handle_t open_existing_file
    (const char *name, mode_t mode, bool temporary = false)
-{
+{
    unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
    return winapi::create_file
- (name, (unsigned int)mode, winapi::open_existing, attr, 0);
+ (name, (unsigned int)mode, winapi::open_existing, attr, 0);
 }
 
 inline bool delete_file(const char *name)
@@ -177,7 +177,7 @@
 { return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); }
 
 inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
-{
+{
    unsigned long written;
    return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0);
 }
@@ -189,9 +189,9 @@
 { return 0 != winapi::close_handle(hnd); }
 
 inline bool acquire_file_lock(file_handle_t hnd)
-{
+{
    static winapi::interprocess_overlapped overlapped;
- const unsigned long len = ~((unsigned long)(0u));
+ const unsigned long len = ((unsigned long)-1);
 // winapi::interprocess_overlapped overlapped;
 // std::memset(&overlapped, 0, sizeof(overlapped));
    return winapi::lock_file_ex
@@ -199,8 +199,8 @@
 }
 
 inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
-{
- const unsigned long len = ~((unsigned long)(0u));
+{
+ const unsigned long len = ((unsigned long)-1);
    winapi::interprocess_overlapped overlapped;
    std::memset(&overlapped, 0, sizeof(overlapped));
    if(!winapi::lock_file_ex
@@ -208,30 +208,30 @@
        0, len, len, &overlapped)){
       return winapi::get_last_error() == winapi::error_lock_violation ?
                acquired = false, true : false;
-
+
    }
    return (acquired = true);
 }
 
 inline bool release_file_lock(file_handle_t hnd)
-{
- const unsigned long len = ~((unsigned long)(0u));
+{
+ const unsigned long len = ((unsigned long)-1);
    winapi::interprocess_overlapped overlapped;
    std::memset(&overlapped, 0, sizeof(overlapped));
    return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped);
 }
 
 inline bool acquire_file_lock_sharable(file_handle_t hnd)
-{
- const unsigned long len = ~((unsigned long)(0u));
+{
+ const unsigned long len = ((unsigned long)-1);
    winapi::interprocess_overlapped overlapped;
    std::memset(&overlapped, 0, sizeof(overlapped));
    return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped);
 }
 
 inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
-{
- const unsigned long len = ~((unsigned long)(0u));
+{
+ const unsigned long len = ((unsigned long)-1);
    winapi::interprocess_overlapped overlapped;
    std::memset(&overlapped, 0, sizeof(overlapped));
    if(!winapi::lock_file_ex
@@ -406,7 +406,7 @@
 
 inline file_handle_t create_new_file
    (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
-{
+{
    (void)temporary;
    int ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions());
    if(ret >= 0){
@@ -439,7 +439,7 @@
 
 inline file_handle_t open_existing_file
    (const char *name, mode_t mode, bool temporary = false)
-{
+{
    (void)temporary;
    return ::open(name, (int)mode);
 }
@@ -459,7 +459,7 @@
 }
 
 inline bool get_file_size(file_handle_t hnd, offset_t &size)
-{
+{
    struct stat data;
    bool ret = 0 == ::fstat(hnd, &data);
    if(ret){
@@ -472,7 +472,7 @@
 { return ((off_t)(-1)) != ::lseek(hnd, off, (int)pos); }
 
 inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
-{
+{
    off = ::lseek(hnd, 0, SEEK_CUR);
    return off != ((off_t)-1);
 }
@@ -522,7 +522,7 @@
 }
 
 inline bool acquire_file_lock_sharable(file_handle_t hnd)
-{
+{
    struct ::flock lock;
    lock.l_type = F_RDLCK;
    lock.l_whence = SEEK_SET;
@@ -532,7 +532,7 @@
 }
 
 inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
-{
+{
    struct flock lock;
    lock.l_type = F_RDLCK;
    lock.l_whence = SEEK_SET;
@@ -601,7 +601,7 @@
             || (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
          continue;
       }
- if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
+ if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
          continue;
       }
       fn = refcstrRootDirectory;

Modified: trunk/boost/interprocess/detail/win32_api.hpp
==============================================================================
--- trunk/boost/interprocess/detail/win32_api.hpp (original)
+++ trunk/boost/interprocess/detail/win32_api.hpp 2012-08-07 05:06:43 EDT (Tue, 07 Aug 2012)
@@ -50,6 +50,7 @@
 static const unsigned long error_sharing_violation = 32L;
 static const unsigned long error_file_not_found = 2u;
 static const unsigned long error_no_more_files = 18u;
+static const unsigned long error_not_locked = 158L;
 //Retries in CreateFile, see http://support.microsoft.com/kb/316609
 static const unsigned int error_sharing_violation_tries = 3u;
 static const unsigned int error_sharing_violation_sleep_ms = 250u;
@@ -61,6 +62,7 @@
 static const unsigned long page_readonly = 0x02;
 static const unsigned long page_readwrite = 0x04;
 static const unsigned long page_writecopy = 0x08;
+static const unsigned long page_noaccess = 0x01;
 
 static const unsigned long standard_rights_required = 0x000F0000L;
 static const unsigned long section_query = 0x0001;
@@ -876,6 +878,8 @@
 extern "C" __declspec(dllimport) int __stdcall MoveFileExA (const char *, const char *, unsigned long);
 extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *);
 extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t);
+extern "C" __declspec(dllimport) int __stdcall VirtualUnlock (void *, std::size_t);
+extern "C" __declspec(dllimport) int __stdcall VirtualProtect (void *, std::size_t, unsigned long, unsigned long *);
 extern "C" __declspec(dllimport) int __stdcall FlushFileBuffers (void *);
 extern "C" __declspec(dllimport) int __stdcall GetFileSizeEx (void *, __int64 *size);
 extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA
@@ -1137,6 +1141,12 @@
 inline bool flush_view_of_file(void *base_addr, std::size_t numbytes)
 { return 0 != FlushViewOfFile(base_addr, numbytes); }
 
+inline bool virtual_unlock(void *base_addr, std::size_t numbytes)
+{ return 0 != VirtualUnlock(base_addr, numbytes); }
+
+inline bool virtual_protect(void *base_addr, std::size_t numbytes, unsigned long flNewProtect, unsigned long &lpflOldProtect)
+{ return 0 != VirtualProtect(base_addr, numbytes, flNewProtect, &lpflOldProtect); }
+
 inline bool flush_file_buffers(void *handle)
 { return 0 != FlushFileBuffers(handle); }
 

Modified: trunk/boost/interprocess/mapped_region.hpp
==============================================================================
--- trunk/boost/interprocess/mapped_region.hpp (original)
+++ trunk/boost/interprocess/mapped_region.hpp 2012-08-07 05:06:43 EDT (Tue, 07 Aug 2012)
@@ -117,6 +117,10 @@
       return *this;
    }
 
+ //!Swaps the mapped_region with another
+ //!mapped region
+ void swap(mapped_region &other);
+
    //!Returns the size of the mapping. Never throws.
    std::size_t get_size() const;
 
@@ -135,9 +139,41 @@
    //!Never throws. Returns false if operation could not be performed.
    bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0, bool async = true);
 
- //!Swaps the mapped_region with another
- //!mapped region
- void swap(mapped_region &other);
+ //!Shrinks current mapped region. If after shrinking there is no longer need for a previously
+ //!mapped memory page, accessing that page can trigger a segmentation fault.
+ //!Depending on the OS, this operation might fail (XSI shared memory), it can decommit storage
+ //!and free a portion of the virtual address space (e.g.POSIX) or this
+ //!function can release some physical memory wihout freeing any virtual address space(Windows).
+ //!Returns true on success. Never throws.
+ bool shrink_by(std::size_t bytes, bool from_back = true);
+
+ //!This enum specifies region usage behaviors that an application can specify
+ //!to the mapped region implementation.
+ enum advice_types{
+ //!Specifies that the application has no advice to give on its behavior with respect to
+ //!the region. It is the default characteristic if no advice is given for a range of memory.
+ advice_normal,
+ //!Specifies that the application expects to access the region sequentially from
+ //!lower addresses to higher addresses. The implementation can lower the priority of
+ //!preceding pages within the region once a page have been accessed.
+ advice_sequential,
+ //!Specifies that the application expects to access the region in a random order,
+ //!and prefetching is likely not advantageous.
+ advice_random,
+ //!Specifies that the application expects to access the region in the near future.
+ //!The implementation can prefetch pages of the region.
+ advice_willneed,
+ //!Specifies that the application expects that it will not access the region in the near future.
+ //!The implementation can unload pages within the range to save system resources.
+ advice_dontneed
+ };
+
+ //!Advises the implementation on the expected behavior of the application with respect to the data
+ //!in the region. The implementation may use this information to optimize handling of the region data.
+ //!This function has no effect on the semantics of access to memory in the region, although it may affect
+ //!the performance of access.
+ //!If the advise type is not known to the implementation, the function returns false. True otherwise.
+ bool advise(advice_types advise);
 
    //!Returns the size of the page. This size is the minimum memory that
    //!will be used by the system when mapping a memory mappable source and
@@ -152,6 +188,7 @@
    void* priv_map_address() const;
    std::size_t priv_map_size() const;
    bool priv_flush_param_check(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const;
+ bool priv_shrink_param_check(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes);
    static void priv_size_from_mapping_size
       (offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size);
    static offset_t priv_page_offset_addr_fixup(offset_t page_offset, const void *&addr);
@@ -226,6 +263,38 @@
    return true;
 }
 
+inline bool mapped_region::priv_shrink_param_check
+ (std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes)
+{
+ //Check some errors
+ if(m_base == 0 || bytes > m_size){
+ return false;
+ }
+ else if(bytes == m_size){
+ this->priv_close();
+ return true;
+ }
+ else{
+ const std::size_t page_size = mapped_region::get_page_size();
+ if(from_back){
+ const std::size_t new_pages = (m_size + m_page_offset - bytes - 1)/page_size + 1;
+ shrink_page_start = static_cast<char*>(this->priv_map_address()) + new_pages*page_size;
+ shrink_page_bytes = m_page_offset + m_size - new_pages*page_size;
+ m_size -= bytes;
+ }
+ else{
+ shrink_page_start = this->priv_map_address();
+ m_page_offset += bytes;
+ shrink_page_bytes = (m_page_offset/page_size)*page_size;
+ m_page_offset = m_page_offset % page_size;
+ m_size -= bytes;
+ m_base = static_cast<char *>(m_base) + bytes;
+ assert(shrink_page_bytes%page_size == 0);
+ }
+ return true;
+ }
+}
+
 inline void mapped_region::priv_size_from_mapping_size
    (offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size)
 {
@@ -405,6 +474,37 @@
    return true;
 }
 
+inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back)
+{
+ void *shrink_page_start;
+ std::size_t shrink_page_bytes;
+ if(!this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){
+ return false;
+ }
+ else if(shrink_page_bytes){
+ //In Windows, we can't decommit the storage or release the virtual address space,
+ //the best we can do is try to remove some memory from the process working set.
+ //With a bit of luck we can free some physical memory.
+ unsigned long old_protect_ignored;
+ bool b_ret = winapi::virtual_unlock(shrink_page_start, shrink_page_bytes)
+ || (winapi::get_last_error() == winapi::error_not_locked);
+ (void)old_protect_ignored;
+ //Change page protection to forbid any further access
+ b_ret = b_ret && winapi::virtual_protect
+ (shrink_page_start, shrink_page_bytes, winapi::page_noaccess, old_protect_ignored);
+ return b_ret;
+ }
+ else{
+ return true;
+ }
+}
+
+inline bool mapped_region::advise(advice_types)
+{
+ //Windows has no madvise/posix_madvise equivalent
+ return false;
+}
+
 inline void mapped_region::priv_close()
 {
    if(m_base){
@@ -503,7 +603,13 @@
 
    //Create new mapping
    int prot = 0;
- int flags = 0;
+ int flags =
+ #ifdef MAP_NOSYNC
+ //Avoid excessive syncing in BSD systems
+ MAP_NOSYNC;
+ #else
+ 0;
+ #endif
 
    switch(mode)
    {
@@ -562,14 +668,103 @@
    }
 }
 
+inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back)
+{
+ void *shrink_page_start;
+ std::size_t shrink_page_bytes;
+ if(m_is_xsi || !this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){
+ return false;
+ }
+ else if(shrink_page_bytes){
+ //In UNIX we can decommit and free virtual address space.
+ return 0 == munmap(shrink_page_start, shrink_page_bytes);
+ }
+ else{
+ return true;
+ }
+}
+
 inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async)
 {
    void *addr;
- if(!this->priv_flush_param_check(mapping_offset, addr, numbytes)){
+ if(m_is_xsi || !this->priv_flush_param_check(mapping_offset, addr, numbytes)){
       return false;
    }
    //Flush it all
- return msync( addr, numbytes, async ? MS_ASYNC : MS_SYNC) == 0;
+ return msync(addr, numbytes, async ? MS_ASYNC : MS_SYNC) == 0;
+}
+
+inline bool mapped_region::advise(advice_types advice)
+{
+ int unix_advice = 0;
+ //Modes; 0: none, 2: posix, 1: madvise
+ const unsigned int mode_none = 0;
+ const unsigned int mode_padv = 1;
+ const unsigned int mode_madv = 2;
+ unsigned int mode = mode_none;
+ //Choose advice either from POSIX (preferred) or native Unix
+ switch(advice){
+ case advice_normal:
+ #if defined(POSIX_MADV_NORMAL)
+ unix_advice = POSIX_MADV_NORMAL;
+ mode = mode_padv;
+ #elif defined(MADV_NORMAL)
+ unix_advice = MADV_NORMAL;
+ mode = mode_madv;
+ #endif
+ break;
+ case advice_sequential:
+ #if defined(POSIX_MADV_SEQUENTIAL)
+ unix_advice = POSIX_MADV_SEQUENTIAL;
+ mode = mode_padv;
+ #elif defined(MADV_SEQUENTIAL)
+ unix_advice = MADV_SEQUENTIAL;
+ mode = mode_madv;
+ #endif
+ break;
+ case advice_random:
+ #if defined(POSIX_MADV_RANDOM)
+ unix_advice = POSIX_MADV_RANDOM;
+ mode = mode_padv;
+ #elif defined(MADV_RANDOM)
+ unix_advice = MADV_RANDOM;
+ mode = mode_madv;
+ #endif
+ break;
+ case advice_willneed:
+ #if defined(POSIX_MADV_WILLNEED)
+ unix_advice = POSIX_MADV_WILLNEED;
+ mode = mode_padv;
+ #elif defined(MADV_WILLNEED)
+ unix_advice = MADV_WILLNEED;
+ mode = mode_madv;
+ #endif
+ break;
+ case advice_dontneed:
+ #if defined(POSIX_MADV_DONTNEED)
+ unix_advice = POSIX_MADV_DONTNEED;
+ mode = mode_padv;
+ #elif defined(MADV_DONTNEED)
+ unix_advice = MADV_DONTNEED;
+ mode = mode_madv;
+ #endif
+ break;
+ default:
+ return false;
+ }
+ switch(mode){
+ #if defined(POSIX_MADV_NORMAL)
+ case mode_padv:
+ return 0 == posix_madvise(this->priv_map_address(), this->priv_map_size(), unix_advice);
+ #endif
+ #if defined(MADV_NORMAL)
+ case mode_madv:
+ return 0 == madvise(this->priv_map_address(), this->priv_map_size(), unix_advice);
+ #endif
+ default:
+ return false;
+
+ }
 }
 
 inline void mapped_region::priv_close()


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk