boost/interprocess/sync/posix/semaphore_wrapper.hpp
//////////////////////////////////////////////////////////////////////////////
//
// (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 detail{ class interprocess_tester; }
/// @endcond
namespace detail {
inline bool semaphore_open
(sem_t *&handle, detail::create_enum_t type, const char *origname,
unsigned int count, const permissions &perm = permissions())
{
std::string name;
#ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
detail::add_leading_slash(origname, name);
#else
detail::create_tmp_and_clean_old_and_get_filename(origname, name);
#endif
//Create new mapping
int oflag = 0;
switch(type){
case detail::DoOpen:
//No addition
break;
case detail::DoCreate:
oflag |= (O_CREAT | O_EXCL);
break;
case detail::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
detail::add_leading_slash(semname, sem_str);
#else
detail::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 = detail::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
(detail::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 detail::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 detail {
} //namespace interprocess {
} //namespace boost {
#undef BOOST_INTERPROCESS_POSIX_SEM_FAILED
#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP