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 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_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 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; }
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 semaphore_wait(sem_t *handle) { int ret = sem_wait(handle); if(ret != 0){ throw interprocess_exception(system_error_code()); } }
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 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 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 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_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 bool semaphore_try_wait(sem_t *handle) { while (1) { int res = sem_trywait(handle); if (res == 0) return true; if (system_error_code() != EINTR) return false; } }
inline void semaphore_wait(sem_t *handle) { while (1) { int res = sem_wait(handle); if (res == 0) return; if (system_error_code() != EINTR) return; } }
inline bool open_or_create_directory(const char *dir_name) { //If fails, check that it's because it already exists if(!create_directory(dir_name)){ error_info info(system_error_code()); if(info.get_error_code() != already_exists_error){ return false; } } return true; }
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; }
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); } }
inline bool winapi_wrapper_try_wait_for_single_object(void *handle) { unsigned long ret = winapi::wait_for_single_object(handle, 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); } }
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); } } }
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 create_tmp_dir_and_get_filename(const char *filename, std::string &tmp_name) { //First get the temp directory get_tmp_base_dir(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); } } #ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME //Create a new subdirectory with the bootstamp std::string root_tmp_name = tmp_name; tmp_name += '/'; //Obtain bootstamp string std::string bootstamp; get_bootstamp(bootstamp); tmp_name += bootstamp; //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 delete_subdirectories(root_tmp_name, bootstamp.c_str()); #endif //Add filename tmp_name += '/'; tmp_name += filename; }
inline void create_shared_dir_and_clean_old(std::string &shared_dir) { #if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) || defined(BOOST_INTERPROCESS_SHARED_DIR_FUNC) get_shared_dir(shared_dir); #else //First get the temp directory std::string root_shared_dir; get_shared_dir_root(root_shared_dir); //If fails, check that it's because already exists if(!create_directory(root_shared_dir.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) get_shared_dir(shared_dir); //If fails, check that it's because already exists if(!create_directory(shared_dir.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 = shared_dir; subdir.erase(0, root_shared_dir.size()+1); delete_subdirectories(root_shared_dir, subdir.c_str()); #else shared_dir = root_shared_dir; #endif #endif }
inline void create_tmp_dir_and_get_filename(const char *filename, std::string &tmp_name) { const char *tmp_path = get_temporary_path(); if(!tmp_path){ error_info err = system_error_code(); throw interprocess_exception(err); } tmp_name = tmp_path; tmp_name += "/boost_interprocess"; //Create the temporary directory. //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); } } //Add filename tmp_name += '/'; tmp_name += filename; }
//!Creates a new XSI shared memory with a key obtained from a call to ftok (with path //!"path" and id "id"), of size "size" and permissions "perm". //!If the shared memory previously exists, throws an error. xsi_key(const char *path, boost::uint8_t id) { key_t key; if(path){ key = ::ftok(path, id); if(((key_t)-1) == key){ error_info err = system_error_code(); throw interprocess_exception(err); } } else{ key = IPC_PRIVATE; } m_key = key; }
bool timed_lock(const boost::posix_time::ptime &abs_time) { if(abs_time == boost::posix_time::pos_infin){ this->lock(); return true; } unsigned long ret = winapi::wait_for_single_object (m_mtx_hnd, (abs_time - microsec_clock::universal_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 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; }
inline bool robust_spin_mutex<Mutex>::is_owner_dead(boost::uint32_t own) { //If owner is an invalid id, then it's clear it's dead if(own == (boost::uint32_t)get_invalid_process_id()){ return true; } //Obtain the lock filename of the owner field std::string file; this->owner_to_filename(own, file); //Now the logic is to open and lock it file_handle_t fhnd = open_existing_file(file.c_str(), read_write); if(fhnd != invalid_file()){ //If we can open the file, lock it. bool acquired; if(try_acquire_file_lock(fhnd, acquired) && acquired){ //If locked, just delete the file delete_file(file.c_str()); close_file(fhnd); return true; } //If not locked, the owner is suppossed to be still alive close_file(fhnd); } else{ //If the lock file does not exist then the owner is dead (a previous cleanup) //function has deleted the file. If there is another reason, then this is //an unrecoverable error if(error_info(system_error_code()).get_error_code() == not_found_error){ return true; } } return false; }
inline void windows_named_sync::open_or_create ( create_enum_t creation_type , const char *name , const permissions &perm , windows_named_sync_interface &sync_interface) { std::string aux_str(name); m_file_hnd = winapi::invalid_handle_value; //Use a file to emulate POSIX lifetime semantics. After this logic //we'll obtain the ID of the native handle to open in aux_str { create_shared_dir_cleaning_old_and_get_filepath(name, aux_str); //Create a file with required permissions. m_file_hnd = winapi::create_file ( aux_str.c_str() , winapi::generic_read | winapi::generic_write , creation_type == DoOpen ? winapi::open_existing : (creation_type == DoCreate ? winapi::create_new : winapi::open_always) , 0 , (winapi::interprocess_security_attributes*)perm.get_permissions()); //Obtain OS error in case something has failed error_info err; bool success = false; if(m_file_hnd != winapi::invalid_handle_value){ //Now lock the file const std::size_t buflen = sync_interface.get_data_size(); typedef __int64 unique_id_type; const std::size_t sizeof_file_info = sizeof(unique_id_type) + buflen; winapi::interprocess_overlapped overlapped; if(winapi::lock_file_ex (m_file_hnd, winapi::lockfile_exclusive_lock, 0, sizeof_file_info, 0, &overlapped)){ __int64 filesize = 0; //Obtain the unique id to open the native semaphore. //If file size was created if(winapi::get_file_size(m_file_hnd, filesize)){ unsigned long written_or_read = 0; unique_id_type unique_id_val; if(static_cast<std::size_t>(filesize) != sizeof_file_info){ winapi::set_end_of_file(m_file_hnd); winapi::query_performance_counter(&unique_id_val); const void *buf = sync_interface.buffer_with_init_data_to_file(); //Write unique ID in file. This ID will be used to calculate the semaphore name if(winapi::write_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) && written_or_read == sizeof(unique_id_val) && winapi::write_file(m_file_hnd, buf, buflen, &written_or_read, 0) && written_or_read == buflen ){ success = true; } winapi::get_file_size(m_file_hnd, filesize); BOOST_ASSERT(std::size_t(filesize) == sizeof_file_info); } else{ void *buf = sync_interface.buffer_to_store_init_data_from_file(); if(winapi::read_file(m_file_hnd, &unique_id_val, sizeof(unique_id_val), &written_or_read, 0) && written_or_read == sizeof(unique_id_val) && winapi::read_file(m_file_hnd, buf, buflen, &written_or_read, 0) && written_or_read == buflen ){ success = true; } } if(success){ //Now create a global semaphore name based on the unique id char unique_id_name[sizeof(unique_id_val)*2+1]; std::size_t name_suffix_length = sizeof(unique_id_name); bytes_to_str(&unique_id_val, sizeof(unique_id_val), &unique_id_name[0], name_suffix_length); success = sync_interface.open(creation_type, unique_id_name); } } //Obtain OS error in case something has failed err = system_error_code(); //If this fails we have no possible rollback so don't check the return if(!winapi::unlock_file_ex(m_file_hnd, 0, sizeof_file_info, 0, &overlapped)){ err = system_error_code(); } } else{ //Obtain OS error in case something has failed err = system_error_code(); } } else{ err = system_error_code(); } if(!success){ if(m_file_hnd != winapi::invalid_handle_value){ winapi::close_handle(m_file_hnd); m_file_hnd = winapi::invalid_handle_value; } //Throw as something went wrong throw interprocess_exception(err); } } }