Jamoma API  0.6.0.a19
JSONNode_Mutex.cpp
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