Threads.c revision 1477040f
1444c061aSmrg/* $Xorg: Threads.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */
2444c061aSmrg
3444c061aSmrg/************************************************************
41477040fSmrgCopyright 1993 Sun Microsystems, Inc.  All rights reserved.
51477040fSmrg
61477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
71477040fSmrgcopy of this software and associated documentation files (the "Software"),
81477040fSmrgto deal in the Software without restriction, including without limitation
91477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
101477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
111477040fSmrgSoftware is furnished to do so, subject to the following conditions:
121477040fSmrg
131477040fSmrgThe above copyright notice and this permission notice (including the next
141477040fSmrgparagraph) shall be included in all copies or substantial portions of the
151477040fSmrgSoftware.
161477040fSmrg
171477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
201477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
211477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
221477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
231477040fSmrgDEALINGS IN THE SOFTWARE.
24444c061aSmrg
25444c061aSmrg********************************************************/
26444c061aSmrg
27444c061aSmrg/*
28444c061aSmrg
29444c061aSmrgCopyright 1994, 1998  The Open Group
30444c061aSmrg
31444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
32444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
33444c061aSmrgthe above copyright notice appear in all copies and that both that
34444c061aSmrgcopyright notice and this permission notice appear in supporting
35444c061aSmrgdocumentation.
36444c061aSmrg
37444c061aSmrgThe above copyright notice and this permission notice shall be included in
38444c061aSmrgall copies or substantial portions of the Software.
39444c061aSmrg
40444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
43444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
44444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
45444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46444c061aSmrg
47444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
48444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
49444c061aSmrgin this Software without prior written authorization from The Open Group.
50444c061aSmrg
51444c061aSmrg*/
52444c061aSmrg/* $XFree86: xc/lib/Xt/Threads.c,v 3.6 2001/12/14 19:56:31 dawes Exp $ */
53444c061aSmrg
54444c061aSmrg#ifdef HAVE_CONFIG_H
55444c061aSmrg#include <config.h>
56444c061aSmrg#endif
57444c061aSmrg#include "IntrinsicI.h"
58444c061aSmrg
59444c061aSmrg#ifdef XTHREADS
60444c061aSmrg
61444c061aSmrg#define xmalloc __XtMalloc
62444c061aSmrg#define xfree XtFree
63444c061aSmrg#include <X11/Xthreads.h>
64444c061aSmrg
65444c061aSmrg#ifndef NDEBUG
66444c061aSmrg#define NDEBUG
67444c061aSmrg#endif
68444c061aSmrg#include <assert.h>
69444c061aSmrg#include <stdio.h>
70444c061aSmrg
71444c061aSmrgtypedef struct _ThreadStack {
72444c061aSmrg    unsigned int size;
73444c061aSmrg    int sp;
74444c061aSmrg    struct _Tstack {
75444c061aSmrg	xthread_t t;
76444c061aSmrg	xcondition_t c;
77444c061aSmrg    } *st;
78444c061aSmrg} ThreadStack;
79444c061aSmrg
80444c061aSmrgtypedef struct _LockRec {
81444c061aSmrg    xmutex_t mutex;
82444c061aSmrg    int level;
83444c061aSmrg    ThreadStack stack;
84444c061aSmrg#ifndef _XMUTEX_NESTS
85444c061aSmrg    xthread_t holder;
86444c061aSmrg    xcondition_t cond;
87444c061aSmrg#endif
88444c061aSmrg} LockRec;
89444c061aSmrg
90444c061aSmrg
91444c061aSmrg#define STACK_INCR 16
92444c061aSmrg
93444c061aSmrgstatic LockPtr process_lock = NULL;
94444c061aSmrg
95444c061aSmrgstatic void
96444c061aSmrgInitProcessLock(void)
97444c061aSmrg{
98444c061aSmrg    if(!process_lock) {
99444c061aSmrg    	process_lock = XtNew(LockRec);
100444c061aSmrg    	process_lock->mutex = xmutex_malloc();
101444c061aSmrg    	xmutex_init(process_lock->mutex);
102444c061aSmrg    	process_lock->level = 0;
103444c061aSmrg#ifndef _XMUTEX_NESTS
104444c061aSmrg    	process_lock->cond = xcondition_malloc();
105444c061aSmrg    	xcondition_init(process_lock->cond);
106444c061aSmrg    	xthread_clear_id(process_lock->holder);
107444c061aSmrg#endif
108444c061aSmrg    }
109444c061aSmrg}
110444c061aSmrg
111444c061aSmrgstatic void
112444c061aSmrgProcessLock(void)
113444c061aSmrg{
114444c061aSmrg#ifdef _XMUTEX_NESTS
115444c061aSmrg    xmutex_lock(process_lock->mutex);
116444c061aSmrg    process_lock->level++;
117444c061aSmrg#else
118444c061aSmrg    xthread_t this_thread = xthread_self();
119444c061aSmrg
120444c061aSmrg    xmutex_lock(process_lock->mutex);
121444c061aSmrg
122444c061aSmrg    if (!xthread_have_id(process_lock->holder)) {
123444c061aSmrg	process_lock->holder = this_thread;
124444c061aSmrg	xmutex_unlock(process_lock->mutex);
125444c061aSmrg	return;
126444c061aSmrg    }
127444c061aSmrg
128444c061aSmrg    if (xthread_equal(process_lock->holder,this_thread)) {
129444c061aSmrg	process_lock->level++;
130444c061aSmrg	xmutex_unlock(process_lock->mutex);
131444c061aSmrg	return;
132444c061aSmrg    }
133444c061aSmrg
134444c061aSmrg    while(xthread_have_id(process_lock->holder))
135444c061aSmrg	xcondition_wait(process_lock->cond, process_lock->mutex);
136444c061aSmrg
137444c061aSmrg    process_lock->holder = this_thread;
138444c061aSmrg    assert(xthread_equal(process_lock->holder, this_thread));
139444c061aSmrg    xmutex_unlock(process_lock->mutex);
140444c061aSmrg#endif
141444c061aSmrg}
142444c061aSmrg
143444c061aSmrgstatic void
144444c061aSmrgProcessUnlock(void)
145444c061aSmrg{
146444c061aSmrg#ifdef _XMUTEX_NESTS
147444c061aSmrg    process_lock->level--;
148444c061aSmrg    xmutex_unlock(process_lock->mutex);
149444c061aSmrg#else
150444c061aSmrg    xmutex_lock(process_lock->mutex);
151444c061aSmrg    assert(xthread_equal(process_lock->holder, xthread_self()));
152444c061aSmrg    if (process_lock->level != 0) {
153444c061aSmrg	process_lock->level--;
154444c061aSmrg	xmutex_unlock(process_lock->mutex);
155444c061aSmrg	return;
156444c061aSmrg    }
157444c061aSmrg
158444c061aSmrg    xthread_clear_id(process_lock->holder);
159444c061aSmrg    xcondition_signal(process_lock->cond);
160444c061aSmrg
161444c061aSmrg    xmutex_unlock(process_lock->mutex);
162444c061aSmrg#endif
163444c061aSmrg}
164444c061aSmrg
165444c061aSmrg
166444c061aSmrgstatic void
167444c061aSmrgAppLock(XtAppContext app)
168444c061aSmrg{
169444c061aSmrg    LockPtr app_lock = app->lock_info;
170444c061aSmrg#ifdef _XMUTEX_NESTS
171444c061aSmrg    xmutex_lock(app_lock->mutex);
172444c061aSmrg    app_lock->level++;
173444c061aSmrg#else
174444c061aSmrg    xthread_t self = xthread_self();
175444c061aSmrg    xmutex_lock(app_lock->mutex);
176444c061aSmrg    if (!xthread_have_id(app_lock->holder)) {
177444c061aSmrg	app_lock->holder = self;
178444c061aSmrg    	assert(xthread_equal(app_lock->holder, self));
179444c061aSmrg	xmutex_unlock(app_lock->mutex);
180444c061aSmrg	return;
181444c061aSmrg    }
182444c061aSmrg    if (xthread_equal(app_lock->holder, self)) {
183444c061aSmrg	app_lock->level++;
184444c061aSmrg	xmutex_unlock(app_lock->mutex);
185444c061aSmrg	return;
186444c061aSmrg    }
187444c061aSmrg    while(xthread_have_id(app_lock->holder)) {
188444c061aSmrg	xcondition_wait(app_lock->cond, app_lock->mutex);
189444c061aSmrg    }
190444c061aSmrg    app_lock->holder = self;
191444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
192444c061aSmrg    xmutex_unlock(app_lock->mutex);
193444c061aSmrg#endif
194444c061aSmrg}
195444c061aSmrg
196444c061aSmrgstatic void
197444c061aSmrgAppUnlock(XtAppContext app)
198444c061aSmrg{
199444c061aSmrg    LockPtr app_lock = app->lock_info;
200444c061aSmrg#ifdef _XMUTEX_NESTS
201444c061aSmrg    app_lock->level--;
202444c061aSmrg    xmutex_unlock(app_lock->mutex);
203444c061aSmrg#else
204444c061aSmrg    xthread_t self;
205444c061aSmrg
206444c061aSmrg    self = xthread_self();
207444c061aSmrg    xmutex_lock(app_lock->mutex);
208444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
209444c061aSmrg    if (app_lock->level != 0) {
210444c061aSmrg	app_lock->level--;
211444c061aSmrg	xmutex_unlock(app_lock->mutex);
212444c061aSmrg	return;
213444c061aSmrg    }
214444c061aSmrg    xthread_clear_id(app_lock->holder);
215444c061aSmrg    xcondition_signal(app_lock->cond);
216444c061aSmrg    xmutex_unlock(app_lock->mutex);
217444c061aSmrg#endif
218444c061aSmrg}
219444c061aSmrg
220444c061aSmrgstatic void
221444c061aSmrgYieldAppLock(
222444c061aSmrg    XtAppContext app,
223444c061aSmrg    Boolean* push_thread,
224444c061aSmrg    Boolean* pushed_thread,
225444c061aSmrg    int* level)
226444c061aSmrg{
227444c061aSmrg    LockPtr app_lock = app->lock_info;
228444c061aSmrg    xthread_t self = xthread_self();
229444c061aSmrg#ifndef _XMUTEX_NESTS
230444c061aSmrg    xmutex_lock(app_lock->mutex);
231444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
232444c061aSmrg#endif
233444c061aSmrg    *level = app_lock->level;
234444c061aSmrg    if (*push_thread) {
235444c061aSmrg	*push_thread = FALSE;
236444c061aSmrg	*pushed_thread = TRUE;
237444c061aSmrg
238444c061aSmrg	if(app_lock->stack.sp == (int)app_lock->stack.size - 1) {
239444c061aSmrg	    unsigned ii;
240444c061aSmrg	    app_lock->stack.st = (struct _Tstack *)
241444c061aSmrg		XtRealloc ((char *)app_lock->stack.st,
242444c061aSmrg		(app_lock->stack.size + STACK_INCR) * sizeof (struct _Tstack));
243444c061aSmrg	    ii = app_lock->stack.size;
244444c061aSmrg	    app_lock->stack.size += STACK_INCR;
245444c061aSmrg	    for ( ; ii < app_lock->stack.size; ii++) {
246444c061aSmrg		app_lock->stack.st[ii].c = xcondition_malloc();
247444c061aSmrg		xcondition_init(app_lock->stack.st[ii].c);
248444c061aSmrg	    }
249444c061aSmrg	}
250444c061aSmrg	app_lock->stack.st[++(app_lock->stack.sp)].t = self;
251444c061aSmrg    }
252444c061aSmrg#ifdef _XMUTEX_NESTS
253444c061aSmrg    while (app_lock->level > 0) {
254444c061aSmrg	app_lock->level--;
255444c061aSmrg	xmutex_unlock(app_lock->mutex);
256444c061aSmrg    }
257444c061aSmrg#else
258444c061aSmrg    xcondition_signal(app_lock->cond);
259444c061aSmrg    app_lock->level = 0;
260444c061aSmrg    xthread_clear_id(app_lock->holder);
261444c061aSmrg    xmutex_unlock(app_lock->mutex);
262444c061aSmrg#endif
263444c061aSmrg}
264444c061aSmrg
265444c061aSmrgstatic void
266444c061aSmrgRestoreAppLock(
267444c061aSmrg    XtAppContext app,
268444c061aSmrg    int level,
269444c061aSmrg    Boolean* pushed_thread)
270444c061aSmrg{
271444c061aSmrg    LockPtr app_lock = app->lock_info;
272444c061aSmrg    xthread_t self = xthread_self();
273444c061aSmrg    xmutex_lock(app_lock->mutex);
274444c061aSmrg#ifdef _XMUTEX_NESTS
275444c061aSmrg    app_lock->level++;
276444c061aSmrg#else
277444c061aSmrg    while(xthread_have_id(app_lock->holder)) {
278444c061aSmrg	xcondition_wait(app_lock->cond, app_lock->mutex);
279444c061aSmrg    }
280444c061aSmrg#endif
281444c061aSmrg    if (!xthread_equal(app_lock->stack.st[app_lock->stack.sp].t, self)) {
282444c061aSmrg	int ii;
283444c061aSmrg	for (ii = app_lock->stack.sp - 1; ii >= 0; ii--) {
284444c061aSmrg	    if (xthread_equal(app_lock->stack.st[ii].t, self)) {
285444c061aSmrg		xcondition_wait(app_lock->stack.st[ii].c, app_lock->mutex);
286444c061aSmrg		break;
287444c061aSmrg	    }
288444c061aSmrg	}
289444c061aSmrg#ifndef _XMUTEX_NESTS
290444c061aSmrg	while(xthread_have_id(app_lock->holder)) {
291444c061aSmrg	    xcondition_wait(app_lock->cond, app_lock->mutex);
292444c061aSmrg	}
293444c061aSmrg#endif
294444c061aSmrg    }
295444c061aSmrg#ifdef _XMUTEX_NESTS
296444c061aSmrg    while (app_lock->level < level) {
297444c061aSmrg	xmutex_lock(app_lock->mutex);
298444c061aSmrg	app_lock->level++;
299444c061aSmrg    }
300444c061aSmrg#else
301444c061aSmrg    app_lock->holder = self;
302444c061aSmrg    app_lock->level = level;
303444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
304444c061aSmrg#endif
305444c061aSmrg    if (*pushed_thread) {
306444c061aSmrg	*pushed_thread = FALSE;
307444c061aSmrg	(app_lock->stack.sp)--;
308444c061aSmrg	if (app_lock->stack.sp >= 0) {
309444c061aSmrg	    xcondition_signal (app_lock->stack.st[app_lock->stack.sp].c);
310444c061aSmrg	}
311444c061aSmrg    }
312444c061aSmrg#ifndef _XMUTEX_NESTS
313444c061aSmrg    xmutex_unlock(app_lock->mutex);
314444c061aSmrg#endif
315444c061aSmrg}
316444c061aSmrg
317444c061aSmrgstatic void
318444c061aSmrgFreeAppLock(XtAppContext app)
319444c061aSmrg{
320444c061aSmrg    unsigned ii;
321444c061aSmrg    LockPtr app_lock = app->lock_info;
322444c061aSmrg
323444c061aSmrg    if(app_lock) {
324444c061aSmrg	xmutex_clear(app_lock->mutex);
325444c061aSmrg	xmutex_free(app_lock->mutex);
326444c061aSmrg#ifndef _XMUTEX_NESTS
327444c061aSmrg	xcondition_clear(app_lock->cond);
328444c061aSmrg	xcondition_free(app_lock->cond);
329444c061aSmrg#endif
330444c061aSmrg	if(app_lock->stack.st != (struct _Tstack *)NULL) {
331444c061aSmrg	    for (ii = 0; ii < app_lock->stack.size; ii++) {
332444c061aSmrg		xcondition_clear(app_lock->stack.st[ii].c);
333444c061aSmrg		xcondition_free(app_lock->stack.st[ii].c);
334444c061aSmrg	    }
335444c061aSmrg	    XtFree((char *)app_lock->stack.st);
336444c061aSmrg	}
337444c061aSmrg	XtFree((char *)app_lock);
338444c061aSmrg	app->lock_info = NULL;
339444c061aSmrg    }
340444c061aSmrg}
341444c061aSmrg
342444c061aSmrgstatic void
343444c061aSmrgInitAppLock(XtAppContext app)
344444c061aSmrg{
345444c061aSmrg    int ii;
346444c061aSmrg    LockPtr app_lock;
347444c061aSmrg
348444c061aSmrg    app->lock = AppLock;
349444c061aSmrg    app->unlock = AppUnlock;
350444c061aSmrg    app->yield_lock = YieldAppLock;
351444c061aSmrg    app->restore_lock = RestoreAppLock;
352444c061aSmrg    app->free_lock = FreeAppLock;
353444c061aSmrg
354444c061aSmrg    app_lock = app->lock_info = XtNew(LockRec);
355444c061aSmrg    app_lock->mutex = xmutex_malloc();
356444c061aSmrg    xmutex_init(app_lock->mutex);
357444c061aSmrg    app_lock->level = 0;
358444c061aSmrg#ifndef _XMUTEX_NESTS
359444c061aSmrg    app_lock->cond = xcondition_malloc();
360444c061aSmrg    xcondition_init(app_lock->cond);
361444c061aSmrg    xthread_clear_id(app_lock->holder);
362444c061aSmrg#endif
363444c061aSmrg    app_lock->stack.size = STACK_INCR;
364444c061aSmrg    app_lock->stack.sp = -1;
365444c061aSmrg    app_lock->stack.st =
366444c061aSmrg	(struct _Tstack *)__XtMalloc(sizeof(struct _Tstack)*STACK_INCR);
367444c061aSmrg    for (ii = 0; ii < STACK_INCR; ii++) {
368444c061aSmrg	app_lock->stack.st[ii].c = xcondition_malloc();
369444c061aSmrg	xcondition_init(app_lock->stack.st[ii].c);
370444c061aSmrg    }
371444c061aSmrg}
372444c061aSmrg
373444c061aSmrg#endif /* defined(XTHREADS) */
374444c061aSmrg
375444c061aSmrgvoid XtAppLock(XtAppContext app)
376444c061aSmrg{
377444c061aSmrg#ifdef XTHREADS
378444c061aSmrg    if(app->lock)
379444c061aSmrg	(*app->lock)(app);
380444c061aSmrg#endif
381444c061aSmrg}
382444c061aSmrg
383444c061aSmrgvoid XtAppUnlock(XtAppContext app)
384444c061aSmrg{
385444c061aSmrg#ifdef XTHREADS
386444c061aSmrg    if(app->unlock)
387444c061aSmrg	(*app->unlock)(app);
388444c061aSmrg#endif
389444c061aSmrg}
390444c061aSmrg
391444c061aSmrgvoid XtProcessLock(void)
392444c061aSmrg{
393444c061aSmrg#ifdef XTHREADS
394444c061aSmrg    if(_XtProcessLock)
395444c061aSmrg	(*_XtProcessLock)();
396444c061aSmrg#endif
397444c061aSmrg}
398444c061aSmrg
399444c061aSmrgvoid XtProcessUnlock(void)
400444c061aSmrg{
401444c061aSmrg#ifdef XTHREADS
402444c061aSmrg    if(_XtProcessUnlock)
403444c061aSmrg	(*_XtProcessUnlock)();
404444c061aSmrg#endif
405444c061aSmrg}
406444c061aSmrg
407444c061aSmrgBoolean XtToolkitThreadInitialize(void)
408444c061aSmrg{
409444c061aSmrg#ifdef XTHREADS
410444c061aSmrg    if (_XtProcessLock == NULL) {
411444c061aSmrg#ifdef xthread_init
412444c061aSmrg	xthread_init();
413444c061aSmrg#endif
414444c061aSmrg	InitProcessLock();
415444c061aSmrg	_XtProcessLock = ProcessLock;
416444c061aSmrg	_XtProcessUnlock = ProcessUnlock;
417444c061aSmrg	_XtInitAppLock = InitAppLock;
418444c061aSmrg    }
419444c061aSmrg    return True;
420444c061aSmrg#else
421444c061aSmrg    return False;
422444c061aSmrg#endif
423444c061aSmrg}
424444c061aSmrg
425