| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (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 |