1 #include "JSONNode.h"
2 #include "JSONGlobals.h"
3 
4 #ifdef JSON_MUTEX_CALLBACKS
5 
6 json_mutex_callback_t json_lock_callback = 0;
7 json_mutex_callback_t json_unlock_callback = 0;
8 void * global_mutex = 0;
9 void * manager_mutex = 0;
10 
11 struct AutoLock {
12 public:
13 	LIBJSON_OBJECT(AutoLock);
AutoLockAutoLock14     AutoLock(void) json_nothrow {
15 		LIBJSON_CTOR;
16 	   json_lock_callback(manager_mutex);
17     }
~AutoLockAutoLock18     ~AutoLock(void) json_nothrow {
19 		LIBJSON_DTOR;
20 	   json_unlock_callback(manager_mutex);
21     }
22 private:
23     AutoLock(const AutoLock &);
24     AutoLock & operator = (const AutoLock &);
25 };
26 
27 #ifdef JSON_MUTEX_MANAGE
28     json_mutex_callback_t json_destroy = 0;
29 
30     //make sure that the global mutex is taken care of too
31     struct auto_global {
32     public:
33 		LIBJSON_OBJECT(auto_global;)
auto_globalauto_global34 	   auto_global(void) json_nothrow { LIBJSON_CTOR; }
~auto_globalauto_global35 	   ~auto_global(void) json_nothrow {
36 		  LIBJSON_DTOR;
37 		  if (global_mutex){
38 			 JSON_ASSERT_SAFE(json_destroy != 0, JSON_TEXT("No json_destroy in mutex managed mode"), return;);
39 			 json_destroy(global_mutex);
40 		  }
41 	   }
42     private:
43         auto_global(const auto_global &);
44         auto_global & operator = (const auto_global &);
45     };
46     auto_global cleanupGlobal;
47 #endif
48 
register_mutex_callbacks(json_mutex_callback_t lock,json_mutex_callback_t unlock,void * manager_lock)49 void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock) json_nothrow {
50     json_lock_callback = lock;
51     json_unlock_callback = unlock;
52     manager_mutex = manager_lock;
53 }
54 
set_global_mutex(void * mutex)55 void JSONNode::set_global_mutex(void * mutex) json_nothrow {
56     global_mutex = mutex;
57 }
58 
set_mutex(void * mutex)59 void JSONNode::set_mutex(void * mutex) json_nothrow {
60     makeUniqueInternal();
61     internal -> _set_mutex(mutex);
62 }
63 
getThisLock(JSONNode * pthis)64 void * JSONNode::getThisLock(JSONNode * pthis) json_nothrow {
65     if (pthis -> internal -> mylock != 0){
66 	   return pthis -> internal -> mylock;
67     }
68     JSON_ASSERT(global_mutex != 0, JSON_TEXT("No global_mutex"));  //this is safe, because it's just goingi to return 0 anyway
69     return global_mutex;
70 }
71 
lock(int thread)72 void JSONNode::lock(int thread) json_nothrow {
73     JSON_ASSERT_SAFE(json_lock_callback != 0, JSON_TEXT("No locking callback"), return;);
74 
75     AutoLock lockControl;
76 
77     //first, figure out what needs to be locked
78     void * thislock = getThisLock(this);
79     #ifdef JSON_SAFE
80 	   if (json_unlikely(thislock == 0)) return;
81     #endif
82 
83     //make sure that the same thread isn't locking it more than once (possible due to complex ref counting)
84     JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread);
85     if (it == json_global(THREAD_LOCKS).end()){
86 		JSON_MAP(void *, unsigned int) newthread;
87 		newthread[thislock] = 1;
88 		json_global(THREAD_LOCKS).insert(std::pair<int, JSON_MAP(void *, unsigned int) >(thread, newthread));
89     } else {  //this thread already has some things locked, check if the current mutex is
90 		JSON_MAP(void *, unsigned int) & newthread = it -> second;
91 		JSON_MAP(void *, unsigned int)::iterator locker(newthread.find(thislock));
92 		if (locker == newthread.end()){  //current mutex is not locked, set it to locked
93 			newthread.insert(std::pair<void *, unsigned int>(thislock, 1));
94 		} else {  //it's already locked, don't relock it
95 			++(locker -> second);
96 			return;  //don't try to relock, it will deadlock the program
97 		}
98     }
99 
100     //if I need to, lock it
101     json_lock_callback(thislock);
102 }
103 
unlock(int thread)104 void JSONNode::unlock(int thread) json_nothrow{
105     JSON_ASSERT_SAFE(json_unlock_callback != 0, JSON_TEXT("No unlocking callback"), return;);
106 
107     AutoLock lockControl;
108 
109     //first, figure out what needs to be locked
110     void * thislock = getThisLock(this);
111 	#ifdef JSON_SAFE
112 		if (thislock == 0) return;
113 	#endif
114 
115     //get it out of the map
116     JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread);
117     JSON_ASSERT_SAFE(it != json_global(THREAD_LOCKS).end(), JSON_TEXT("thread unlocking something it didn't lock"), return;);
118 
119     //get the mutex out of the thread
120     JSON_MAP(void *, unsigned int) & newthread = it -> second;
121     JSON_MAP(void *, unsigned int)::iterator locker = newthread.find(thislock);
122     JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;);
123 
124     //unlock it
125     if (--(locker -> second)) return;  //other nodes is this same thread still have a lock on it
126 
127     //if I need to, unlock it
128     newthread.erase(locker);
129     json_unlock_callback(thislock);
130 
131 }
132 
133 #ifdef JSON_MUTEX_MANAGE
register_mutex_destructor(json_mutex_callback_t destroy)134     void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow {
135 	   json_destroy = destroy;
136     }
137 #endif
138 
139 
_set_mutex(void * mutex,bool unset)140 void internalJSONNode::_set_mutex(void * mutex, bool unset) json_nothrow {
141     if (unset) _unset_mutex();  //for reference counting
142     mylock = mutex;
143     if (mutex != 0){
144 	   #ifdef JSON_MUTEX_MANAGE
145 		  JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mutex);
146 		  if (it == json_global(MUTEX_MANAGER).end()){
147 			 json_global(MUTEX_MANAGER).insert(std::pair<void *, unsigned int>(mutex, 1));
148 		  } else {
149 			 ++it -> second;
150 		  }
151 	   #endif
152 	   if (isContainer()){
153 		  json_foreach(CHILDREN, myrunner){
154 			 (*myrunner) -> set_mutex(mutex);
155 		  }
156 	   }
157     }
158 }
159 
_unset_mutex(void)160 void internalJSONNode::_unset_mutex(void) json_nothrow {
161     #ifdef JSON_MUTEX_MANAGE
162 	   if (mylock != 0){
163 		  JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock);
164 		  JSON_ASSERT_SAFE(it != json_global(MUTEX_MANAGER).end(), JSON_TEXT("Mutex not managed"), return;);
165 		  --it -> second;
166 		  if (it -> second == 0){
167 			 JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;);
168 			 json_global(MUTEX_MANAGER).erase(it);
169 		  }
170 	   }
171     #endif
172 }
173 
174 #ifdef JSON_DEBUG
175     #ifndef JSON_LIBRARY
DumpMutex(void) const176 	   JSONNode internalJSONNode::DumpMutex(void) const json_nothrow {
177 		  JSONNode mut(JSON_NODE);
178 		  mut.set_name(JSON_TEXT("mylock"));
179 		  #ifdef JSON_MUTEX_MANAGE
180 			 if (mylock != 0){
181 				mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock)));
182 				JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock);
183 				if (it == json_global(MUTEX_MANAGER).end()){
184 				    mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error"))));
185 				} else {
186 				    mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second)));
187 				}
188 			 } else {
189 				mut = (long)mylock;
190 			 }
191 		  #else
192 			 mut = (long)mylock;
193 		  #endif
194 		  return mut;
195 	   }
196     #endif
197 #endif
198 
199 #else
200     #ifdef JSON_MUTEX_MANAGE
201 	   #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS
202     #endif
203 #endif
204