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(_WIN64) && (defined(_M_AMD64) || defined(_M_X64))) || \ |
59 |
(defined(__i386) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ |
60 |
(defined(__x86_64) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ |
61 |
(defined(__sparc) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ |
62 |
defined(AIX) || \ |
63 |
defined(USE_ARM_KUSER) |
64 |
# define JS_HAS_NATIVE_COMPARE_AND_SWAP 1 |
65 |
#else |
66 |
# define JS_HAS_NATIVE_COMPARE_AND_SWAP 0 |
67 |
#endif |
68 |
|
69 |
#if defined(JS_USE_ONLY_NSPR_LOCKS) || !JS_HAS_NATIVE_COMPARE_AND_SWAP |
70 |
# define NSPR_LOCK 1 |
71 |
#else |
72 |
# undef NSPR_LOCK |
73 |
#endif |
74 |
|
75 |
#define Thin_GetWait(W) ((jsword)(W) & 0x1) |
76 |
#define Thin_SetWait(W) ((jsword)(W) | 0x1) |
77 |
#define Thin_RemoveWait(W) ((jsword)(W) & ~0x1) |
78 |
|
79 |
typedef struct JSFatLock JSFatLock; |
80 |
|
81 |
typedef struct JSThinLock { |
82 |
jsword owner; |
83 |
JSFatLock *fat; |
84 |
} JSThinLock; |
85 |
|
86 |
#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread) |
87 |
#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId()) |
88 |
|
89 |
typedef PRLock JSLock; |
90 |
|
91 |
typedef struct JSTitle JSTitle; |
92 |
|
93 |
struct JSTitle { |
94 |
JSContext *ownercx; /* creating context, NULL if shared */ |
95 |
JSThinLock lock; /* binary semaphore protecting title */ |
96 |
union { /* union lockful and lock-free state: */ |
97 |
jsrefcount count; /* lock entry count for reentrancy */ |
98 |
JSTitle *link; /* next link in rt->titleSharingTodo */ |
99 |
} u; |
100 |
#ifdef JS_DEBUG_TITLE_LOCKS |
101 |
const char *file[4]; /* file where lock was (re-)taken */ |
102 |
unsigned int line[4]; /* line where lock was (re-)taken */ |
103 |
#endif |
104 |
}; |
105 |
|
106 |
/* |
107 |
* Title structure is always allocated as a field of JSScope. |
108 |
*/ |
109 |
#define TITLE_TO_SCOPE(title) \ |
110 |
((JSScope *)((uint8 *) (title) - offsetof(JSScope, title))) |
111 |
|
112 |
/* |
113 |
* Atomic increment and decrement for a reference counter, given jsrefcount *p. |
114 |
* NB: jsrefcount is int32, aka PRInt32, so that pratom.h functions work. |
115 |
*/ |
116 |
#define JS_ATOMIC_INCREMENT(p) PR_AtomicIncrement((PRInt32 *)(p)) |
117 |
#define JS_ATOMIC_DECREMENT(p) PR_AtomicDecrement((PRInt32 *)(p)) |
118 |
#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v)) |
119 |
#define JS_ATOMIC_SET(p,v) PR_AtomicSet((PRInt32 *)(p), (PRInt32)(v)) |
120 |
|
121 |
#define js_CurrentThreadId() (jsword)PR_GetCurrentThread() |
122 |
#define JS_NEW_LOCK() PR_NewLock() |
123 |
#define JS_DESTROY_LOCK(l) PR_DestroyLock(l) |
124 |
#define JS_ACQUIRE_LOCK(l) PR_Lock(l) |
125 |
#define JS_RELEASE_LOCK(l) PR_Unlock(l) |
126 |
|
127 |
#define JS_NEW_CONDVAR(l) PR_NewCondVar(l) |
128 |
#define JS_DESTROY_CONDVAR(cv) PR_DestroyCondVar(cv) |
129 |
#define JS_WAIT_CONDVAR(cv,to) PR_WaitCondVar(cv,to) |
130 |
#define JS_NO_TIMEOUT PR_INTERVAL_NO_TIMEOUT |
131 |
#define JS_NOTIFY_CONDVAR(cv) PR_NotifyCondVar(cv) |
132 |
#define JS_NOTIFY_ALL_CONDVAR(cv) PR_NotifyAllCondVar(cv) |
133 |
|
134 |
#ifdef JS_DEBUG_TITLE_LOCKS |
135 |
|
136 |
#define JS_SET_OBJ_INFO(obj_, file_, line_) \ |
137 |
JS_SET_SCOPE_INFO(OBJ_SCOPE(obj_), file_, line_) |
138 |
|
139 |
#define JS_SET_SCOPE_INFO(scope_, file_, line_) \ |
140 |
js_SetScopeInfo(scope_, file_, line_) |
141 |
|
142 |
#endif |
143 |
|
144 |
#define JS_LOCK(cx, tl) js_Lock(cx, tl) |
145 |
#define JS_UNLOCK(cx, tl) js_Unlock(cx, tl) |
146 |
|
147 |
#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt) |
148 |
#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt) |
149 |
|
150 |
/* |
151 |
* NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects |
152 |
* (objects for which OBJ_IS_NATIVE returns true). All uses of these macros in |
153 |
* the engine are predicated on OBJ_IS_NATIVE or equivalent checks. These uses |
154 |
* are for optimizations above the JSObjectOps layer, under which object locks |
155 |
* normally hide. |
156 |
*/ |
157 |
#define JS_LOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \ |
158 |
? (void)0 \ |
159 |
: (js_LockObj(cx, obj), \ |
160 |
JS_SET_OBJ_INFO(obj,__FILE__,__LINE__))) |
161 |
#define JS_UNLOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \ |
162 |
? (void)0 : js_UnlockObj(cx, obj)) |
163 |
|
164 |
/* |
165 |
* Lock object only if its scope has the given shape. |
166 |
*/ |
167 |
#define JS_LOCK_OBJ_IF_SHAPE(cx,obj,shape) \ |
168 |
(OBJ_SHAPE(obj) == (shape) \ |
169 |
? (OBJ_SCOPE(obj)->title.ownercx == (cx) \ |
170 |
? true \ |
171 |
: js_LockObjIfShape(cx, obj, shape)) \ |
172 |
: false) |
173 |
|
174 |
#define JS_LOCK_TITLE(cx,title) \ |
175 |
((title)->ownercx == (cx) ? (void)0 \ |
176 |
: (js_LockTitle(cx, (title)), \ |
177 |
JS_SET_TITLE_INFO(title,__FILE__,__LINE__))) |
178 |
|
179 |
#define JS_UNLOCK_TITLE(cx,title) ((title)->ownercx == (cx) ? (void)0 \ |
180 |
: js_UnlockTitle(cx, title)) |
181 |
|
182 |
#define JS_LOCK_SCOPE(cx,scope) JS_LOCK_TITLE(cx,&(scope)->title) |
183 |
#define JS_UNLOCK_SCOPE(cx,scope) JS_UNLOCK_TITLE(cx,&(scope)->title) |
184 |
|
185 |
#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \ |
186 |
js_TransferTitle(cx, &scope->title, &newscope->title) |
187 |
|
188 |
|
189 |
extern void js_Lock(JSContext *cx, JSThinLock *tl); |
190 |
extern void js_Unlock(JSContext *cx, JSThinLock *tl); |
191 |
extern void js_LockRuntime(JSRuntime *rt); |
192 |
extern void js_UnlockRuntime(JSRuntime *rt); |
193 |
extern void js_LockObj(JSContext *cx, JSObject *obj); |
194 |
extern void js_UnlockObj(JSContext *cx, JSObject *obj); |
195 |
#ifdef __cplusplus /* Allow inclusion from LiveConnect C files. */ |
196 |
extern bool js_LockObjIfShape(JSContext *cx, JSObject *obj, uint32 shape); |
197 |
#else |
198 |
extern JSBool js_LockObjIfShape(JSContext *cx, JSObject *obj, uint32 shape); |
199 |
#endif |
200 |
extern void js_InitTitle(JSContext *cx, JSTitle *title); |
201 |
extern void js_FinishTitle(JSContext *cx, JSTitle *title); |
202 |
extern void js_LockTitle(JSContext *cx, JSTitle *title); |
203 |
extern void js_UnlockTitle(JSContext *cx, JSTitle *title); |
204 |
extern int js_SetupLocks(int,int); |
205 |
extern void js_CleanupLocks(); |
206 |
extern void js_TransferTitle(JSContext *, JSTitle *, JSTitle *); |
207 |
extern JS_FRIEND_API(jsval) |
208 |
js_GetSlotThreadSafe(JSContext *, JSObject *, uint32); |
209 |
extern void js_SetSlotThreadSafe(JSContext *, JSObject *, uint32, jsval); |
210 |
extern void js_InitLock(JSThinLock *); |
211 |
extern void js_FinishLock(JSThinLock *); |
212 |
|
213 |
/* |
214 |
* This function must be called with the GC lock held. |
215 |
*/ |
216 |
extern void |
217 |
js_ShareWaitingTitles(JSContext *cx); |
218 |
|
219 |
extern void |
220 |
js_NudgeOtherContexts(JSContext *cx); |
221 |
|
222 |
#ifdef DEBUG |
223 |
|
224 |
#define JS_IS_RUNTIME_LOCKED(rt) js_IsRuntimeLocked(rt) |
225 |
#define JS_IS_OBJ_LOCKED(cx,obj) js_IsObjLocked(cx,obj) |
226 |
#define JS_IS_TITLE_LOCKED(cx,title) js_IsTitleLocked(cx,title) |
227 |
|
228 |
extern JSBool js_IsRuntimeLocked(JSRuntime *rt); |
229 |
extern JSBool js_IsObjLocked(JSContext *cx, JSObject *obj); |
230 |
extern JSBool js_IsTitleLocked(JSContext *cx, JSTitle *title); |
231 |
#ifdef JS_DEBUG_TITLE_LOCKS |
232 |
extern void js_SetScopeInfo(JSScope *scope, const char *file, int line); |
233 |
#endif |
234 |
|
235 |
#else |
236 |
|
237 |
#define JS_IS_RUNTIME_LOCKED(rt) 0 |
238 |
#define JS_IS_OBJ_LOCKED(cx,obj) 1 |
239 |
#define JS_IS_TITLE_LOCKED(cx,title) 1 |
240 |
|
241 |
#endif /* DEBUG */ |
242 |
|
243 |
#else /* !JS_THREADSAFE */ |
244 |
|
245 |
#define JS_ATOMIC_INCREMENT(p) (++*(p)) |
246 |
#define JS_ATOMIC_DECREMENT(p) (--*(p)) |
247 |
#define JS_ATOMIC_ADD(p,v) (*(p) += (v)) |
248 |
#define JS_ATOMIC_SET(p,v) (*(p) = (v)) |
249 |
|
250 |
#define JS_CurrentThreadId() 0 |
251 |
#define JS_NEW_LOCK() NULL |
252 |
#define JS_DESTROY_LOCK(l) ((void)0) |
253 |
#define JS_ACQUIRE_LOCK(l) ((void)0) |
254 |
#define JS_RELEASE_LOCK(l) ((void)0) |
255 |
#define JS_LOCK(cx, tl) ((void)0) |
256 |
#define JS_UNLOCK(cx, tl) ((void)0) |
257 |
|
258 |
#define JS_NEW_CONDVAR(l) NULL |
259 |
#define JS_DESTROY_CONDVAR(cv) ((void)0) |
260 |
#define JS_WAIT_CONDVAR(cv,to) ((void)0) |
261 |
#define JS_NOTIFY_CONDVAR(cv) ((void)0) |
262 |
#define JS_NOTIFY_ALL_CONDVAR(cv) ((void)0) |
263 |
|
264 |
#define JS_LOCK_RUNTIME(rt) ((void)0) |
265 |
#define JS_UNLOCK_RUNTIME(rt) ((void)0) |
266 |
#define JS_LOCK_OBJ(cx,obj) ((void)0) |
267 |
#define JS_UNLOCK_OBJ(cx,obj) ((void)0) |
268 |
#define JS_LOCK_OBJ_IF_SHAPE(cx,obj,shape) (OBJ_SHAPE(obj) == (shape)) |
269 |
|
270 |
#define JS_LOCK_OBJ_VOID(cx,obj,e) (e) |
271 |
#define JS_LOCK_SCOPE(cx,scope) ((void)0) |
272 |
#define JS_UNLOCK_SCOPE(cx,scope) ((void)0) |
273 |
#define JS_TRANSFER_SCOPE_LOCK(c,o,n) ((void)0) |
274 |
|
275 |
#define JS_IS_RUNTIME_LOCKED(rt) 1 |
276 |
#define JS_IS_OBJ_LOCKED(cx,obj) 1 |
277 |
#define JS_IS_TITLE_LOCKED(cx,title) 1 |
278 |
|
279 |
#endif /* !JS_THREADSAFE */ |
280 |
|
281 |
#define JS_LOCK_RUNTIME_VOID(rt,e) \ |
282 |
JS_BEGIN_MACRO \ |
283 |
JS_LOCK_RUNTIME(rt); \ |
284 |
e; \ |
285 |
JS_UNLOCK_RUNTIME(rt); \ |
286 |
JS_END_MACRO |
287 |
|
288 |
#define JS_LOCK_GC(rt) JS_ACQUIRE_LOCK((rt)->gcLock) |
289 |
#define JS_UNLOCK_GC(rt) JS_RELEASE_LOCK((rt)->gcLock) |
290 |
#define JS_AWAIT_GC_DONE(rt) JS_WAIT_CONDVAR((rt)->gcDone, JS_NO_TIMEOUT) |
291 |
#define JS_NOTIFY_GC_DONE(rt) JS_NOTIFY_ALL_CONDVAR((rt)->gcDone) |
292 |
#define JS_AWAIT_REQUEST_DONE(rt) JS_WAIT_CONDVAR((rt)->requestDone, \ |
293 |
JS_NO_TIMEOUT) |
294 |
#define JS_NOTIFY_REQUEST_DONE(rt) JS_NOTIFY_CONDVAR((rt)->requestDone) |
295 |
|
296 |
#ifndef JS_SET_OBJ_INFO |
297 |
#define JS_SET_OBJ_INFO(obj,f,l) ((void)0) |
298 |
#endif |
299 |
#ifndef JS_SET_TITLE_INFO |
300 |
#define JS_SET_TITLE_INFO(title,f,l) ((void)0) |
301 |
#endif |
302 |
|
303 |
#ifdef JS_THREADSAFE |
304 |
|
305 |
extern JSBool |
306 |
js_CompareAndSwap(jsword *w, jsword ov, jsword nv); |
307 |
|
308 |
/* Atomically bitwise-or the mask into the word *w using compare and swap. */ |
309 |
extern void |
310 |
js_AtomicSetMask(jsword *w, jsword mask); |
311 |
|
312 |
#define JS_ATOMIC_SET_MASK(w, mask) js_AtomicSetMask(w, mask) |
313 |
|
314 |
#else |
315 |
|
316 |
static inline JSBool |
317 |
js_CompareAndSwap(jsword *w, jsword ov, jsword nv) |
318 |
{ |
319 |
return (*w == ov) ? *w = nv, JS_TRUE : JS_FALSE; |
320 |
} |
321 |
|
322 |
#define JS_ATOMIC_SET_MASK(w, mask) (*(w) |= (mask)) |
323 |
|
324 |
#endif /* JS_THREADSAFE */ |
325 |
|
326 |
JS_END_EXTERN_C |
327 |
|
328 |
#endif /* jslock_h___ */ |