Blame | Last modification | View Log | Download | RSS feed
#include "JSONNode.h"#include "JSONGlobals.h"#ifdef JSON_MUTEX_CALLBACKSjson_mutex_callback_t json_lock_callback = 0;json_mutex_callback_t json_unlock_callback = 0;void * global_mutex = 0;void * manager_mutex = 0;struct AutoLock {public:LIBJSON_OBJECT(AutoLock);AutoLock(void) json_nothrow {LIBJSON_CTOR;json_lock_callback(manager_mutex);}~AutoLock(void) json_nothrow {LIBJSON_DTOR;json_unlock_callback(manager_mutex);}private:AutoLock(const AutoLock &);AutoLock & operator = (const AutoLock &);};#ifdef JSON_MUTEX_MANAGEjson_mutex_callback_t json_destroy = 0;//make sure that the global mutex is taken care of toostruct auto_global {public:LIBJSON_OBJECT(auto_global;)auto_global(void) json_nothrow { LIBJSON_CTOR; }~auto_global(void) json_nothrow {LIBJSON_DTOR;if (global_mutex){JSON_ASSERT_SAFE(json_destroy != 0, JSON_TEXT("No json_destroy in mutex managed mode"), return;);json_destroy(global_mutex);}}private:auto_global(const auto_global &);auto_global & operator = (const auto_global &);};auto_global cleanupGlobal;#endifvoid JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock) json_nothrow {json_lock_callback = lock;json_unlock_callback = unlock;manager_mutex = manager_lock;}void JSONNode::set_global_mutex(void * mutex) json_nothrow {global_mutex = mutex;}void JSONNode::set_mutex(void * mutex) json_nothrow {makeUniqueInternal();internal -> _set_mutex(mutex);}void * JSONNode::getThisLock(JSONNode * pthis) json_nothrow {if (pthis -> internal -> mylock != 0){return pthis -> internal -> mylock;}JSON_ASSERT(global_mutex != 0, JSON_TEXT("No global_mutex")); //this is safe, because it's just goingi to return 0 anywayreturn global_mutex;}void JSONNode::lock(int thread) json_nothrow {JSON_ASSERT_SAFE(json_lock_callback != 0, JSON_TEXT("No locking callback"), return;);AutoLock lockControl;//first, figure out what needs to be lockedvoid * thislock = getThisLock(this);#ifdef JSON_SAFEif (json_unlikely(thislock == 0)) return;#endif//make sure that the same thread isn't locking it more than once (possible due to complex ref counting)JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread);if (it == json_global(THREAD_LOCKS).end()){JSON_MAP(void *, unsigned int) newthread;newthread[thislock] = 1;json_global(THREAD_LOCKS).insert(std::pair<int, JSON_MAP(void *, unsigned int) >(thread, newthread));} else { //this thread already has some things locked, check if the current mutex isJSON_MAP(void *, unsigned int) & newthread = it -> second;JSON_MAP(void *, unsigned int)::iterator locker(newthread.find(thislock));if (locker == newthread.end()){ //current mutex is not locked, set it to lockednewthread.insert(std::pair<void *, unsigned int>(thislock, 1));} else { //it's already locked, don't relock it++(locker -> second);return; //don't try to relock, it will deadlock the program}}//if I need to, lock itjson_lock_callback(thislock);}void JSONNode::unlock(int thread) json_nothrow{JSON_ASSERT_SAFE(json_unlock_callback != 0, JSON_TEXT("No unlocking callback"), return;);AutoLock lockControl;//first, figure out what needs to be lockedvoid * thislock = getThisLock(this);#ifdef JSON_SAFEif (thislock == 0) return;#endif//get it out of the mapJSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread);JSON_ASSERT_SAFE(it != json_global(THREAD_LOCKS).end(), JSON_TEXT("thread unlocking something it didn't lock"), return;);//get the mutex out of the threadJSON_MAP(void *, unsigned int) & newthread = it -> second;JSON_MAP(void *, unsigned int)::iterator locker = newthread.find(thislock);JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;);//unlock itif (--(locker -> second)) return; //other nodes is this same thread still have a lock on it//if I need to, unlock itnewthread.erase(locker);json_unlock_callback(thislock);}#ifdef JSON_MUTEX_MANAGEvoid JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow {json_destroy = destroy;}#endifvoid internalJSONNode::_set_mutex(void * mutex, bool unset) json_nothrow {if (unset) _unset_mutex(); //for reference countingmylock = mutex;if (mutex != 0){#ifdef JSON_MUTEX_MANAGEJSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mutex);if (it == json_global(MUTEX_MANAGER).end()){json_global(MUTEX_MANAGER).insert(std::pair<void *, unsigned int>(mutex, 1));} else {++it -> second;}#endifif (isContainer()){json_foreach(CHILDREN, myrunner){(*myrunner) -> set_mutex(mutex);}}}}void internalJSONNode::_unset_mutex(void) json_nothrow {#ifdef JSON_MUTEX_MANAGEif (mylock != 0){JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock);JSON_ASSERT_SAFE(it != json_global(MUTEX_MANAGER).end(), JSON_TEXT("Mutex not managed"), return;);--it -> second;if (it -> second == 0){JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;);json_global(MUTEX_MANAGER).erase(it);}}#endif}#ifdef JSON_DEBUG#ifndef JSON_LIBRARYJSONNode internalJSONNode::DumpMutex(void) const json_nothrow {JSONNode mut(JSON_NODE);mut.set_name(JSON_TEXT("mylock"));#ifdef JSON_MUTEX_MANAGEif (mylock != 0){mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock)));JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock);if (it == json_global(MUTEX_MANAGER).end()){mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error"))));} else {mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second)));}} else {mut = (long)mylock;}#elsemut = (long)mylock;#endifreturn mut;}#endif#endif#else#ifdef JSON_MUTEX_MANAGE#error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS#endif#endif