inline void robust_spin_mutex<Mutex>::unlock() { //If in "fixing" state, unlock and mark the mutex as unrecoverable //so next locks will fail and all threads will be notified that the //data protected by the mutex was not recoverable. if(atomic_read32(&this->state) == fixing_state){ atomic_write32(&this->state, broken_state); } //Write an invalid owner to minimize pid reuse possibility atomic_write32(&this->owner, get_invalid_process_id()); mtx.unlock(); }
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 robust_spin_mutex<Mutex>::robust_check() { //If the old owner was dead, and we've acquired ownership, mark //the mutex as 'fixing'. This means that a "consistent()" is needed //to avoid marking the mutex as "broken" when the mutex is unlocked. if(!this->check_if_owner_dead_and_take_ownership_atomically()){ return false; } atomic_write32(&this->state, fixing_state); return true; }
inline void robust_spin_mutex<Mutex>::lock() { //If the mutex is broken (recovery didn't call consistent()), //then throw an exception if(atomic_read32(&this->state) == broken_state){ throw interprocess_exception(lock_error, "Broken id"); } //This function provokes intermodule_singleton instantiation if(!this->lock_own_unique_file()){ throw interprocess_exception(lock_error, "Broken id"); } //Now the logic. Try to lock, if successful mark the owner //if it fails, start recovery logic unsigned int spin_count = 0; while(1){ if (mtx.try_lock()){ atomic_write32(&this->owner, get_current_process_id()); break; } else{ //Do the dead owner checking each spin_threshold lock tries ipcdetail::thread_yield(); ++spin_count; if(spin_count > spin_threshold){ //Check if owner dead and take ownership if possible if(!this->robust_check()){ spin_count = 0; } else{ break; } } } } }
inline bool robust_spin_mutex<Mutex>::try_lock() { //Same as lock() but without spinning if(atomic_read32(&this->state) == broken_state){ throw interprocess_exception(lock_error, "Broken id"); } if(!this->lock_own_unique_file()){ throw interprocess_exception(lock_error, "Broken id"); } if (mtx.try_lock()){ atomic_write32(&this->owner, get_current_process_id()); return true; } else{ if(!this->robust_check()){ return false; } else{ return true; } } }
void atomicSetValue32(DWORD &value, DWORD newValue) { atomic_write32((boost::uint32_t *)&value, newValue); }
void unlock() { atomic_write32(&lock_var, 0); }