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