1 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
* |
3 |
* ***** BEGIN LICENSE BLOCK ***** |
4 |
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
5 |
* |
6 |
* The contents of this file are subject to the Mozilla Public License Version |
7 |
* 1.1 (the "License"); you may not use this file except in compliance with |
8 |
* the License. You may obtain a copy of the License at |
9 |
* http://www.mozilla.org/MPL/ |
10 |
* |
11 |
* Software distributed under the License is distributed on an "AS IS" basis, |
12 |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 |
* for the specific language governing rights and limitations under the |
14 |
* License. |
15 |
* |
16 |
* The Original Code is Mozilla Communicator client code, released |
17 |
* March 31, 1998. |
18 |
* |
19 |
* The Initial Developer of the Original Code is |
20 |
* Netscape Communications Corporation. |
21 |
* Portions created by the Initial Developer are Copyright (C) 1998 |
22 |
* the Initial Developer. All Rights Reserved. |
23 |
* |
24 |
* Contributor(s): |
25 |
* |
26 |
* Alternatively, the contents of this file may be used under the terms of |
27 |
* either of the GNU General Public License Version 2 or later (the "GPL"), |
28 |
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
29 |
* in which case the provisions of the GPL or the LGPL are applicable instead |
30 |
* of those above. If you wish to allow use of your version of this file only |
31 |
* under the terms of either the GPL or the LGPL, and not to allow others to |
32 |
* use your version of this file under the terms of the MPL, indicate your |
33 |
* decision by deleting the provisions above and replace them with the notice |
34 |
* and other provisions required by the GPL or the LGPL. If you do not delete |
35 |
* the provisions above, a recipient may use your version of this file under |
36 |
* the terms of any one of the MPL, the GPL or the LGPL. |
37 |
* |
38 |
* ***** END LICENSE BLOCK ***** */ |
39 |
#ifndef jslock_h__ |
40 |
#define jslock_h__ |
41 |
|
42 |
#include "jstypes.h" |
43 |
#include "jsprvtd.h" /* for JSScope, etc. */ |
44 |
#include "jspubtd.h" /* for JSRuntime, etc. */ |
45 |
|
46 |
#ifdef JS_THREADSAFE |
47 |
# include "pratom.h" |
48 |
# include "prlock.h" |
49 |
# include "prcvar.h" |
50 |
# include "prthread.h" |
51 |
#endif |
52 |
|
53 |
JS_BEGIN_EXTERN_C |
54 |
|
55 |
#ifdef JS_THREADSAFE |
56 |
|
57 |
#if (defined(_WIN32) && defined(_M_IX86)) || \ |
58 |
(defined(__GNUC__) && defined(__i386__)) || \ |
59 |
(defined(__GNUC__) && defined(__x86_64__)) || \ |
60 |
(defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) || \ |
61 |
defined(AIX) || \ |
62 |
defined(USE_ARM_KUSER) |
63 |
# define JS_HAS_NATIVE_COMPARE_AND_SWAP 1 |
64 |
#else |
65 |
# define JS_HAS_NATIVE_COMPARE_AND_SWAP 0 |
66 |
#endif |
67 |
|
68 |
#if defined(JS_USE_ONLY_NSPR_LOCKS) || !JS_HAS_NATIVE_COMPARE_AND_SWAP |
69 |
# define NSPR_LOCK 1 |
70 |
#else |
71 |
# undef NSPR_LOCK |
72 |
#endif |
73 |
|
74 |
#define Thin_GetWait(W) ((jsword)(W) & 0x1) |
75 |
#define Thin_SetWait(W) ((jsword)(W) | 0x1) |
76 |
#define Thin_RemoveWait(W) ((jsword)(W) & ~0x1) |
77 |
|
78 |
typedef struct JSFatLock JSFatLock; |
79 |
|
80 |
typedef struct JSThinLock { |
81 |
jsword owner; |
82 |
JSFatLock *fat; |
83 |
} JSThinLock; |
84 |
|
85 |
#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread) |
86 |
#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId()) |
87 |
|
88 |
typedef PRLock JSLock; |
89 |
|
90 |
typedef struct JSTitle JSTitle; |
91 |
|
92 |
struct JSTitle { |
93 |
JSContext *ownercx; /* creating context, NULL if shared */ |
94 |
JSThinLock lock; /* binary semaphore protecting title */ |
95 |
union { /* union lockful and lock-free state: */ |
96 |
jsrefcount count; /* lock entry count for reentrancy */ |
97 |
JSTitle *link; /* next link in rt->titleSharingTodo */ |
98 |
} u; |
99 |
#ifdef JS_DEBUG_TITLE_LOCKS |
100 |
const char *file[4]; /* file where lock was (re-)taken */ |
101 |
unsigned int line[4]; /* line where lock was (re-)taken */ |
102 |
#endif |
103 |
}; |
104 |
|
105 |
/* |
106 |
* Title structure is always allocated as a field of JSScope. |
107 |
*/ |
108 |
#define TITLE_TO_SCOPE(title) \ |
109 |
((JSScope *)((uint8 *) (title) - offsetof(JSScope, title))) |
110 |
|
111 |
/* |
112 |
* Atomic increment and decrement for a reference counter, given jsrefcount *p. |
113 |
* NB: jsrefcount is int32, aka PRInt32, so that pratom.h functions work. |
114 |
*/ |
115 |
#define JS_ATOMIC_INCREMENT(p) PR_AtomicIncrement((PRInt32 *)(p)) |
116 |
#define JS_ATOMIC_DECREMENT(p) PR_AtomicDecrement((PRInt32 *)(p)) |
117 |
#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v)) |
118 |
#define JS_ATOMIC_SET(p,v) PR_AtomicSet((PRInt32 *)(p), (PRInt32)(v)) |
119 |
|
120 |
#define js_CurrentThreadId() (jsword)PR_GetCurrentThread() |
121 |
#define JS_NEW_LOCK() PR_NewLock() |
122 |
#define JS_DESTROY_LOCK(l) PR_DestroyLock(l) |
123 |
#define JS_ACQUIRE_LOCK(l) PR_Lock(l) |
124 |
#define JS_RELEASE_LOCK(l) PR_Unlock(l) |
125 |
|
126 |
#define JS_NEW_CONDVAR(l) PR_NewCondVar(l) |
127 |
#define JS_DESTROY_CONDVAR(cv) PR_DestroyCondVar(cv) |
128 |
#define JS_WAIT_CONDVAR(cv,to) PR_WaitCondVar(cv,to) |
129 |
#define JS_NO_TIMEOUT PR_INTERVAL_NO_TIMEOUT |
130 |
#define JS_NOTIFY_CONDVAR(cv) PR_NotifyCondVar(cv) |
131 |
#define JS_NOTIFY_ALL_CONDVAR(cv) PR_NotifyAllCondVar(cv) |
132 |
|
133 |
#ifdef JS_DEBUG_TITLE_LOCKS |
134 |
|
135 |
#define JS_SET_OBJ_INFO(obj_, file_, line_) \ |
136 |
JS_SET_SCOPE_INFO(OBJ_SCOPE(obj_), file_, line_) |
137 |
|
138 |
#define JS_SET_SCOPE_INFO(scope_, file_, line_) \ |
139 |
js_SetScopeInfo(scope_, file_, line_) |
140 |
|
141 |
#endif |
142 |
|
143 |
#define JS_LOCK(cx, tl) js_Lock(cx, tl) |
144 |
#define JS_UNLOCK(cx, tl) js_Unlock(cx, tl) |
145 |
|
146 |
#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt) |
147 |
#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt) |
148 |
|
149 |
/* |
150 |
* NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects |
151 |
* (objects for which OBJ_IS_NATIVE returns true). All uses of these macros in |
152 |
* the engine are predicated on OBJ_IS_NATIVE or equivalent checks. These uses |
153 |
* are for optimizations above the JSObjectOps layer, under which object locks |
154 |
* normally hide. |
155 |
*/ |
156 |
#define JS_LOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \ |
157 |
? (void)0 \ |
158 |
: (js_LockObj(cx, obj), \ |
159 |
JS_SET_OBJ_INFO(obj,__FILE__,__LINE__))) |
160 |
#define JS_UNLOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \ |
161 |
? (void)0 : js_UnlockObj(cx, obj)) |
162 |
|
163 |
#define JS_LOCK_TITLE(cx,title) \ |
164 |
((title)->ownercx == (cx) ? (void)0 \ |
165 |
: (js_LockTitle(cx, (title)), \ |
166 |
JS_SET_TITLE_INFO(title,__FILE__,__LINE__))) |
167 |
|
168 |
#define JS_UNLOCK_TITLE(cx,title) ((title)->ownercx == (cx) ? (void)0 \ |
169 |
: js_UnlockTitle(cx, title)) |
170 |
|
171 |
#define JS_LOCK_SCOPE(cx,scope) JS_LOCK_TITLE(cx,&(scope)->title) |
172 |
#define JS_UNLOCK_SCOPE(cx,scope) JS_UNLOCK_TITLE(cx,&(scope)->title) |
173 |
|
174 |
#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \ |
175 |
js_TransferTitle(cx, &scope->title, &newscope->title) |
176 |
|
177 |
|
178 |
extern void js_Lock(JSContext *cx, JSThinLock *tl); |
179 |
extern void js_Unlock(JSContext *cx, JSThinLock *tl); |
180 |
extern void js_LockRuntime(JSRuntime *rt); |
181 |
extern void js_UnlockRuntime(JSRuntime *rt); |
182 |
extern void js_LockObj(JSContext *cx, JSObject *obj); |
183 |
extern void js_UnlockObj(JSContext *cx, JSObject *obj); |
184 |
extern void js_InitTitle(JSContext *cx, JSTitle *title); |
185 |
extern void js_FinishTitle(JSContext *cx, JSTitle *title); |
186 |
extern void js_LockTitle(JSContext *cx, JSTitle *title); |
187 |
extern void js_UnlockTitle(JSContext *cx, JSTitle *title); |
188 |
extern int js_SetupLocks(int,int); |
189 |
extern void js_CleanupLocks(); |
190 |
extern void js_TransferTitle(JSContext *, JSTitle *, JSTitle *); |
191 |
extern JS_FRIEND_API(jsval) |
192 |
js_GetSlotThreadSafe(JSContext *, JSObject *, uint32); |
193 |
extern void js_SetSlotThreadSafe(JSContext *, JSObject *, uint32, jsval); |
194 |
extern void js_InitLock(JSThinLock *); |
195 |
extern void js_FinishLock(JSThinLock *); |
196 |
|
197 |
/* |
198 |
* This function must be called with the GC lock held. |
199 |
*/ |
200 |
extern void |
201 |
js_ShareWaitingTitles(JSContext *cx); |
202 |
|
203 |
extern void |
204 |
js_NudgeOtherContexts(JSContext *cx); |
205 |
|
206 |
#ifdef DEBUG |
207 |
|
208 |
#define JS_IS_RUNTIME_LOCKED(rt) js_IsRuntimeLocked(rt) |
209 |
#define JS_IS_OBJ_LOCKED(cx,obj) js_IsObjLocked(cx,obj) |
210 |
#define JS_IS_TITLE_LOCKED(cx,title) js_IsTitleLocked(cx,title) |
211 |
|
212 |
extern JSBool js_IsRuntimeLocked(JSRuntime *rt); |
213 |
extern JSBool js_IsObjLocked(JSContext *cx, JSObject *obj); |
214 |
extern JSBool js_IsTitleLocked(JSContext *cx, JSTitle *title); |
215 |
#ifdef JS_DEBUG_TITLE_LOCKS |
216 |
extern void js_SetScopeInfo(JSScope *scope, const char *file, int line); |
217 |
#endif |
218 |
|
219 |
#else |
220 |
|
221 |
#define JS_IS_RUNTIME_LOCKED(rt) 0 |
222 |
#define JS_IS_OBJ_LOCKED(cx,obj) 1 |
223 |
#define JS_IS_TITLE_LOCKED(cx,title) 1 |
224 |
|
225 |
#endif /* DEBUG */ |
226 |
|
227 |
#define JS_LOCK_OBJ_VOID(cx, obj, e) \ |
228 |
JS_BEGIN_MACRO \ |
229 |
JS_LOCK_OBJ(cx, obj); \ |
230 |
e; \ |
231 |
JS_UNLOCK_OBJ(cx, obj); \ |
232 |
JS_END_MACRO |
233 |
|
234 |
#define JS_LOCK_VOID(cx, e) \ |
235 |
JS_BEGIN_MACRO \ |
236 |
JSRuntime *_rt = (cx)->runtime; \ |
237 |
JS_LOCK_RUNTIME_VOID(_rt, e); \ |
238 |
JS_END_MACRO |
239 |
|
240 |
#else /* !JS_THREADSAFE */ |
241 |
|
242 |
#define JS_ATOMIC_INCREMENT(p) (++*(p)) |
243 |
#define JS_ATOMIC_DECREMENT(p) (--*(p)) |
244 |
#define JS_ATOMIC_ADD(p,v) (*(p) += (v)) |
245 |
#define JS_ATOMIC_SET(p,v) (*(p) = (v)) |
246 |
|
247 |
#define JS_CurrentThreadId() 0 |
248 |
#define JS_NEW_LOCK() NULL |
249 |
#define JS_DESTROY_LOCK(l) ((void)0) |
250 |
#define JS_ACQUIRE_LOCK(l) ((void)0) |
251 |
#define JS_RELEASE_LOCK(l) ((void)0) |
252 |
#define JS_LOCK(cx, tl) ((void)0) |
253 |
#define JS_UNLOCK(cx, tl) ((void)0) |
254 |
|
255 |
#define JS_NEW_CONDVAR(l) NULL |
256 |
#define JS_DESTROY_CONDVAR(cv) ((void)0) |
257 |
#define JS_WAIT_CONDVAR(cv,to) ((void)0) |
258 |
#define JS_NOTIFY_CONDVAR(cv) ((void)0) |
259 |
#define JS_NOTIFY_ALL_CONDVAR(cv) ((void)0) |
260 |
|
261 |
#define JS_LOCK_RUNTIME(rt) ((void)0) |
262 |
#define JS_UNLOCK_RUNTIME(rt) ((void)0) |
263 |
#define JS_LOCK_OBJ(cx,obj) ((void)0) |
264 |
#define JS_UNLOCK_OBJ(cx,obj) ((void)0) |
265 |
#define JS_LOCK_OBJ_VOID(cx,obj,e) (e) |
266 |
#define JS_LOCK_SCOPE(cx,scope) ((void)0) |
267 |
#define JS_UNLOCK_SCOPE(cx,scope) ((void)0) |
268 |
#define JS_TRANSFER_SCOPE_LOCK(c,o,n) ((void)0) |
269 |
|
270 |
#define JS_IS_RUNTIME_LOCKED(rt) 1 |
271 |
#define JS_IS_OBJ_LOCKED(cx,obj) 1 |
272 |
#define JS_IS_TITLE_LOCKED(cx,title) 1 |
273 |
#define JS_LOCK_VOID(cx, e) JS_LOCK_RUNTIME_VOID((cx)->runtime, e) |
274 |
|
275 |
#endif /* !JS_THREADSAFE */ |
276 |
|
277 |
#define JS_LOCK_RUNTIME_VOID(rt,e) \ |
278 |
JS_BEGIN_MACRO \ |
279 |
JS_LOCK_RUNTIME(rt); \ |
280 |
e; \ |
281 |
JS_UNLOCK_RUNTIME(rt); \ |
282 |
JS_END_MACRO |
283 |
|
284 |
#define JS_LOCK_GC(rt) JS_ACQUIRE_LOCK((rt)->gcLock) |
285 |
#define JS_UNLOCK_GC(rt) JS_RELEASE_LOCK((rt)->gcLock) |
286 |
#define JS_LOCK_GC_VOID(rt,e) (JS_LOCK_GC(rt), (e), JS_UNLOCK_GC(rt)) |
287 |
#define JS_AWAIT_GC_DONE(rt) JS_WAIT_CONDVAR((rt)->gcDone, JS_NO_TIMEOUT) |
288 |
#define JS_NOTIFY_GC_DONE(rt) JS_NOTIFY_ALL_CONDVAR((rt)->gcDone) |
289 |
#define JS_AWAIT_REQUEST_DONE(rt) JS_WAIT_CONDVAR((rt)->requestDone, \ |
290 |
JS_NO_TIMEOUT) |
291 |
#define JS_NOTIFY_REQUEST_DONE(rt) JS_NOTIFY_CONDVAR((rt)->requestDone) |
292 |
|
293 |
#ifndef JS_SET_OBJ_INFO |
294 |
#define JS_SET_OBJ_INFO(obj,f,l) ((void)0) |
295 |
#endif |
296 |
#ifndef JS_SET_TITLE_INFO |
297 |
#define JS_SET_TITLE_INFO(title,f,l) ((void)0) |
298 |
#endif |
299 |
|
300 |
#ifdef JS_THREADSAFE |
301 |
|
302 |
extern JSBool |
303 |
js_CompareAndSwap(jsword *w, jsword ov, jsword nv); |
304 |
|
305 |
/* Atomically bitwise-or the mask into the word *w using compare and swap. */ |
306 |
extern void |
307 |
js_AtomicSetMask(jsword *w, jsword mask); |
308 |
|
309 |
#define JS_ATOMIC_SET_MASK(w, mask) js_AtomicSetMask(w, mask) |
310 |
|
311 |
#else |
312 |
|
313 |
static inline JSBool |
314 |
js_CompareAndSwap(jsword *w, jsword ov, jsword nv) |
315 |
{ |
316 |
return (*w == ov) ? *w = nv, JS_TRUE : JS_FALSE; |
317 |
} |
318 |
|
319 |
#define JS_ATOMIC_SET_MASK(w, mask) (*(w) |= (mask)) |
320 |
|
321 |
#endif /* JS_THREADSAFE */ |
322 |
|
323 |
JS_END_EXTERN_C |
324 |
|
325 |
#endif /* jslock_h___ */ |