////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2005-2012. 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 #ifndef BOOST_CONFIG_HPP # include #endif # #if defined(BOOST_HAS_PRAGMA_ONCE) # pragma once #endif #include #include #include #include #include #include #include //O_CREAT, O_*... #include //close #include //std::string #include //sem_* family, SEM_VALUE_MAX #include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, #include #ifdef SEM_FAILED #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(SEM_FAILED)) #else #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(-1)) #endif #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS #include #else #include #include #include #endif namespace boost { namespace interprocess { namespace ipcdetail { #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES 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_shared_dir_cleaning_old_and_get_filepath(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 shared_filepath(semname, sem_str); #endif return 0 == sem_unlink(sem_str.c_str()); } catch(...){ return false; } } #endif //BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES #ifdef BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES 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){ error_info err = system_error_code(); throw interprocess_exception(err); } } inline void semaphore_destroy(sem_t *handle) { int ret = sem_destroy(handle); if(ret != 0){ BOOST_ASSERT(0); } } #endif //BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES inline void semaphore_post(sem_t *handle) { int ret = sem_post(handle); if(ret != 0){ error_info err = system_error_code(); throw interprocess_exception(err); } } inline void semaphore_wait(sem_t *handle) { int ret = sem_wait(handle); if(ret != 0){ error_info err = system_error_code(); throw interprocess_exception(err); } } 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; } error_info err = system_error_code(); throw interprocess_exception(err); } #ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS struct semaphore_wrapper_try_wrapper { explicit semaphore_wrapper_try_wrapper(sem_t *handle) : m_handle(handle) {} void wait() { semaphore_wait(m_handle); } bool try_wait() { return semaphore_try_wait(m_handle); } private: sem_t *m_handle; }; #endif inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time) { #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS //Posix does not support infinity absolute time so handle it here if(abs_time == boost::posix_time::pos_infin){ semaphore_wait(handle); return true; } 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; } error_info err = system_error_code(); throw interprocess_exception(err); } return false; #else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS semaphore_wrapper_try_wrapper swtw(handle); ipcdetail::lock_to_wait lw(swtw); return ipcdetail::try_based_timed_lock(lw, abs_time); #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS } } //namespace ipcdetail { } //namespace interprocess { } //namespace boost { #endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP