11#include < nan.h>
22#include < git2.h>
3- #include < uv.h>
43#include < set>
54#include < vector>
65#include < map>
76#include < algorithm>
7+ #include < mutex>
8+ #include < iostream>
9+ #include < memory>
810
911#include " ../include/lock_master.h"
1012
1113// information about a lockable object
1214// - the mutex used to lock it and the number of outstanding locks
1315struct ObjectInfo {
14- uv_mutex_t * mutex;
16+ std::shared_ptr<std::mutex> mutex;
1517 unsigned useCount;
1618
17- ObjectInfo (uv_mutex_t *mutex, unsigned useCount)
18- : mutex(mutex), useCount(useCount)
19+ ObjectInfo (unsigned useCount)
20+ : mutex(new std:: mutex), useCount(useCount)
1921 {}
2022};
2123
@@ -27,17 +29,15 @@ class LockMasterImpl {
2729 // A map from objects that are locked (or were locked), to information on their mutex
2830 static std::map<const void *, ObjectInfo> mutexes;
2931 // A mutex used for the mutexes map
30- static uv_mutex_t mapMutex;
32+ static std::mutex mapMutex;
3133
32- // A libuv key used to store the current thread-specific LockMasterImpl instance
33- static uv_key_t currentLockMasterKey ;
34+ // A thread local storage slot for the current thread-specific LockMasterImpl instance
35+ thread_local static LockMasterImpl* currentLockMaster ;
3436
3537 // Cleans up any mutexes that are not currently used
3638 static NAN_GC_CALLBACK (CleanupMutexes);
3739
3840public:
39- static void InitializeGlobal ();
40-
4141 static void InitializeContext ();
4242
4343 // INSTANCE variables / methods
@@ -47,13 +47,13 @@ class LockMasterImpl {
4747 std::set<const void *> objectsToLock;
4848
4949 // Mutexes locked by this LockMaster on construction and unlocked on destruction
50- std::vector<uv_mutex_t * > GetMutexes (int useCountDelta);
50+ std::vector<std::shared_ptr<std::mutex> > GetMutexes (int useCountDelta);
5151 void Register ();
5252 void Unregister ();
5353
5454public:
5555 static LockMasterImpl *CurrentLockMasterImpl () {
56- return (LockMasterImpl *)uv_key_get (¤tLockMasterKey) ;
56+ return (LockMasterImpl *)currentLockMaster ;
5757 }
5858
5959 LockMasterImpl () {
@@ -74,128 +74,117 @@ class LockMasterImpl {
7474};
7575
7676std::map<const void *, ObjectInfo> LockMasterImpl::mutexes;
77- uv_mutex_t LockMasterImpl::mapMutex;
78- uv_key_t LockMasterImpl::currentLockMasterKey;
79-
80- void LockMasterImpl::InitializeGlobal () {
81- uv_mutex_init (&mapMutex);
82- uv_key_create (¤tLockMasterKey);
83- }
77+ std::mutex LockMasterImpl::mapMutex;
78+ thread_local LockMasterImpl* LockMasterImpl::currentLockMaster = NULL ;
8479
8580void LockMasterImpl::InitializeContext () {
8681 Nan::AddGCEpilogueCallback (CleanupMutexes);
8782}
8883
8984NAN_GC_CALLBACK (LockMasterImpl::CleanupMutexes) {
90- uv_mutex_lock (& mapMutex);
85+ std::lock_guard<std::mutex> lock ( mapMutex);
9186
9287 for (auto it = mutexes.begin (); it != mutexes.end (); )
9388 {
94- uv_mutex_t *mutex = it->second .mutex ;
95- unsigned useCount = it->second .useCount ;
9689 // if the mutex is not used by any LockMasters,
9790 // we can destroy it
91+ unsigned useCount = it->second .useCount ;
9892 if (!useCount) {
99- uv_mutex_destroy (mutex);
100- free (mutex);
10193 auto to_erase = it;
10294 it++;
10395 mutexes.erase (to_erase);
10496 } else {
10597 it++;
10698 }
10799 }
108-
109- uv_mutex_unlock (&mapMutex);
110- }
111-
112- void LockMaster::InitializeGlobal () {
113- LockMasterImpl::InitializeGlobal ();
114100}
115101
116102void LockMaster::InitializeContext () {
117103 LockMasterImpl::InitializeContext ();
118104}
119105
120- std::vector<uv_mutex_t *> LockMasterImpl::GetMutexes (int useCountDelta) {
121- std::vector<uv_mutex_t *> objectMutexes;
122-
123- uv_mutex_lock (&mapMutex);
106+ std::vector<std::shared_ptr<std::mutex>> LockMasterImpl::GetMutexes (int useCountDelta) {
107+ std::vector<std::shared_ptr<std::mutex>> objectMutexes;
108+ std::lock_guard<std::mutex> lock (mapMutex);
124109
125110 for (auto object : objectsToLock) {
126- if (object) {
111+ if (object) {
127112 // ensure we have an initialized mutex for each object
128113 auto mutexIt = mutexes.find (object);
129- if (mutexIt == mutexes.end ()) {
114+ if (mutexIt == mutexes.end ()) {
130115 mutexIt = mutexes.insert (
131116 std::make_pair (
132117 object,
133- ObjectInfo (( uv_mutex_t *) malloc ( sizeof ( uv_mutex_t )), 0U )
118+ ObjectInfo (0U )
134119 )
135120 ).first ;
136- uv_mutex_init (mutexIt->second .mutex );
137121 }
138122
139123 objectMutexes.push_back (mutexIt->second .mutex );
140124 mutexIt->second .useCount += useCountDelta;
141125 }
142126 }
143127
144- uv_mutex_unlock (&mapMutex);
145-
146128 return objectMutexes;
147129}
148130
149131void LockMasterImpl::Register () {
150- uv_key_set (¤tLockMasterKey, this ) ;
132+ currentLockMaster = this ;
151133}
152134
153135void LockMasterImpl::Unregister () {
154- uv_key_set (¤tLockMasterKey, NULL ) ;
136+ currentLockMaster = NULL ;
155137}
156138
157139void LockMasterImpl::Lock (bool acquireMutexes) {
158- std::vector<uv_mutex_t * > objectMutexes = GetMutexes (acquireMutexes * 1 );
140+ std::vector<std::shared_ptr<std::mutex> > objectMutexes = GetMutexes (acquireMutexes * 1 );
159141
160142 auto alreadyLocked = objectMutexes.end ();
143+ std::vector<std::shared_ptr<std::mutex>>::iterator it;
161144
162145 // we will attempt to lock all the mutexes at the same time to avoid deadlocks
163146 // note in most cases we are locking 0 or 1 mutexes. more than 1 implies
164147 // passing objects with different repos/owners in the same call.
165- std::vector<uv_mutex_t *>::iterator it;
166148 do {
167149 // go through all the mutexes and try to lock them
168- for (it = objectMutexes.begin (); it != objectMutexes.end (); it++) {
169- // if we already locked this mutex in a previous pass via uv_mutex_lock ,
150+ for (it = objectMutexes.begin (); it != objectMutexes.end (); it++) {
151+ // if we already locked this mutex in a previous pass via std::mutex::lock ,
170152 // we don't need to lock it again
171153 if (it == alreadyLocked) {
172154 continue ;
173155 }
156+
174157 // first, try to lock (non-blocking)
175- bool failure = uv_mutex_trylock (*it);
176- if (failure ) {
158+ bool success = (*it)-> try_lock ( );
159+ if (!success ) {
177160 // we have failed to lock a mutex... unlock everything we have locked
178- std::for_each (objectMutexes.begin (), it, uv_mutex_unlock);
161+ std::for_each (objectMutexes.begin (), it, [](std::shared_ptr<std::mutex> mutex) {
162+ mutex->unlock ();
163+ });
164+
179165 if (alreadyLocked > it && alreadyLocked != objectMutexes.end ()) {
180- uv_mutex_unlock (*alreadyLocked);
166+ (*alreadyLocked)-> unlock ( );
181167 }
168+
182169 // now do a blocking lock on what we couldn't lock
183- uv_mutex_lock (*it);
170+ (*it)-> lock ( );
184171 // mark that we have already locked this one
185172 // if there are more mutexes than this one, we will go back to locking everything
186173 alreadyLocked = it;
187174 break ;
188175 }
189176 }
190- } while (it != objectMutexes.end ());
177+ } while (it != objectMutexes.end ());
191178}
192179
193180void LockMasterImpl::Unlock (bool releaseMutexes) {
194181 // Get the mutexes but don't decrement their use count until after we've
195182 // unlocked them all.
196- std::vector<uv_mutex_t * > objectMutexes = GetMutexes (0 );
183+ std::vector<std::shared_ptr<std::mutex> > objectMutexes = GetMutexes (0 );
197184
198- std::for_each (objectMutexes.begin (), objectMutexes.end (), uv_mutex_unlock);
185+ std::for_each (objectMutexes.begin (), objectMutexes.end (), [](std::shared_ptr<std::mutex> mutex) {
186+ mutex->unlock ();
187+ });
199188
200189 GetMutexes (releaseMutexes * -1 );
201190}
@@ -222,7 +211,7 @@ void LockMaster::ObjectsToLockAdded() {
222211
223212void LockMaster::TemporaryUnlock::ConstructorImpl () {
224213 impl = LockMasterImpl::CurrentLockMasterImpl ();
225- if (impl) {
214+ if (impl) {
226215 impl->Unlock (false );
227216 }
228217}
0 commit comments