inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const boost::posix_time::ptime &abs_time) { const boost::posix_time::ptime cur_time = microsec_clock::universal_time(); //Windows uses relative wait times so check for negative waits //and implement as 0 wait to allow try-semantics as POSIX mandates. unsigned long time = 0u; if (abs_time == boost::posix_time::pos_infin){ time = winapi::infinite_time; } else if(abs_time > cur_time){ time = (abs_time - cur_time).total_milliseconds(); } unsigned long ret = winapi::wait_for_single_object(handle, time); if(ret == winapi::wait_object_0){ return true; } else if(ret == winapi::wait_timeout){ return false; } else if(ret == winapi::wait_abandoned){ //Special case for orphaned mutexes winapi::release_mutex(handle); throw interprocess_exception(owner_dead_error); } else{ error_info err = system_error_code(); throw interprocess_exception(err); } }
inline void create_tmp_and_clean_old(std::string &tmp_name) { //First get the temp directory std::string root_tmp_name; get_tmp_base_dir(root_tmp_name); //If fails, check that it's because already exists if(!create_directory(root_tmp_name.c_str())){ error_info info(system_error_code()); if(info.get_error_code() != already_exists_error){ throw interprocess_exception(info); } } #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) tmp_folder(tmp_name); //If fails, check that it's because already exists if(!create_directory(tmp_name.c_str())){ error_info info(system_error_code()); if(info.get_error_code() != already_exists_error){ throw interprocess_exception(info); } } //Now erase all old directories created in the previous boot sessions std::string subdir = tmp_name; subdir.erase(0, root_tmp_name.size()+1); delete_subdirectories(root_tmp_name, subdir.c_str()); #else tmp_name = root_tmp_name; #endif }
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 bool semaphore_open (sem_t *&handle, detail::create_enum_t type, const char *origname, mode_t mode, unsigned int count) { std::string name; #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES detail::add_leading_slash(origname, name); #else detail::create_tmp_dir_and_get_filename(origname, name); #endif //Create new mapping int oflag = 0; if(mode == read_only){ oflag |= O_RDONLY; } else if(mode == read_write){ oflag |= O_RDWR; } else{ error_info err(mode_error); throw interprocess_exception(err); } 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, S_IRWXO | S_IRWXG | S_IRWXU, 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; }
robust_mutex_lock_file() { permissions p; p.set_unrestricted(); //Remove old lock files of other processes remove_old_robust_lock_files(); //Create path and obtain lock file path for this process create_and_get_robust_lock_file_path(fname, get_current_process_id()); //Now try to open or create the lock file fd = create_or_open_file(fname.c_str(), read_write, p); //If we can't open or create it, then something unrecoverable has happened if(fd == invalid_file()){ throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file"); } //Now we must take in care a race condition with another process //calling "remove_old_robust_lock_files()". No other threads from this //process will be creating the lock file because intermodule_singleton //guarantees this. So let's loop acquiring the lock and checking if we //can't exclusively create the file (if the file is erased by another process //then this exclusive open would fail). If the file can't be exclusively created //then we have correctly open/create and lock the file. If the file can //be exclusively created, then close previous locked file and try again. while(1){ bool acquired; if(!try_acquire_file_lock(fd, acquired) || !acquired ){ throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock"); } //Creating exclusively must fail with already_exists_error //to make sure we've locked the file and no one has //deleted it between creation and locking file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p); if(fd2 != invalid_file()){ close_file(fd); fd = fd2; continue; } //If exclusive creation fails with expected error go ahead else if(error_info(system_error_code()).get_error_code() == already_exists_error){ //must already exist //Leak descriptor to mantain the file locked until the process dies break; } //If exclusive creation fails with unexpected error throw an unrecoverable error else{ close_file(fd); throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error"); } } }
inline void winapi_wrapper_wait_for_single_object(void *handle) { unsigned long ret = winapi::wait_for_single_object(handle, winapi::infinite_time); if(ret != winapi::wait_object_0){ if(ret != winapi::wait_abandoned){ error_info err = system_error_code(); throw interprocess_exception(err); } else{ //Special case for orphaned mutexes winapi::release_mutex(handle); throw interprocess_exception(owner_dead_error); } } }
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<semaphore_wrapper_try_wrapper> lw(swtw); return ipcdetail::try_based_timed_lock(lw, abs_time); #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS }
inline interprocess_semaphore::interprocess_semaphore(unsigned int initialCount) : m_mut(), m_cond(), m_count(initialCount) { if(m_count < 0){ throw interprocess_exception(size_error); } }
void lock() { if(winapi::wait_for_single_object(m_mtx_hnd, winapi::infinite_time) != winapi::wait_object_0){ error_info err = system_error_code(); throw interprocess_exception(err); } }
inline void file_wrapper::truncate(offset_t length) { if(!truncate_file(m_handle, length)){ error_info err(system_error_code()); throw interprocess_exception(err); } }
inline bool emulation_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) { typedef ipcdetail::OS_systemwide_thread_id_t handle_t; if(abs_time == boost::posix_time::pos_infin){ this->lock(); return true; } const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); handle_t old_id; ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception("boost::interprocess::emulation_recursive_mutex recursive lock overflow"); } ++m_nLockCount; return true; } if(m_mutex.timed_lock(abs_time)){ ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } return false; }
inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const geofeatures_boost::posix_time::ptime &abs_time) { //Windows does not support infinity abs_time so check it if(abs_time == geofeatures_boost::posix_time::pos_infin){ winapi_wrapper_wait_for_single_object(handle); return true; } const geofeatures_boost::posix_time::ptime cur_time = microsec_clock::universal_time(); //Windows uses relative wait times so check for negative waits //and implement as 0 wait to allow try-semantics as POSIX mandates. unsigned long ret = winapi::wait_for_single_object ( handle , (abs_time <= cur_time) ? 0u : (abs_time - cur_time).total_milliseconds() ); if(ret == winapi::wait_object_0){ return true; } else if(ret == winapi::wait_timeout){ return false; } else{ error_info err = system_error_code(); throw interprocess_exception(err); } }
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 }
inline void semaphore_wait(sem_t *handle) { int ret = sem_wait(handle); if(ret != 0){ throw interprocess_exception(system_error_code()); } }
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); } }
//!Constructor. Takes barrier attributes to initialize the barrier barrier_initializer(pthread_barrier_t &mut, pthread_barrierattr_t &mut_attr, int count) : mp_barrier(&mut) { if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0) throw interprocess_exception("pthread_barrier_init failed"); }
//!Creates heap memory and initializes the segment manager. //!This can throw. basic_managed_heap_memory(std::size_t size) : m_heapmem(size, char(0)) { if(!base_t::create_impl(&m_heapmem[0], size)){ this->priv_close(); throw interprocess_exception(); } }
//!Constructor mutexattr_wrapper(bool recursive = false) { if(pthread_mutexattr_init(&m_attr)!=0 || pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 || (recursive && pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 )) throw interprocess_exception("pthread_mutexattr_xxxx failed"); }
inline bool barrier::wait() { int res = pthread_barrier_wait(&m_barrier); if (res != PTHREAD_BARRIER_SERIAL_THREAD && res != 0) { throw interprocess_exception(res); } return res == PTHREAD_BARRIER_SERIAL_THREAD; }
//!Creates and places the segment manager. This can throw basic_managed_external_buffer (open_only_t, void *addr, std::size_t size) { //Check if alignment is correct assert((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - std::size_t(1u))))); if(!base_t::open_impl(addr, size)) { throw interprocess_exception(); } }
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 interprocess_condition::interprocess_condition() { int res; pthread_condattr_t cond_attr; res = pthread_condattr_init(&cond_attr); if(res != 0){ throw interprocess_exception("pthread_condattr_init failed"); } res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); if(res != 0){ pthread_condattr_destroy(&cond_attr); throw interprocess_exception(res); } res = pthread_cond_init(&m_condition, &cond_attr); pthread_condattr_destroy(&cond_attr); if(res != 0){ throw interprocess_exception(res); } }
inline void semaphore_init(sem_t *handle, 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 robust_spin_mutex<Mutex>::consistent() { //This function supposes the previous state was "fixing" //and the current process holds the mutex if(atomic_read32(&this->state) != fixing_state && atomic_read32(&this->owner) != (boost::uint32_t)get_current_process_id()){ throw interprocess_exception(lock_error, "Broken id"); } //If that's the case, just update mutex state atomic_write32(&this->state, correct_state); }
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 void windows_semaphore::wait(void) { sync_handles &handles = intermodule_singleton<sync_handles>::get(); //This can throw void *hnd = handles.obtain_semaphore(this->id_, 0); unsigned long ret = winapi::wait_for_single_object(hnd, winapi::infinite_time); if(ret == winapi::wait_failed){ error_info err(winapi::get_last_error()); throw interprocess_exception(err); } }
inline void interprocess_recursive_mutex::lock() { #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING boost::posix_time::ptime wait_time = boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS); if (!mutex.timed_lock(wait_time)){ throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?"); } #else mutex.lock(); #endif }
inline void tmp_filename(const char *filename, std::string &tmp_name) { const char *tmp_dir = get_temporary_path(); if(!tmp_dir){ error_info err = system_error_code(); throw interprocess_exception(err); } tmp_name = tmp_dir; //Remove final null. tmp_name += "/boost_interprocess/"; tmp_name += filename; }
inline bool file_wrapper::priv_open_or_create (detail::create_enum_t type, const char *filename, mode_t mode) { m_filename = filename; if(mode != read_only && mode != read_write){ error_info err(mode_error); throw interprocess_exception(err); } //Open file existing native API to obtain the handle switch(type){ case detail::DoOpen: m_handle = open_existing_file(filename, mode); break; case detail::DoCreate: m_handle = create_new_file(filename, mode); break; case detail::DoOpenOrCreate: m_handle = create_or_open_file(filename, mode); break; default: { error_info err = other_error; throw interprocess_exception(err); } } //Check for error if(m_handle == invalid_file()){ throw interprocess_exception(error_info(system_error_code())); } m_mode = mode; return true; }
bool try_lock() { unsigned long ret = winapi::wait_for_single_object(m_mtx_hnd, 0); if(ret == winapi::wait_object_0){ return true; } else if(ret == winapi::wait_timeout){ return false; } else{ error_info err = system_error_code(); throw interprocess_exception(err); } }