FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Thread safety implementation using locking by srajko · Pull Request #836 · nodegit/nodegit · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension .cc  (1) .h  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
Prev Previous commit
Next Next commit
Remove use of shared_ptr
  • Loading branch information
srajko committed Dec 30, 2015
commit 5efab3f13fdf8dd02813d1923ec9423f20990e8f
13 changes: 5 additions & 8 deletions generate/templates/manual/include/nodegit.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@
#include <set>
#include <vector>
#include <uv.h>
#include <memory>

class LockMaster {

static bool enabled;

std::set<const void *> objects_to_lock;
std::vector<std::shared_ptr<uv_mutex_t> > object_mutexes;

template<typename T>
void AddLocks(const T *t) {
Expand All @@ -34,11 +32,11 @@ class LockMaster {
AddParameters(args...);
}

void GetMutexes();
std::vector<uv_mutex_t *> GetMutexes(int use_count_delta);
void Register();
void Unregister();
void Lock();
void Unlock();
void Lock(bool acquire_mutexes);
void Unlock(bool release_mutexes);
void CleanupMutexes();

public:
Expand All @@ -51,9 +49,8 @@ class LockMaster {
}

AddParameters(types...);
GetMutexes();
Register();
Lock();
Lock(true);
}

// and unlock on destruction
Expand All @@ -64,7 +61,7 @@ class LockMaster {
}

Unregister();
Unlock();
Unlock(true);
CleanupMutexes();
}

Expand Down
68 changes: 43 additions & 25 deletions generate/templates/templates/nodegit.cc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <map>
#include <algorithm>
#include <set>
#include <memory>

#include "../include/nodegit.h"
#include "../include/wrapper.h"
Expand All @@ -17,23 +16,27 @@
{% endif %}
{% endeach %}

std::map<const void *, std::shared_ptr<uv_mutex_t>> mutexes;
std::map<const void *, std::pair<uv_mutex_t *, unsigned> > mutexes;
uv_mutex_t map_mutex;
uv_key_t current_lock_master_key;
uv_async_t cleanup_mutexes_handle;

void cleanup_mutexes(uv_async_t *async) {
uv_mutex_lock(&map_mutex);

for(std::map<const void *, std::shared_ptr<uv_mutex_t> >::iterator it=mutexes.begin(); it != mutexes.end(); )
for(std::map<const void *, std::pair<uv_mutex_t *, unsigned> >::iterator it=mutexes.begin(); it != mutexes.end(); )
{
std::shared_ptr<uv_mutex_t> &mutex = it->second;
uv_mutex_t *mutex = it->second.first;
unsigned use_count = it->second.second;
// if the mutex is only referenced by the mutexes map,
// we can destroy it (because any LockMaster that is using the mutex would
// hold it in its object_mutexes)
if (mutex.unique()) {
uv_mutex_destroy(mutex.get());
it = mutexes.erase(it);
if (!use_count) {
uv_mutex_destroy(mutex);
free(mutex);
std::map<const void *, std::pair<uv_mutex_t *, unsigned> >::iterator to_erase = it;
it++;
mutexes.erase(to_erase);
} else {
it++;
}
Expand Down Expand Up @@ -71,24 +74,35 @@ extern "C" void init(Local<v8::Object> target) {
uv_async_init(uv_default_loop(), &cleanup_mutexes_handle, cleanup_mutexes);
}

void LockMaster::GetMutexes()
std::vector<uv_mutex_t *> LockMaster::GetMutexes(int use_count_delta)
{
std::vector<uv_mutex_t *> object_mutexes;

uv_mutex_lock(&map_mutex);

for (std::set<const void *>::const_iterator it = objects_to_lock.begin(); it != objects_to_lock.end(); it++) {
const void *object = *it;
if(object) {
// ensure we have an initialized mutex for each object
if(!mutexes[object]) {
mutexes[object] = std::shared_ptr<uv_mutex_t>((uv_mutex_t *)malloc(sizeof(uv_mutex_t)));
uv_mutex_init(mutexes[object].get());
std::map<const void *, std::pair<uv_mutex_t *, unsigned> >::iterator mutex_it = mutexes.find(object);
if(mutex_it == mutexes.end()) {
mutex_it = mutexes.insert(
std::make_pair(
object,
std::make_pair((uv_mutex_t *)malloc(sizeof(uv_mutex_t)), 0U)
)
).first;
uv_mutex_init(mutex_it->second.first);
}

object_mutexes.push_back(mutexes[object]);
object_mutexes.push_back(mutex_it->second.first);
mutex_it->second.second += use_count_delta;
}
}

uv_mutex_unlock(&map_mutex);

return object_mutexes;
}

void LockMaster::Register()
Expand All @@ -101,14 +115,16 @@ void LockMaster::Unregister()
uv_key_set(&current_lock_master_key, NULL);
}

void LockMaster::Lock()
void LockMaster::Lock(bool acquire_mutexes)
{
std::vector<std::shared_ptr<uv_mutex_t> >::iterator already_locked = object_mutexes.end();
std::vector<uv_mutex_t *> object_mutexes = GetMutexes(acquire_mutexes * 1);

std::vector<uv_mutex_t *>::iterator already_locked = object_mutexes.end();

// we will attempt to lock all the mutexes at the same time to avoid deadlocks
// note in most cases we are locking 0 or 1 mutexes. more than 1 implies
// passing objects with different repos/owners in the same call.
std::vector<std::shared_ptr<uv_mutex_t> >::iterator it;
std::vector<uv_mutex_t *>::iterator it;
do
{
// go through all the mutexes and try to lock them
Expand All @@ -119,17 +135,17 @@ void LockMaster::Lock()
continue;
}
// first, try to lock (non-blocking)
bool failure = uv_mutex_trylock(it->get());
bool failure = uv_mutex_trylock(*it);
if(failure) {
// we have failed to lock a mutex... unlock everything we have locked
for(std::vector<std::shared_ptr<uv_mutex_t> >::iterator unlock_it = object_mutexes.begin(); unlock_it != it; unlock_it++) {
uv_mutex_unlock(unlock_it->get());
for(std::vector<uv_mutex_t *>::iterator unlock_it = object_mutexes.begin(); unlock_it != it; unlock_it++) {
uv_mutex_unlock(*unlock_it);
}
if(already_locked > it && already_locked != object_mutexes.end()) {
uv_mutex_unlock(already_locked->get());
uv_mutex_unlock(*already_locked);
}
// now do a blocking lock on what we couldn't lock
uv_mutex_lock(it->get());
uv_mutex_lock(*it);
// mark that we have already locked this one
// if there are more mutexes than this one, we will go back to locking everything
already_locked = it;
Expand All @@ -139,10 +155,12 @@ void LockMaster::Lock()
} while(it != object_mutexes.end());
}

void LockMaster::Unlock()
void LockMaster::Unlock(bool release_mutexes)
{
for(std::shared_ptr<uv_mutex_t> &mutex : object_mutexes) {
uv_mutex_unlock(mutex.get());
std::vector<uv_mutex_t *> object_mutexes = GetMutexes(release_mutexes * -1);

for(std::vector<uv_mutex_t *>::iterator it=object_mutexes.begin(); it != object_mutexes.end(); it++) {
uv_mutex_unlock(*it);
}
}

Expand All @@ -158,14 +176,14 @@ LockMaster::TemporaryUnlock::TemporaryUnlock() {
return;
}
lockMaster = (LockMaster *)uv_key_get(&current_lock_master_key);
lockMaster->Unlock();
lockMaster->Unlock(false);
}

LockMaster::TemporaryUnlock::~TemporaryUnlock() {
if(!enabled) {
return;
}
lockMaster->Lock();
lockMaster->Lock(false);
}

bool LockMaster::enabled = false;
Expand Down

Back | FazBrowse Home | New Git URL