diff options
Diffstat (limited to 'boost/interprocess/sync/posix/semaphore_wrapper.hpp')
-rw-r--r-- | boost/interprocess/sync/posix/semaphore_wrapper.hpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/boost/interprocess/sync/posix/semaphore_wrapper.hpp new file mode 100644 index 0000000000..1aeef47662 --- /dev/null +++ b/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -0,0 +1,211 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2011. 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 <fcntl.h> //O_CREAT, O_*... +#include <unistd.h> //close +#include <string> //std::string +#include <semaphore.h> //sem_* family, SEM_VALUE_MAX +#include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#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 { +namespace ipcdetail { + +inline bool semaphore_open + (sem_t *&handle, create_enum_t type, const char *origname, + unsigned int count = 0, const permissions &perm = permissions()) +{ + std::string name; + #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + add_leading_slash(origname, name); + #else + create_tmp_and_clean_old_and_get_filename(origname, name); + #endif + + //Create new mapping + int oflag = 0; + switch(type){ + case DoOpen: + { + //No addition + handle = ::sem_open(name.c_str(), oflag); + } + break; + case DoOpenOrCreate: + case DoCreate: + { + while(1){ + oflag = (O_CREAT | O_EXCL); + handle = ::sem_open(name.c_str(), oflag, perm.get_permissions(), count); + if(handle != BOOST_INTERPROCESS_POSIX_SEM_FAILED){ + //We can't change semaphore permissions! + //::fchmod(handle, perm.get_permissions()); + break; + } + else if(errno == EEXIST && type == DoOpenOrCreate){ + oflag = 0; + if( (handle = ::sem_open(name.c_str(), oflag)) != BOOST_INTERPROCESS_POSIX_SEM_FAILED + || (errno != ENOENT) ){ + break; + } + } + else{ + break; + } + } + } + break; + default: + { + error_info err(other_error); + throw interprocess_exception(err); + } + } + + //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 + add_leading_slash(semname, sem_str); + #else + 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) +{ + if(abs_time == boost::posix_time::pos_infin){ + semaphore_wait(handle); + return true; + } + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + timespec tspec = 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; + do{ + if(semaphore_try_wait(handle)) + return true; + thread_yield(); + }while((now = microsec_clock::universal_time()) < abs_time); + return false; + #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP |