You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
265 lines
6.8 KiB
265 lines
6.8 KiB
////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost |
|
// Software License, Version 1.0. (See accompanying file |
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
// See http://www.boost.org/libs/interprocess for documentation. |
|
// |
|
////////////////////////////////////////////////////////////////////////////// |
|
|
|
#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP |
|
#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP |
|
|
|
#include <boost/interprocess/detail/posix_time_types_wrk.hpp> |
|
#include <boost/interprocess/exceptions.hpp> |
|
#include <boost/interprocess/creation_tags.hpp> |
|
#include <boost/interprocess/detail/os_file_functions.hpp> |
|
#include <boost/interprocess/detail/tmp_dir_helpers.hpp> |
|
#include <boost/interprocess/permissions.hpp> |
|
#include <string> |
|
#include <semaphore.h> |
|
#include <boost/assert.hpp> |
|
|
|
#ifdef SEM_FAILED |
|
#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(SEM_FAILED)) |
|
#else |
|
#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(-1)) |
|
#endif |
|
|
|
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS |
|
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp> |
|
#else |
|
#include <boost/interprocess/detail/os_thread_functions.hpp> |
|
#endif |
|
|
|
namespace boost { |
|
namespace interprocess { |
|
|
|
/// @cond |
|
namespace ipcdetail{ class interprocess_tester; } |
|
/// @endcond |
|
|
|
namespace ipcdetail { |
|
|
|
inline bool semaphore_open |
|
(sem_t *&handle, ipcdetail::create_enum_t type, const char *origname, |
|
unsigned int count, const permissions &perm = permissions()) |
|
{ |
|
std::string name; |
|
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES |
|
ipcdetail::add_leading_slash(origname, name); |
|
#else |
|
ipcdetail::create_tmp_and_clean_old_and_get_filename(origname, name); |
|
#endif |
|
|
|
//Create new mapping |
|
int oflag = 0; |
|
switch(type){ |
|
case ipcdetail::DoOpen: |
|
//No addition |
|
break; |
|
case ipcdetail::DoCreate: |
|
oflag |= (O_CREAT | O_EXCL); |
|
break; |
|
case ipcdetail::DoOpenOrCreate: |
|
oflag |= O_CREAT; |
|
break; |
|
default: |
|
{ |
|
error_info err = other_error; |
|
throw interprocess_exception(err); |
|
} |
|
} |
|
|
|
//Open file using POSIX API |
|
if(oflag & O_CREAT) |
|
handle = sem_open(name.c_str(), oflag, perm.get_permissions(), count); |
|
else |
|
handle = sem_open(name.c_str(), oflag); |
|
|
|
//Check for error |
|
if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){ |
|
throw interprocess_exception(error_info(errno)); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
inline void semaphore_close(sem_t *handle) |
|
{ |
|
int ret = sem_close(handle); |
|
if(ret != 0){ |
|
BOOST_ASSERT(0); |
|
} |
|
} |
|
|
|
inline bool semaphore_unlink(const char *semname) |
|
{ |
|
try{ |
|
std::string sem_str; |
|
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES |
|
ipcdetail::add_leading_slash(semname, sem_str); |
|
#else |
|
ipcdetail::tmp_filename(semname, sem_str); |
|
#endif |
|
return 0 == sem_unlink(sem_str.c_str()); |
|
} |
|
catch(...){ |
|
return false; |
|
} |
|
} |
|
|
|
inline void semaphore_init(sem_t *handle, unsigned int initialCount) |
|
{ |
|
int ret = sem_init(handle, 1, initialCount); |
|
//According to SUSV3 version 2003 edition, the return value of a successful |
|
//sem_init call is not defined, but -1 is returned on failure. |
|
//In the future, a successful call might be required to return 0. |
|
if(ret == -1){ |
|
throw interprocess_exception(system_error_code()); |
|
} |
|
} |
|
|
|
inline void semaphore_destroy(sem_t *handle) |
|
{ |
|
int ret = sem_destroy(handle); |
|
if(ret != 0){ |
|
BOOST_ASSERT(0); |
|
} |
|
} |
|
|
|
inline void semaphore_post(sem_t *handle) |
|
{ |
|
int ret = sem_post(handle); |
|
if(ret != 0){ |
|
throw interprocess_exception(system_error_code()); |
|
} |
|
} |
|
|
|
inline void semaphore_wait(sem_t *handle) |
|
{ |
|
int ret = sem_wait(handle); |
|
if(ret != 0){ |
|
throw interprocess_exception(system_error_code()); |
|
} |
|
} |
|
|
|
inline bool semaphore_try_wait(sem_t *handle) |
|
{ |
|
int res = sem_trywait(handle); |
|
if(res == 0) |
|
return true; |
|
if(system_error_code() == EAGAIN){ |
|
return false; |
|
} |
|
throw interprocess_exception(system_error_code()); |
|
return false; |
|
} |
|
|
|
inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time) |
|
{ |
|
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS |
|
timespec tspec = ipcdetail::ptime_to_timespec(abs_time); |
|
for (;;){ |
|
int res = sem_timedwait(handle, &tspec); |
|
if(res == 0) |
|
return true; |
|
if (res > 0){ |
|
//buggy glibc, copy the returned error code to errno |
|
errno = res; |
|
} |
|
if(system_error_code() == ETIMEDOUT){ |
|
return false; |
|
} |
|
throw interprocess_exception(system_error_code()); |
|
} |
|
return false; |
|
#else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS |
|
boost::posix_time::ptime now; |
|
while((now = microsec_clock::universal_time()) < abs_time){ |
|
if(semaphore_try_wait(handle)) |
|
return true; |
|
thread_yield(); |
|
} |
|
return false; |
|
#endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS |
|
} |
|
|
|
|
|
class named_semaphore_wrapper |
|
{ |
|
named_semaphore_wrapper(); |
|
named_semaphore_wrapper(const named_semaphore_wrapper&); |
|
named_semaphore_wrapper &operator= (const named_semaphore_wrapper &); |
|
|
|
public: |
|
named_semaphore_wrapper |
|
(ipcdetail::create_enum_t type, const char *name, unsigned int count, const permissions &perm = permissions()) |
|
{ semaphore_open(mp_sem, type, name, count, perm); } |
|
|
|
~named_semaphore_wrapper() |
|
{ |
|
if(mp_sem != BOOST_INTERPROCESS_POSIX_SEM_FAILED) |
|
semaphore_close(mp_sem); |
|
} |
|
|
|
void post() |
|
{ semaphore_post(mp_sem); } |
|
|
|
void wait() |
|
{ semaphore_wait(mp_sem); } |
|
|
|
bool try_wait() |
|
{ return semaphore_try_wait(mp_sem); } |
|
|
|
bool timed_wait(const boost::posix_time::ptime &abs_time) |
|
{ return semaphore_timed_wait(mp_sem, abs_time); } |
|
|
|
static bool remove(const char *name) |
|
{ return semaphore_unlink(name); } |
|
|
|
private: |
|
friend class ipcdetail::interprocess_tester; |
|
void dont_close_on_destruction() |
|
{ mp_sem = BOOST_INTERPROCESS_POSIX_SEM_FAILED; } |
|
|
|
sem_t *mp_sem; |
|
}; |
|
|
|
class semaphore_wrapper |
|
{ |
|
semaphore_wrapper(); |
|
semaphore_wrapper(const semaphore_wrapper&); |
|
semaphore_wrapper &operator= (const semaphore_wrapper &); |
|
|
|
public: |
|
semaphore_wrapper(unsigned int initialCount) |
|
{ semaphore_init(&m_sem, initialCount); } |
|
|
|
~semaphore_wrapper() |
|
{ semaphore_destroy(&m_sem); } |
|
|
|
void post() |
|
{ semaphore_post(&m_sem); } |
|
|
|
void wait() |
|
{ semaphore_wait(&m_sem); } |
|
|
|
bool try_wait() |
|
{ return semaphore_try_wait(&m_sem); } |
|
|
|
bool timed_wait(const boost::posix_time::ptime &abs_time) |
|
{ return semaphore_timed_wait(&m_sem, abs_time); } |
|
|
|
private: |
|
sem_t m_sem; |
|
}; |
|
|
|
} //namespace ipcdetail { |
|
} //namespace interprocess { |
|
} //namespace boost { |
|
|
|
#undef BOOST_INTERPROCESS_POSIX_SEM_FAILED |
|
|
|
#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
|
|
|