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