1 /************************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice (including the next
12 paragraph) shall be included in all copies or substantial portions of the
13 Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22
23 ********************************************************/
24
25 /*
26
27 Copyright 1994, 1998 The Open Group
28
29 Permission to use, copy, modify, distribute, and sell this software and its
30 documentation for any purpose is hereby granted without fee, provided that
31 the above copyright notice appear in all copies and that both that
32 copyright notice and this permission notice appear in supporting
33 documentation.
34
35 The above copyright notice and this permission notice shall be included in
36 all copies or substantial portions of the Software.
37
38 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
42 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
43 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44
45 Except as contained in this notice, the name of The Open Group shall not be
46 used in advertising or otherwise to promote the sale, use or other dealings
47 in this Software without prior written authorization from The Open Group.
48
49 */
50
51 #ifdef HAVE_CONFIG_H
52 #include <config.h>
53 #endif
54 #include "IntrinsicI.h"
55
56 #ifdef XTHREADS
57
58 #define xmalloc __XtMalloc
59 #define xfree XtFree
60 #include <X11/Xthreads.h>
61
62 #ifndef NDEBUG
63 #define NDEBUG
64 #endif
65 #include <assert.h>
66 #include <stdio.h>
67
68 typedef struct _ThreadStack {
69 unsigned int size;
70 int sp;
71 struct _Tstack {
72 xthread_t t;
73 xcondition_t c;
74 } *st;
75 } ThreadStack;
76
77 typedef struct _LockRec {
78 xmutex_t mutex;
79 int level;
80 ThreadStack stack;
81 #ifndef _XMUTEX_NESTS
82 xthread_t holder;
83 xcondition_t cond;
84 #endif
85 } LockRec;
86
87 #define STACK_INCR 16
88
89 static LockPtr process_lock = NULL;
90
91 static void
InitProcessLock(void)92 InitProcessLock(void)
93 {
94 if (!process_lock) {
95 process_lock = XtNew(LockRec);
96 process_lock->mutex = xmutex_malloc();
97 xmutex_init(process_lock->mutex);
98 process_lock->level = 0;
99 #ifndef _XMUTEX_NESTS
100 process_lock->cond = xcondition_malloc();
101 xcondition_init(process_lock->cond);
102 xthread_clear_id(process_lock->holder);
103 #endif
104 }
105 }
106
107 static void
ProcessLock(void)108 ProcessLock(void)
109 {
110 #ifdef _XMUTEX_NESTS
111 xmutex_lock(process_lock->mutex);
112 process_lock->level++;
113 #else
114 xthread_t this_thread = xthread_self();
115
116 xmutex_lock(process_lock->mutex);
117
118 if (!xthread_have_id(process_lock->holder)) {
119 process_lock->holder = this_thread;
120 xmutex_unlock(process_lock->mutex);
121 return;
122 }
123
124 if (xthread_equal(process_lock->holder, this_thread)) {
125 process_lock->level++;
126 xmutex_unlock(process_lock->mutex);
127 return;
128 }
129
130 while (xthread_have_id(process_lock->holder))
131 xcondition_wait(process_lock->cond, process_lock->mutex);
132
133 process_lock->holder = this_thread;
134 assert(xthread_equal(process_lock->holder, this_thread));
135 xmutex_unlock(process_lock->mutex);
136 #endif
137 }
138
139 static void
ProcessUnlock(void)140 ProcessUnlock(void)
141 {
142 #ifdef _XMUTEX_NESTS
143 process_lock->level--;
144 xmutex_unlock(process_lock->mutex);
145 #else
146 xmutex_lock(process_lock->mutex);
147 assert(xthread_equal(process_lock->holder, xthread_self()));
148 if (process_lock->level != 0) {
149 process_lock->level--;
150 xmutex_unlock(process_lock->mutex);
151 return;
152 }
153
154 xthread_clear_id(process_lock->holder);
155 xcondition_signal(process_lock->cond);
156
157 xmutex_unlock(process_lock->mutex);
158 #endif
159 }
160
161 static void
AppLock(XtAppContext app)162 AppLock(XtAppContext app)
163 {
164 LockPtr app_lock = app->lock_info;
165
166 #ifdef _XMUTEX_NESTS
167 xmutex_lock(app_lock->mutex);
168 app_lock->level++;
169 #else
170 xthread_t self = xthread_self();
171
172 xmutex_lock(app_lock->mutex);
173 if (!xthread_have_id(app_lock->holder)) {
174 app_lock->holder = self;
175 assert(xthread_equal(app_lock->holder, self));
176 xmutex_unlock(app_lock->mutex);
177 return;
178 }
179 if (xthread_equal(app_lock->holder, self)) {
180 app_lock->level++;
181 xmutex_unlock(app_lock->mutex);
182 return;
183 }
184 while (xthread_have_id(app_lock->holder)) {
185 xcondition_wait(app_lock->cond, app_lock->mutex);
186 }
187 app_lock->holder = self;
188 assert(xthread_equal(app_lock->holder, self));
189 xmutex_unlock(app_lock->mutex);
190 #endif
191 }
192
193 static void
AppUnlock(XtAppContext app)194 AppUnlock(XtAppContext app)
195 {
196 LockPtr app_lock = app->lock_info;
197
198 #ifdef _XMUTEX_NESTS
199 app_lock->level--;
200 xmutex_unlock(app_lock->mutex);
201 #else
202 xthread_t self;
203
204 self = xthread_self();
205 (void) self;
206
207 xmutex_lock(app_lock->mutex);
208 assert(xthread_equal(app_lock->holder, self));
209 if (app_lock->level != 0) {
210 app_lock->level--;
211 xmutex_unlock(app_lock->mutex);
212 return;
213 }
214 xthread_clear_id(app_lock->holder);
215 xcondition_signal(app_lock->cond);
216 xmutex_unlock(app_lock->mutex);
217 #endif
218 }
219
220 static void
YieldAppLock(XtAppContext app,Boolean * push_thread,Boolean * pushed_thread,int * level)221 YieldAppLock(XtAppContext app,
222 Boolean *push_thread,
223 Boolean *pushed_thread,
224 int *level)
225 {
226 LockPtr app_lock = app->lock_info;
227 xthread_t self = xthread_self();
228
229 #ifndef _XMUTEX_NESTS
230 xmutex_lock(app_lock->mutex);
231 assert(xthread_equal(app_lock->holder, self));
232 #endif
233 *level = app_lock->level;
234 if (*push_thread) {
235 *push_thread = FALSE;
236 *pushed_thread = TRUE;
237
238 if (app_lock->stack.sp == (int) app_lock->stack.size - 1) {
239 unsigned ii;
240
241 app_lock->stack.st = (struct _Tstack *)
242 XtRealloc((char *) app_lock->stack.st,
243 (Cardinal) ((app_lock->stack.size +
244 STACK_INCR) * sizeof(struct _Tstack)));
245 ii = app_lock->stack.size;
246 app_lock->stack.size += STACK_INCR;
247 for (; ii < app_lock->stack.size; ii++) {
248 app_lock->stack.st[ii].c = xcondition_malloc();
249 xcondition_init(app_lock->stack.st[ii].c);
250 }
251 }
252 app_lock->stack.st[++(app_lock->stack.sp)].t = self;
253 }
254 #ifdef _XMUTEX_NESTS
255 while (app_lock->level > 0) {
256 app_lock->level--;
257 xmutex_unlock(app_lock->mutex);
258 }
259 #else
260 xcondition_signal(app_lock->cond);
261 app_lock->level = 0;
262 xthread_clear_id(app_lock->holder);
263 xmutex_unlock(app_lock->mutex);
264 #endif
265 }
266
267 static void
RestoreAppLock(XtAppContext app,int level,Boolean * pushed_thread)268 RestoreAppLock(XtAppContext app, int level, Boolean *pushed_thread)
269 {
270 LockPtr app_lock = app->lock_info;
271 xthread_t self = xthread_self();
272
273 xmutex_lock(app_lock->mutex);
274 #ifdef _XMUTEX_NESTS
275 app_lock->level++;
276 #else
277 while (xthread_have_id(app_lock->holder)) {
278 xcondition_wait(app_lock->cond, app_lock->mutex);
279 }
280 #endif
281 if (!xthread_equal(app_lock->stack.st[app_lock->stack.sp].t, self)) {
282 int ii;
283
284 for (ii = app_lock->stack.sp - 1; ii >= 0; ii--) {
285 if (xthread_equal(app_lock->stack.st[ii].t, self)) {
286 xcondition_wait(app_lock->stack.st[ii].c, app_lock->mutex);
287 break;
288 }
289 }
290 #ifndef _XMUTEX_NESTS
291 while (xthread_have_id(app_lock->holder)) {
292 xcondition_wait(app_lock->cond, app_lock->mutex);
293 }
294 #endif
295 }
296 #ifdef _XMUTEX_NESTS
297 while (app_lock->level < level) {
298 xmutex_lock(app_lock->mutex);
299 app_lock->level++;
300 }
301 #else
302 app_lock->holder = self;
303 app_lock->level = level;
304 assert(xthread_equal(app_lock->holder, self));
305 #endif
306 if (*pushed_thread) {
307 *pushed_thread = FALSE;
308 (app_lock->stack.sp)--;
309 if (app_lock->stack.sp >= 0) {
310 xcondition_signal(app_lock->stack.st[app_lock->stack.sp].c);
311 }
312 }
313 #ifndef _XMUTEX_NESTS
314 xmutex_unlock(app_lock->mutex);
315 #endif
316 }
317
318 static void
FreeAppLock(XtAppContext app)319 FreeAppLock(XtAppContext app)
320 {
321 unsigned ii;
322 LockPtr app_lock = app->lock_info;
323
324 if (app_lock) {
325 xmutex_clear(app_lock->mutex);
326 xmutex_free(app_lock->mutex);
327 #ifndef _XMUTEX_NESTS
328 xcondition_clear(app_lock->cond);
329 xcondition_free(app_lock->cond);
330 #endif
331 if (app_lock->stack.st != (struct _Tstack *) NULL) {
332 for (ii = 0; ii < app_lock->stack.size; ii++) {
333 xcondition_clear(app_lock->stack.st[ii].c);
334 xcondition_free(app_lock->stack.st[ii].c);
335 }
336 XtFree((char *) app_lock->stack.st);
337 }
338 XtFree((char *) app_lock);
339 app->lock_info = NULL;
340 }
341 }
342
343 static void
InitAppLock(XtAppContext app)344 InitAppLock(XtAppContext app)
345 {
346 int ii;
347 LockPtr app_lock;
348
349 app->lock = AppLock;
350 app->unlock = AppUnlock;
351 app->yield_lock = YieldAppLock;
352 app->restore_lock = RestoreAppLock;
353 app->free_lock = FreeAppLock;
354
355 app_lock = app->lock_info = XtNew(LockRec);
356 app_lock->mutex = xmutex_malloc();
357 xmutex_init(app_lock->mutex);
358 app_lock->level = 0;
359 #ifndef _XMUTEX_NESTS
360 app_lock->cond = xcondition_malloc();
361 xcondition_init(app_lock->cond);
362 xthread_clear_id(app_lock->holder);
363 #endif
364 app_lock->stack.size = STACK_INCR;
365 app_lock->stack.sp = -1;
366 app_lock->stack.st =
367 (struct _Tstack *) __XtMalloc(sizeof(struct _Tstack) * STACK_INCR);
368 for (ii = 0; ii < STACK_INCR; ii++) {
369 app_lock->stack.st[ii].c = xcondition_malloc();
370 xcondition_init(app_lock->stack.st[ii].c);
371 }
372 }
373
374 #endif /* defined(XTHREADS) */
375
376 void
XtAppLock(XtAppContext app)377 XtAppLock(XtAppContext app)
378 {
379 #ifdef XTHREADS
380 if (app->lock)
381 (*app->lock) (app);
382 #endif
383 }
384
385 void
XtAppUnlock(XtAppContext app)386 XtAppUnlock(XtAppContext app)
387 {
388 #ifdef XTHREADS
389 if (app->unlock)
390 (*app->unlock) (app);
391 #endif
392 }
393
394 void
XtProcessLock(void)395 XtProcessLock(void)
396 {
397 #ifdef XTHREADS
398 if (_XtProcessLock)
399 (*_XtProcessLock) ();
400 #endif
401 }
402
403 void
XtProcessUnlock(void)404 XtProcessUnlock(void)
405 {
406 #ifdef XTHREADS
407 if (_XtProcessUnlock)
408 (*_XtProcessUnlock) ();
409 #endif
410 }
411
412 Boolean
XtToolkitThreadInitialize(void)413 XtToolkitThreadInitialize(void)
414 {
415 #ifdef XTHREADS
416 if (_XtProcessLock == NULL) {
417 #ifdef xthread_init
418 xthread_init();
419 #endif
420 InitProcessLock();
421 _XtProcessLock = ProcessLock;
422 _XtProcessUnlock = ProcessUnlock;
423 _XtInitAppLock = InitAppLock;
424 }
425 return True;
426 #else
427 return False;
428 #endif
429 }
430