66#include < map>
77#include < algorithm>
88#include < set>
9+ #include < memory>
910
1011#include " ../include/nodegit.h"
1112#include " ../include/wrapper.h"
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;
2021uv_mutex_t map_mutex;
2122uv_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
2345extern " 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 (¤t_lock_master_key);
60+ uv_async_init (uv_default_loop (), &cleanup_mutexes_handle, cleanup_mutexes);
3861}
3962
4063void 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
78103void 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
83117LockMaster::TemporaryUnlock::TemporaryUnlock () {
0 commit comments