The R Project SVN R-packages

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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