Skip to content

Commit 651b315

Browse files
committed
Get rid of libuv in lock_master
1 parent ed068ad commit 651b315

File tree

2 files changed

+43
-56
lines changed

2 files changed

+43
-56
lines changed

generate/templates/manual/src/lock_master.cc

Lines changed: 43 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
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
1315
struct 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

3840
public:
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

5454
public:
5555
static LockMasterImpl *CurrentLockMasterImpl() {
56-
return (LockMasterImpl *)uv_key_get(&currentLockMasterKey);
56+
return (LockMasterImpl *)currentLockMaster;
5757
}
5858

5959
LockMasterImpl() {
@@ -74,128 +74,117 @@ class LockMasterImpl {
7474
};
7575

7676
std::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(&currentLockMasterKey);
83-
}
77+
std::mutex LockMasterImpl::mapMutex;
78+
thread_local LockMasterImpl* LockMasterImpl::currentLockMaster = NULL;
8479

8580
void LockMasterImpl::InitializeContext() {
8681
Nan::AddGCEpilogueCallback(CleanupMutexes);
8782
}
8883

8984
NAN_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

116102
void 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

149131
void LockMasterImpl::Register() {
150-
uv_key_set(&currentLockMasterKey, this);
132+
currentLockMaster = this;
151133
}
152134

153135
void LockMasterImpl::Unregister() {
154-
uv_key_set(&currentLockMasterKey, NULL);
136+
currentLockMaster = NULL;
155137
}
156138

157139
void 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

193180
void 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

223212
void LockMaster::TemporaryUnlock::ConstructorImpl() {
224213
impl = LockMasterImpl::CurrentLockMasterImpl();
225-
if(impl) {
214+
if (impl) {
226215
impl->Unlock(false);
227216
}
228217
}

generate/templates/templates/nodegit.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ NAN_MODULE_INIT(init) {
8484
init_ssh2();
8585
// Initialize libgit2.
8686
git_libgit2_init();
87-
88-
LockMaster::InitializeGlobal();
8987
});
9088
}
9189

0 commit comments

Comments
 (0)