| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- #include "JSONNode.h"
- #include "JSONGlobals.h"
- #ifdef JSON_MUTEX_CALLBACKS
- json_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_MANAGE
- json_mutex_callback_t json_destroy = 0;
- //make sure that the global mutex is taken care of too
- struct 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;
- #endif
- void 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 anyway
- return 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 locked
- void * thislock = getThisLock(this);
- #ifdef JSON_SAFE
- if (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 is
- JSON_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 locked
- newthread.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 it
- json_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 locked
- void * thislock = getThisLock(this);
- #ifdef JSON_SAFE
- if (thislock == 0) return;
- #endif
-
- //get it out of the map
- JSON_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 thread
- JSON_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 it
- if (--(locker -> second)) return; //other nodes is this same thread still have a lock on it
-
- //if I need to, unlock it
- newthread.erase(locker);
- json_unlock_callback(thislock);
-
- }
- #ifdef JSON_MUTEX_MANAGE
- void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow {
- json_destroy = destroy;
- }
- #endif
- void internalJSONNode::_set_mutex(void * mutex, bool unset) json_nothrow {
- if (unset) _unset_mutex(); //for reference counting
- mylock = mutex;
- if (mutex != 0){
- #ifdef JSON_MUTEX_MANAGE
- JSON_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;
- }
- #endif
- if (isContainer()){
- json_foreach(CHILDREN, myrunner){
- (*myrunner) -> set_mutex(mutex);
- }
- }
- }
- }
- void internalJSONNode::_unset_mutex(void) json_nothrow {
- #ifdef JSON_MUTEX_MANAGE
- if (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_LIBRARY
- JSONNode internalJSONNode::DumpMutex(void) const json_nothrow {
- JSONNode mut(JSON_NODE);
- mut.set_name(JSON_TEXT("mylock"));
- #ifdef JSON_MUTEX_MANAGE
- if (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;
- }
- #else
- mut = (long)mylock;
- #endif
- return mut;
- }
- #endif
- #endif
- #else
- #ifdef JSON_MUTEX_MANAGE
- #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS
- #endif
- #endif
|