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