| 7747 |
ripley |
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);
|
|
|
14 |
AutoLock(void) json_nothrow {
|
|
|
15 |
LIBJSON_CTOR;
|
|
|
16 |
json_lock_callback(manager_mutex);
|
|
|
17 |
}
|
|
|
18 |
~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;)
|
|
|
34 |
auto_global(void) json_nothrow { LIBJSON_CTOR; }
|
|
|
35 |
~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 |
|
|
|
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 |
|
|
|
55 |
void JSONNode::set_global_mutex(void * mutex) json_nothrow {
|
|
|
56 |
global_mutex = mutex;
|
|
|
57 |
}
|
|
|
58 |
|
|
|
59 |
void JSONNode::set_mutex(void * mutex) json_nothrow {
|
|
|
60 |
makeUniqueInternal();
|
|
|
61 |
internal -> _set_mutex(mutex);
|
|
|
62 |
}
|
|
|
63 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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
|
|
|
134 |
void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow {
|
|
|
135 |
json_destroy = destroy;
|
|
|
136 |
}
|
|
|
137 |
#endif
|
|
|
138 |
|
|
|
139 |
|
|
|
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 |
|
|
|
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
|
|
|
176 |
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
|