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
struct thread_refcount
{
unsigned tid;
std::size_t ref;
unsigned tid; //Thread ID
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
{
std::recursive_mutex mutex;
thread_refcount thread;
unsigned thread_id; //Thread ID
unsigned refs; //Ref count
std::vector<thread_refcount> records;
};
window_manager::revertible_mutex::revertible_mutex()
: impl_(new implementation)
{
impl_->thread.tid = 0;
impl_->thread.ref = 0;
impl_->thread_id = 0;
impl_->refs = 0;
}
window_manager::revertible_mutex::~revertible_mutex()
@ -305,20 +313,20 @@ namespace detail
{
impl_->mutex.lock();
if(0 == impl_->thread.tid)
impl_->thread.tid = nana::system::this_thread_id();
if (0 == impl_->thread_id)
impl_->thread_id = nana::system::this_thread_id();
++(impl_->thread.ref);
++(impl_->refs);
}
bool window_manager::revertible_mutex::try_lock()
{
if (impl_->mutex.try_lock())
{
if (0 == impl_->thread.tid)
impl_->thread.tid = nana::system::this_thread_id();
if (0 == impl_->thread_id)
impl_->thread_id = nana::system::this_thread_id();
++(impl_->thread.ref);
++(impl_->refs);
return true;
}
return false;
@ -326,24 +334,40 @@ namespace detail
void window_manager::revertible_mutex::unlock()
{
if(impl_->thread.tid == nana::system::this_thread_id())
if(0 == --(impl_->thread.ref))
impl_->thread.tid = 0;
if (impl_->thread_id == nana::system::this_thread_id())
if (0 == --(impl_->refs))
impl_->thread_id = 0;
impl_->mutex.unlock();
}
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);
impl_->thread.tid = 0;
impl_->thread.ref = 0;
//Check if there is a record
for (auto & r : impl_->records)
{
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();
}
else
@ -363,10 +387,17 @@ namespace detail
if (this_tid != i->tid)
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_->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);
return;
}