From 99475b2a0b2ef287708364a34d6d56fd5952fd56 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sun, 23 Mar 2014 10:28:33 +0200 Subject: [PATCH] Lock/Unlock multiple locks at once function / class --- include/library/threads.hpp | 31 +++++++++++++++++++++++ src/library/fileimage.cpp | 10 +------- src/library/filesystem.cpp | 17 +------------ src/library/threads.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 25 deletions(-) create mode 100644 src/library/threads.cpp diff --git a/include/library/threads.hpp b/include/library/threads.hpp index dd81db18..d8a34436 100644 --- a/include/library/threads.hpp +++ b/include/library/threads.hpp @@ -2,6 +2,7 @@ #define _library_threads__hpp__included__ #include +#include #ifdef NATIVE_THREADS #include @@ -45,6 +46,36 @@ inline id this_id() return boost::this_thread::get_id(); } #endif + +/** + * Lock multiple locks. + * + * The locks are always locked in address order. Duplicate locks are only locked once. + */ +void lock_multiple(std::initializer_list locks); +/** + * Unlock multiple locks. + * + * Duplicate locks are only unlocked once. + */ +void unlock_multiple(std::initializer_list locks); +void unlock_multiple(std::vector locks); + +class alock_multiple +{ +public: + alock_multiple(std::initializer_list locks) + { + _locks = std::vector(locks); + lock_multiple(locks); + } + ~alock_multiple() + { + unlock_multiple(_locks); + } +private: + std::vector _locks; +}; } #endif diff --git a/src/library/fileimage.cpp b/src/library/fileimage.cpp index bdb5721a..f189accf 100644 --- a/src/library/fileimage.cpp +++ b/src/library/fileimage.cpp @@ -182,13 +182,7 @@ hashval& hashval::operator=(const hashval& f) if(this == &f) return *this; threads::alock h2(global_queue_mutex()); - if((size_t)this < (size_t)&f) { - mlock.lock(); - f.mlock.lock(); - } else { - f.mlock.lock(); - mlock.lock(); - } + threads::alock_multiple({&mlock, &f.mlock}); if(!is_ready && hasher) hasher->unlink(*this); @@ -201,8 +195,6 @@ hashval& hashval::operator=(const hashval& f) hasher = f.hasher; if(!is_ready && hasher) hasher->link(*this); - mlock.unlock(); - f.mlock.unlock(); } void hashval::resolve(unsigned id, const std::string& hash, uint64_t _prefix) diff --git a/src/library/filesystem.cpp b/src/library/filesystem.cpp index b3928155..e0d9cca9 100644 --- a/src/library/filesystem.cpp +++ b/src/library/filesystem.cpp @@ -299,24 +299,9 @@ filesystem::ref& filesystem::ref::operator=(const filesystem::ref& r) refcnt = r.refcnt; mlock = r.mlock; fs = r.fs; - } else if(A < B) { - //Two-object case. - threads::alock m1(*mlock); - threads::alock m2(*r.mlock); - --*refcnt; - if(!*refcnt) { - delete fs; - delete refcnt; - mtodelete = mlock; - } - ++*(r.refcnt); - refcnt = r.refcnt; - mlock = r.mlock; - fs = r.fs; } else { //Two-object case. - threads::alock m1(*r.mlock); - threads::alock m2(*mlock); + threads::alock_multiple ms({r.mlock, mlock}); --*refcnt; if(!*refcnt) { delete fs; diff --git a/src/library/threads.cpp b/src/library/threads.cpp new file mode 100644 index 00000000..fdec1fd3 --- /dev/null +++ b/src/library/threads.cpp @@ -0,0 +1,61 @@ +#include "threads.hpp" +#include + +namespace threads +{ +void lock_multiple(std::initializer_list locks) +{ + uintptr_t next = 0; + while(true) { + uintptr_t minaddr = 0; + lock* minlock = NULL; + for(auto i : locks) { + uintptr_t addr = reinterpret_cast(i); + if(addr < minaddr && addr > next) { + minaddr = addr; + minlock = i; + } + } + //If no more locks, exit. + if(!minlock) return; + //Lock minlock. + try { + minlock->lock(); + next = minaddr; + } catch(...) { + //Unlock all locks we got. + for(auto i : locks) { + uintptr_t addr = reinterpret_cast(i); + if(addr < next) + i->unlock(); + } + throw; + } + } +} + +template void _unlock_multiple(T locks) +{ + uintptr_t next = 0; + while(true) { + uintptr_t minaddr = 0; + lock* minlock = NULL; + for(auto i : locks) { + uintptr_t addr = reinterpret_cast(i); + if(addr < minaddr && addr > next) { + minaddr = addr; + minlock = i; + } + } + //If no more locks, exit. + if(!minlock) return; + //Unlock minlock. + minlock->unlock(); + next = minaddr; + } +} + +void unlock_multiple(std::initializer_list locks) { _unlock_multiple(locks); } +void unlock_multiple(std::vector locks) { _unlock_multiple(locks); } + +} -- 2.11.4.GIT