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