fix incorrect implementation of revertible_mutex

This commit is contained in:
Jinhao 2017-03-31 03:23:18 +08:00
parent 3fd5f77e09
commit 8182d93b9a

View File

@ -277,23 +277,31 @@ namespace detail
//class revertible_mutex //class revertible_mutex
struct thread_refcount struct thread_refcount
{ {
unsigned tid; unsigned tid; //Thread ID
std::size_t ref; std::vector<unsigned> callstack_refs;
thread_refcount(unsigned thread_id, unsigned refs)
: tid(thread_id)
{
callstack_refs.push_back(refs);
}
}; };
struct window_manager::revertible_mutex::implementation struct window_manager::revertible_mutex::implementation
{ {
std::recursive_mutex mutex; std::recursive_mutex mutex;
thread_refcount thread; unsigned thread_id; //Thread ID
unsigned refs; //Ref count
std::vector<thread_refcount> records; std::vector<thread_refcount> records;
}; };
window_manager::revertible_mutex::revertible_mutex() window_manager::revertible_mutex::revertible_mutex()
: impl_(new implementation) : impl_(new implementation)
{ {
impl_->thread.tid = 0; impl_->thread_id = 0;
impl_->thread.ref = 0; impl_->refs = 0;
} }
window_manager::revertible_mutex::~revertible_mutex() window_manager::revertible_mutex::~revertible_mutex()
@ -305,20 +313,20 @@ namespace detail
{ {
impl_->mutex.lock(); impl_->mutex.lock();
if(0 == impl_->thread.tid) if (0 == impl_->thread_id)
impl_->thread.tid = nana::system::this_thread_id(); impl_->thread_id = nana::system::this_thread_id();
++(impl_->thread.ref); ++(impl_->refs);
} }
bool window_manager::revertible_mutex::try_lock() bool window_manager::revertible_mutex::try_lock()
{ {
if (impl_->mutex.try_lock()) if (impl_->mutex.try_lock())
{ {
if (0 == impl_->thread.tid) if (0 == impl_->thread_id)
impl_->thread.tid = nana::system::this_thread_id(); impl_->thread_id = nana::system::this_thread_id();
++(impl_->thread.ref); ++(impl_->refs);
return true; return true;
} }
return false; return false;
@ -326,24 +334,40 @@ namespace detail
void window_manager::revertible_mutex::unlock() void window_manager::revertible_mutex::unlock()
{ {
if(impl_->thread.tid == nana::system::this_thread_id()) if (impl_->thread_id == nana::system::this_thread_id())
if(0 == --(impl_->thread.ref)) if (0 == --(impl_->refs))
impl_->thread.tid = 0; impl_->thread_id = 0;
impl_->mutex.unlock(); impl_->mutex.unlock();
} }
void window_manager::revertible_mutex::revert() void window_manager::revertible_mutex::revert()
{ {
if(impl_->thread.tid == nana::system::this_thread_id()) if (impl_->thread_id == nana::system::this_thread_id())
{ {
std::size_t cnt = impl_->thread.ref; auto const current_refs = impl_->refs;
impl_->records.push_back(impl_->thread); //Check if there is a record
impl_->thread.tid = 0; for (auto & r : impl_->records)
impl_->thread.ref = 0; {
if (r.tid == impl_->thread_id)
{
r.callstack_refs.push_back(current_refs);
impl_->thread_id = 0; //Indicates a record is existing
break;
}
}
for (std::size_t i = 0; i < cnt; ++i) if (impl_->thread_id)
{
//Creates a new record
impl_->records.emplace_back(impl_->thread_id, current_refs);
impl_->thread_id = 0;
}
impl_->refs = 0;
for (std::size_t i = 0; i < current_refs; ++i)
impl_->mutex.unlock(); impl_->mutex.unlock();
} }
else else
@ -363,10 +387,17 @@ namespace detail
if (this_tid != i->tid) if (this_tid != i->tid)
continue; continue;
for (std::size_t u = 1; u < i->ref; ++u) auto const refs = i->callstack_refs.back();
for (std::size_t u = 1; u < refs; ++u)
impl_->mutex.lock(); impl_->mutex.lock();
impl_->thread = *i; impl_->thread_id = this_tid;
impl_->refs = refs;
if (i->callstack_refs.size() > 1)
i->callstack_refs.pop_back();
else
impl_->records.erase(i); impl_->records.erase(i);
return; return;
} }