66#include < map>
77#include < algorithm>
88#include < set>
9- #include < memory>
109
1110#include " ../include/nodegit.h"
1211#include " ../include/wrapper.h"
1716 {% endif %}
1817{% endeach %}
1918
20- std::map<const void *, std::shared_ptr <uv_mutex_t > > mutexes;
19+ std::map<const void *, std::pair <uv_mutex_t *, unsigned > > mutexes;
2120uv_mutex_t map_mutex;
2221uv_key_t current_lock_master_key;
2322uv_async_t cleanup_mutexes_handle;
2423
2524void cleanup_mutexes (uv_async_t *async) {
2625 uv_mutex_lock (&map_mutex);
2726
28- for (std::map<const void *, std::shared_ptr <uv_mutex_t > >::iterator it=mutexes.begin (); it != mutexes.end (); )
27+ for (std::map<const void *, std::pair <uv_mutex_t *, unsigned > >::iterator it=mutexes.begin (); it != mutexes.end (); )
2928 {
30- std::shared_ptr<uv_mutex_t > &mutex = it->second ;
29+ uv_mutex_t *mutex = it->second .first ;
30+ unsigned use_count = it->second .second ;
3131 // if the mutex is only referenced by the mutexes map,
3232 // we can destroy it (because any LockMaster that is using the mutex would
3333 // hold it in its object_mutexes)
34- if (mutex.unique ()) {
35- uv_mutex_destroy (mutex.get ());
36- it = mutexes.erase (it);
34+ if (!use_count) {
35+ uv_mutex_destroy (mutex);
36+ free (mutex);
37+ std::map<const void *, std::pair<uv_mutex_t *, unsigned > >::iterator to_erase = it;
38+ it++;
39+ mutexes.erase (to_erase);
3740 } else {
3841 it++;
3942 }
@@ -71,24 +74,35 @@ extern "C" void init(Local<v8::Object> target) {
7174 uv_async_init (uv_default_loop (), &cleanup_mutexes_handle, cleanup_mutexes);
7275}
7376
74- void LockMaster::GetMutexes ()
77+ std::vector< uv_mutex_t *> LockMaster::GetMutexes (int use_count_delta )
7578{
79+ std::vector<uv_mutex_t *> object_mutexes;
80+
7681 uv_mutex_lock (&map_mutex);
7782
7883 for (std::set<const void *>::const_iterator it = objects_to_lock.begin (); it != objects_to_lock.end (); it++) {
7984 const void *object = *it;
8085 if (object) {
8186 // ensure we have an initialized mutex for each object
82- if (!mutexes[object]) {
83- mutexes[object] = std::shared_ptr<uv_mutex_t >((uv_mutex_t *)malloc (sizeof (uv_mutex_t )));
84- uv_mutex_init (mutexes[object].get ());
87+ std::map<const void *, std::pair<uv_mutex_t *, unsigned > >::iterator mutex_it = mutexes.find (object);
88+ if (mutex_it == mutexes.end ()) {
89+ mutex_it = mutexes.insert (
90+ std::make_pair (
91+ object,
92+ std::make_pair ((uv_mutex_t *)malloc (sizeof (uv_mutex_t )), 0U )
93+ )
94+ ).first ;
95+ uv_mutex_init (mutex_it->second .first );
8596 }
8697
87- object_mutexes.push_back (mutexes[object]);
98+ object_mutexes.push_back (mutex_it->second .first );
99+ mutex_it->second .second += use_count_delta;
88100 }
89101 }
90102
91103 uv_mutex_unlock (&map_mutex);
104+
105+ return object_mutexes;
92106}
93107
94108void LockMaster::Register ()
@@ -101,14 +115,16 @@ void LockMaster::Unregister()
101115 uv_key_set (¤t_lock_master_key, NULL );
102116}
103117
104- void LockMaster::Lock ()
118+ void LockMaster::Lock (bool acquire_mutexes )
105119{
106- std::vector<std::shared_ptr<uv_mutex_t > >::iterator already_locked = object_mutexes.end ();
120+ std::vector<uv_mutex_t *> object_mutexes = GetMutexes (acquire_mutexes * 1 );
121+
122+ std::vector<uv_mutex_t *>::iterator already_locked = object_mutexes.end ();
107123
108124 // we will attempt to lock all the mutexes at the same time to avoid deadlocks
109125 // note in most cases we are locking 0 or 1 mutexes. more than 1 implies
110126 // passing objects with different repos/owners in the same call.
111- std::vector<std::shared_ptr< uv_mutex_t > >::iterator it;
127+ std::vector<uv_mutex_t * >::iterator it;
112128 do
113129 {
114130 // go through all the mutexes and try to lock them
@@ -119,17 +135,17 @@ void LockMaster::Lock()
119135 continue ;
120136 }
121137 // first, try to lock (non-blocking)
122- bool failure = uv_mutex_trylock (it-> get () );
138+ bool failure = uv_mutex_trylock (*it );
123139 if (failure) {
124140 // we have failed to lock a mutex... unlock everything we have locked
125- for (std::vector<std::shared_ptr< uv_mutex_t > >::iterator unlock_it = object_mutexes.begin (); unlock_it != it; unlock_it++) {
126- uv_mutex_unlock (unlock_it-> get () );
141+ for (std::vector<uv_mutex_t * >::iterator unlock_it = object_mutexes.begin (); unlock_it != it; unlock_it++) {
142+ uv_mutex_unlock (* unlock_it);
127143 }
128144 if (already_locked > it && already_locked != object_mutexes.end ()) {
129- uv_mutex_unlock (already_locked-> get () );
145+ uv_mutex_unlock (* already_locked);
130146 }
131147 // now do a blocking lock on what we couldn't lock
132- uv_mutex_lock (it-> get () );
148+ uv_mutex_lock (*it );
133149 // mark that we have already locked this one
134150 // if there are more mutexes than this one, we will go back to locking everything
135151 already_locked = it;
@@ -139,10 +155,12 @@ void LockMaster::Lock()
139155 } while (it != object_mutexes.end ());
140156}
141157
142- void LockMaster::Unlock ()
158+ void LockMaster::Unlock (bool release_mutexes )
143159{
144- for (std::shared_ptr<uv_mutex_t > &mutex : object_mutexes) {
145- uv_mutex_unlock (mutex.get ());
160+ std::vector<uv_mutex_t *> object_mutexes = GetMutexes (release_mutexes * -1 );
161+
162+ for (std::vector<uv_mutex_t *>::iterator it=object_mutexes.begin (); it != object_mutexes.end (); it++) {
163+ uv_mutex_unlock (*it);
146164 }
147165}
148166
@@ -158,14 +176,14 @@ LockMaster::TemporaryUnlock::TemporaryUnlock() {
158176 return ;
159177 }
160178 lockMaster = (LockMaster *)uv_key_get (¤t_lock_master_key);
161- lockMaster->Unlock ();
179+ lockMaster->Unlock (false );
162180}
163181
164182LockMaster::TemporaryUnlock::~TemporaryUnlock () {
165183 if (!enabled) {
166184 return ;
167185 }
168- lockMaster->Lock ();
186+ lockMaster->Lock (false );
169187}
170188
171189bool LockMaster::enabled = false ;
0 commit comments