Skip to content

Commit 1f89352

Browse files
committed
Clean up mutexes
1 parent 38e597d commit 1f89352

2 files changed

Lines changed: 43 additions & 6 deletions

File tree

generate/templates/manual/include/nodegit.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
#include <set>
55
#include <vector>
66
#include <uv.h>
7+
#include <memory>
78

89
class LockMaster {
910

1011
std::set<const void *> objects_to_lock;
11-
std::vector<uv_mutex_t *> object_mutexes;
12+
std::vector<std::shared_ptr<uv_mutex_t> > object_mutexes;
1213

1314
template<typename T>
1415
void AddLocks(const T *t) {
@@ -36,6 +37,7 @@ class LockMaster {
3637
void Unregister();
3738
void Lock();
3839
void Unlock();
40+
void CleanupMutexes();
3941

4042
public:
4143

@@ -53,6 +55,7 @@ class LockMaster {
5355
{
5456
Unregister();
5557
Unlock();
58+
CleanupMutexes();
5659
}
5760

5861
class TemporaryUnlock

generate/templates/templates/nodegit.cc

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <map>
77
#include <algorithm>
88
#include <set>
9+
#include <memory>
910

1011
#include "../include/nodegit.h"
1112
#include "../include/wrapper.h"
@@ -16,9 +17,30 @@
1617
{% endif %}
1718
{% endeach %}
1819

19-
std::map<const void *, uv_mutex_t *> mutexes;
20+
std::map<const void *, std::shared_ptr<uv_mutex_t>> mutexes;
2021
uv_mutex_t map_mutex;
2122
uv_key_t current_lock_master_key;
23+
uv_async_t cleanup_mutexes_handle;
24+
25+
void cleanup_mutexes(uv_async_t *async) {
26+
uv_mutex_lock(&map_mutex);
27+
28+
for(std::map<const void *, std::shared_ptr<uv_mutex_t> >::iterator it=mutexes.begin(); it != mutexes.end(); )
29+
{
30+
std::shared_ptr<uv_mutex_t> &mutex = it->second;
31+
// if the mutex is only referenced by the mutexes map,
32+
// we can destroy it (because any LockMaster that is using the mutex would
33+
// hold it in its object_mutexes)
34+
if (mutex.unique()) {
35+
uv_mutex_destroy(mutex.get());
36+
it = mutexes.erase(it);
37+
} else {
38+
it++;
39+
}
40+
}
41+
42+
uv_mutex_unlock(&map_mutex);
43+
}
2244

2345
extern "C" void init(Local<v8::Object> target) {
2446
// Initialize libgit2.
@@ -35,6 +57,7 @@ extern "C" void init(Local<v8::Object> target) {
3557

3658
uv_mutex_init(&map_mutex);
3759
uv_key_create(&current_lock_master_key);
60+
uv_async_init(uv_default_loop(), &cleanup_mutexes_handle, cleanup_mutexes);
3861
}
3962

4063
void LockMaster::GetMutexes()
@@ -46,8 +69,8 @@ void LockMaster::GetMutexes()
4669
if(object) {
4770
// ensure we have an initialized mutex for each object
4871
if(!mutexes[object]) {
49-
mutexes[object] = (uv_mutex_t *)malloc(sizeof(uv_mutex_t));
50-
uv_mutex_init(mutexes[object]);
72+
mutexes[object] = std::shared_ptr<uv_mutex_t>((uv_mutex_t *)malloc(sizeof(uv_mutex_t)));
73+
uv_mutex_init(mutexes[object].get());
5174
}
5275

5376
object_mutexes.push_back(mutexes[object]);
@@ -72,12 +95,23 @@ void LockMaster::Lock()
7295
// lock the mutex (note locking the mutexes one by one can lead to
7396
// deadlocks... we might be better off locking them all at once
7497
// (using trylock, then unlocking if they can't all be locked, then lock & wait, repeat...)
75-
std::for_each(object_mutexes.begin(), object_mutexes.end(), uv_mutex_lock);
98+
for(std::shared_ptr<uv_mutex_t> &mutex : object_mutexes) {
99+
uv_mutex_lock(mutex.get());
100+
}
76101
}
77102

78103
void LockMaster::Unlock()
79104
{
80-
std::for_each(object_mutexes.begin(), object_mutexes.end(), uv_mutex_unlock);
105+
for(std::shared_ptr<uv_mutex_t> &mutex : object_mutexes) {
106+
uv_mutex_unlock(mutex.get());
107+
}
108+
}
109+
110+
void LockMaster::CleanupMutexes()
111+
{
112+
// schedule mutex cleanup on the main event loop
113+
// this somewhat delays and debounces cleanup (uv_async_send coalesces calls)
114+
uv_async_send(&cleanup_mutexes_handle);
81115
}
82116

83117
LockMaster::TemporaryUnlock::TemporaryUnlock() {

0 commit comments

Comments
 (0)