locking.c revision 61b2299d
11ab64890Smrg/* $Xorg: locking.c,v 1.5 2001/02/09 02:03:40 xorgcvs Exp $ */
21ab64890Smrg/*
361b2299dSmrg
41ab64890SmrgCopyright 1992, 1998  The Open Group
51ab64890Smrg
61ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
71ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
81ab64890Smrgthe above copyright notice appear in all copies and that both that
91ab64890Smrgcopyright notice and this permission notice appear in supporting
101ab64890Smrgdocumentation.
111ab64890Smrg
121ab64890SmrgThe above copyright notice and this permission notice shall be included in
131ab64890Smrgall copies or substantial portions of the Software.
141ab64890Smrg
151ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161ab64890SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171ab64890SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
181ab64890SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
191ab64890SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
201ab64890SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
211ab64890Smrg
221ab64890SmrgExcept as contained in this notice, the name of The Open Group shall not be
231ab64890Smrgused in advertising or otherwise to promote the sale, use or other dealings
241ab64890Smrgin this Software without prior written authorization from The Open Group.
251ab64890Smrg
261ab64890Smrg*/
271ab64890Smrg/* $XFree86: xc/lib/X11/locking.c,v 1.5 2003/04/13 19:22:22 dawes Exp $ */
281ab64890Smrg
291ab64890Smrg/*
301ab64890Smrg * Author: Stephen Gildea, MIT X Consortium
311ab64890Smrg *
321ab64890Smrg * locking.c - multi-thread locking routines implemented in C Threads
331ab64890Smrg */
341ab64890Smrg
351ab64890Smrg#ifdef HAVE_CONFIG_H
361ab64890Smrg#include <config.h>
371ab64890Smrg#endif
381ab64890Smrg#include "Xlibint.h"
391ab64890Smrg#undef _XLockMutex
401ab64890Smrg#undef _XUnlockMutex
411ab64890Smrg#undef _XCreateMutex
421ab64890Smrg#undef _XFreeMutex
431ab64890Smrg
441ab64890Smrg#ifdef XTHREADS
451ab64890Smrg
461ab64890Smrg#ifdef __UNIXWARE__
471ab64890Smrg#include <dlfcn.h>
481ab64890Smrg#endif
491ab64890Smrg
501ab64890Smrg#include "locking.h"
511ab64890Smrg#ifdef XTHREADS_WARN
521ab64890Smrg#include <stdio.h>		/* for warn/debug stuff */
531ab64890Smrg#endif
541ab64890Smrg
551ab64890Smrg#define NUM_FREE_CVLS 4
561ab64890Smrg
571ab64890Smrg/* in lcWrap.c */
581ab64890Smrgextern LockInfoPtr _Xi18n_lock;
591ab64890Smrg
601ab64890Smrg#ifdef WIN32
611ab64890Smrgstatic DWORD _X_TlsIndex = (DWORD)-1;
621ab64890Smrg
6361b2299dSmrgvoid _Xthread_init()
641ab64890Smrg{
651ab64890Smrg    if (_X_TlsIndex == (DWORD)-1)
661ab64890Smrg	_X_TlsIndex = TlsAlloc();
671ab64890Smrg}
681ab64890Smrg
691ab64890Smrgstruct _xthread_waiter *
701ab64890Smrg_Xthread_waiter()
711ab64890Smrg{
721ab64890Smrg    struct _xthread_waiter *me;
731ab64890Smrg
741ab64890Smrg    if (!(me = TlsGetValue(_X_TlsIndex))) {
751ab64890Smrg	me = (struct _xthread_waiter *)xmalloc(sizeof(struct _xthread_waiter));
761ab64890Smrg	me->sem = CreateSemaphore(NULL, 0, 1, NULL);
771ab64890Smrg	me->next = NULL;
781ab64890Smrg	TlsSetValue(_X_TlsIndex, me);
791ab64890Smrg    }
801ab64890Smrg    return me;
811ab64890Smrg}
821ab64890Smrg#endif /* WIN32 */
831ab64890Smrg
841ab64890Smrgstatic xthread_t _Xthread_self(void)
851ab64890Smrg{
861ab64890Smrg    return xthread_self();
871ab64890Smrg}
881ab64890Smrg
891ab64890Smrgstatic LockInfoRec global_lock;
901ab64890Smrgstatic LockInfoRec i18n_lock;
911ab64890Smrg
921ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
931ab64890Smrgstatic void _XLockMutex(lip,file,line)
941ab64890Smrg    LockInfoPtr lip;
951ab64890Smrg    char* file;
961ab64890Smrg    int line;
971ab64890Smrg#else
981ab64890Smrgstatic void _XLockMutex(
991ab64890Smrg    LockInfoPtr lip)
1001ab64890Smrg#endif
1011ab64890Smrg{
1021ab64890Smrg    xmutex_lock(lip->lock);
1031ab64890Smrg}
1041ab64890Smrg
1051ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
1061ab64890Smrgstatic void _XUnlockMutex(
1071ab64890Smrg    LockInfoPtr lip,
1081ab64890Smrg    char* file,
1091ab64890Smrg    int line)
1101ab64890Smrg#else
1111ab64890Smrgstatic void _XUnlockMutex(
1121ab64890Smrg    LockInfoPtr lip)
1131ab64890Smrg#endif
1141ab64890Smrg{
1151ab64890Smrg    xmutex_unlock(lip->lock);
1161ab64890Smrg}
1171ab64890Smrg
1181ab64890Smrgstatic void _XCreateMutex(
1191ab64890Smrg    LockInfoPtr lip)
1201ab64890Smrg{
1211ab64890Smrg    lip->lock = xmutex_malloc();
1221ab64890Smrg    if (lip->lock) {
1231ab64890Smrg	xmutex_init(lip->lock);
1241ab64890Smrg	xmutex_set_name(lip->lock, "Xlib");
1251ab64890Smrg    }
1261ab64890Smrg}
1271ab64890Smrg
1281ab64890Smrgstatic void _XFreeMutex(
1291ab64890Smrg    LockInfoPtr lip)
1301ab64890Smrg{
1311ab64890Smrg    xmutex_clear(lip->lock);
1321ab64890Smrg    xmutex_free(lip->lock);
1331ab64890Smrg}
1341ab64890Smrg
1351ab64890Smrg#ifdef XTHREADS_WARN
1361ab64890Smrgstatic char *locking_file;
1371ab64890Smrgstatic int locking_line;
1381ab64890Smrgstatic xthread_t locking_thread;
1391ab64890Smrgstatic Bool xlibint_unlock = False; /* XlibInt.c may Unlock and re-Lock */
1401ab64890Smrg
1411ab64890Smrg/* history that is useful to examine in a debugger */
1421ab64890Smrg#define LOCK_HIST_SIZE 21
1431ab64890Smrg
1441ab64890Smrgstatic struct {
1451ab64890Smrg    Bool lockp;			/* True for lock, False for unlock */
1461ab64890Smrg    xthread_t thread;
1471ab64890Smrg    char *file;
1481ab64890Smrg    int line;
1491ab64890Smrg} locking_history[LOCK_HIST_SIZE];
1501ab64890Smrg
1511ab64890Smrgint lock_hist_loc = 0;		/* next slot to fill */
1521ab64890Smrg
1531ab64890Smrgstatic void _XLockDisplayWarn(
1541ab64890Smrg    Display *dpy,
1551ab64890Smrg    char *file,			/* source file, from macro */
1561ab64890Smrg    int line)
1571ab64890Smrg{
1581ab64890Smrg    xthread_t self;
1591ab64890Smrg    xthread_t old_locker;
1601ab64890Smrg
1611ab64890Smrg    self = xthread_self();
1621ab64890Smrg    old_locker = locking_thread;
1631ab64890Smrg    if (xthread_have_id(old_locker)) {
1641ab64890Smrg	if (xthread_equal(old_locker, self))
1651ab64890Smrg	    printf("Xlib ERROR: %s line %d thread %x: locking display already locked at %s line %d\n",
1661ab64890Smrg		   file, line, self, locking_file, locking_line);
1671ab64890Smrg#ifdef XTHREADS_DEBUG
1681ab64890Smrg	else
1691ab64890Smrg	    printf("%s line %d: thread %x waiting on lock held by %s line %d thread %x\n",
1701ab64890Smrg		   file, line, self,
1711ab64890Smrg		   locking_file, locking_line, old_locker);
1721ab64890Smrg#endif /* XTHREADS_DEBUG */
1731ab64890Smrg    }
1741ab64890Smrg
1751ab64890Smrg    xmutex_lock(dpy->lock->mutex);
1761ab64890Smrg
1771ab64890Smrg    if (strcmp(file, "XlibInt.c") == 0) {
1781ab64890Smrg	if (!xlibint_unlock)
1791ab64890Smrg	    printf("Xlib ERROR: XlibInt.c line %d thread %x locking display it did not unlock\n",
1801ab64890Smrg		   line, self);
1811ab64890Smrg	xlibint_unlock = False;
1821ab64890Smrg    }
1831ab64890Smrg
1841ab64890Smrg#ifdef XTHREADS_DEBUG
1851ab64890Smrg    /* if (old_locker  &&  old_locker != self) */
1861ab64890Smrg    if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */
1871ab64890Smrg	printf("%s line %d: thread %x got display lock\n", file, line, self);
1881ab64890Smrg#endif /* XTHREADS_DEBUG */
1891ab64890Smrg
1901ab64890Smrg    locking_thread = self;
1911ab64890Smrg    if (strcmp(file, "XlibInt.c") != 0) {
1921ab64890Smrg	locking_file = file;
1931ab64890Smrg	locking_line = line;
1941ab64890Smrg    }
1951ab64890Smrg    locking_history[lock_hist_loc].file = file;
1961ab64890Smrg    locking_history[lock_hist_loc].line = line;
1971ab64890Smrg    locking_history[lock_hist_loc].thread = self;
1981ab64890Smrg    locking_history[lock_hist_loc].lockp = True;
1991ab64890Smrg    lock_hist_loc++;
2001ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
2011ab64890Smrg	lock_hist_loc = 0;
2021ab64890Smrg}
2031ab64890Smrg#endif /* XTHREADS_WARN */
2041ab64890Smrg
2051ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
2061ab64890Smrgstatic void _XUnlockDisplay(dpy,file,line)
2071ab64890Smrg    Display *dpy;
2081ab64890Smrg    char *file;
2091ab64890Smrg    int line;
2101ab64890Smrg#else
2111ab64890Smrgstatic void _XUnlockDisplay(
2121ab64890Smrg    Display *dpy)
2131ab64890Smrg#endif
2141ab64890Smrg{
2151ab64890Smrg#ifdef XTHREADS_WARN
2161ab64890Smrg    xthread_t self = xthread_self();
2171ab64890Smrg
2181ab64890Smrg#ifdef XTHREADS_DEBUG
2191ab64890Smrg    if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */
2201ab64890Smrg	printf("%s line %d: thread %x unlocking display\n", file, line, self);
2211ab64890Smrg#endif /* XTHREADS_DEBUG */
2221ab64890Smrg
2231ab64890Smrg    if (!xthread_have_id(locking_thread))
2241ab64890Smrg	printf("Xlib ERROR: %s line %d thread %x: unlocking display that is not locked\n",
2251ab64890Smrg	       file, line, self);
2261ab64890Smrg    else if (strcmp(file, "XlibInt.c") == 0)
2271ab64890Smrg	xlibint_unlock = True;
2281ab64890Smrg#ifdef XTHREADS_DEBUG
2291ab64890Smrg    else if (strcmp(file, locking_file) != 0)
2301ab64890Smrg	/* not always an error because locking_file is not per-thread */
2311ab64890Smrg	printf("%s line %d: unlocking display locked from %s line %d (probably okay)\n",
2321ab64890Smrg	       file, line, locking_file, locking_line);
2331ab64890Smrg#endif /* XTHREADS_DEBUG */
2341ab64890Smrg    xthread_clear_id(locking_thread);
2351ab64890Smrg
2361ab64890Smrg    locking_history[lock_hist_loc].file = file;
2371ab64890Smrg    locking_history[lock_hist_loc].line = line;
2381ab64890Smrg    locking_history[lock_hist_loc].thread = self;
2391ab64890Smrg    locking_history[lock_hist_loc].lockp = False;
2401ab64890Smrg    lock_hist_loc++;
2411ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
2421ab64890Smrg	lock_hist_loc = 0;
2431ab64890Smrg#endif /* XTHREADS_WARN */
2441ab64890Smrg    xmutex_unlock(dpy->lock->mutex);
2451ab64890Smrg}
2461ab64890Smrg
2471ab64890Smrg
2481ab64890Smrgstatic struct _XCVList *_XCreateCVL(
2491ab64890Smrg    Display *dpy)
2501ab64890Smrg{
2511ab64890Smrg    struct _XCVList *cvl;
2521ab64890Smrg
2531ab64890Smrg    if ((cvl = dpy->lock->free_cvls) != NULL) {
2541ab64890Smrg	dpy->lock->free_cvls = cvl->next;
2551ab64890Smrg	dpy->lock->num_free_cvls--;
2561ab64890Smrg    } else {
2571ab64890Smrg	cvl = (struct _XCVList *)Xmalloc(sizeof(struct _XCVList));
2581ab64890Smrg	if (!cvl)
2591ab64890Smrg	    return NULL;
2601ab64890Smrg	cvl->cv = xcondition_malloc();
2611ab64890Smrg	if (!cvl->cv) {
2621ab64890Smrg	    Xfree(cvl);
2631ab64890Smrg	    return NULL;
2641ab64890Smrg	}
2651ab64890Smrg	xcondition_init(cvl->cv);
2661ab64890Smrg	xcondition_set_name(cvl->cv, "Xlib read queue");
2671ab64890Smrg    }
2681ab64890Smrg    cvl->next = NULL;
2691ab64890Smrg    return cvl;
2701ab64890Smrg}
2711ab64890Smrg
2721ab64890Smrg/* Put ourselves on the queue to read the connection.
2731ab64890Smrg   Allocates and returns a queue element. */
2741ab64890Smrg
2751ab64890Smrgstatic struct _XCVList *
2761ab64890Smrg_XPushReader(
2771ab64890Smrg    Display *dpy,
2781ab64890Smrg    struct _XCVList ***tail)
2791ab64890Smrg{
2801ab64890Smrg    struct _XCVList *cvl;
2811ab64890Smrg
2821ab64890Smrg    cvl = _XCreateCVL(dpy);
2831ab64890Smrg#ifdef XTHREADS_DEBUG
2841ab64890Smrg    printf("_XPushReader called in thread %x, pushing %x\n",
2851ab64890Smrg	   xthread_self(), cvl);
2861ab64890Smrg#endif
2871ab64890Smrg    **tail = cvl;
2881ab64890Smrg    *tail = &cvl->next;
2891ab64890Smrg    return cvl;
2901ab64890Smrg}
2911ab64890Smrg
2921ab64890Smrg/* signal the next thread waiting to read the connection */
2931ab64890Smrg
2941ab64890Smrgstatic void _XPopReader(
2951ab64890Smrg    Display *dpy,
2961ab64890Smrg    struct _XCVList **list,
2971ab64890Smrg    struct _XCVList ***tail)
2981ab64890Smrg{
2991ab64890Smrg    register struct _XCVList *front = *list;
3001ab64890Smrg
3011ab64890Smrg#ifdef XTHREADS_DEBUG
3021ab64890Smrg    printf("_XPopReader called in thread %x, popping %x\n",
3031ab64890Smrg	   xthread_self(), front);
3041ab64890Smrg#endif
3051ab64890Smrg
3061ab64890Smrg    if (dpy->flags & XlibDisplayProcConni)
3071ab64890Smrg	/* we never added ourself in the first place */
3081ab64890Smrg	return;
3091ab64890Smrg
3101ab64890Smrg    if (front) {		/* check "front" for paranoia */
3111ab64890Smrg	*list = front->next;
3121ab64890Smrg	if (*tail == &front->next)	/* did we free the last elt? */
3131ab64890Smrg	    *tail = list;
3141ab64890Smrg	if (dpy->lock->num_free_cvls < NUM_FREE_CVLS) {
3151ab64890Smrg	    front->next = dpy->lock->free_cvls;
3161ab64890Smrg	    dpy->lock->free_cvls = front;
3171ab64890Smrg	    dpy->lock->num_free_cvls++;
3181ab64890Smrg	} else {
3191ab64890Smrg	    xcondition_clear(front->cv);
3201ab64890Smrg	    Xfree((char *)front->cv);
3211ab64890Smrg	    Xfree((char *)front);
3221ab64890Smrg	}
3231ab64890Smrg    }
3241ab64890Smrg
3251ab64890Smrg    /* signal new front after it is in place */
3261ab64890Smrg    if ((dpy->lock->reply_first = (dpy->lock->reply_awaiters != NULL))) {
3271ab64890Smrg	ConditionSignal(dpy, dpy->lock->reply_awaiters->cv);
3281ab64890Smrg    } else if (dpy->lock->event_awaiters) {
3291ab64890Smrg	ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
3301ab64890Smrg    }
3311ab64890Smrg}
3321ab64890Smrg
3331ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
3341ab64890Smrgstatic void _XConditionWait(cv, mutex,file,line)
3351ab64890Smrg    xcondition_t cv;
3361ab64890Smrg    xmutex_t mutex;
3371ab64890Smrg    char *file;
3381ab64890Smrg    int line;
3391ab64890Smrg#else
3401ab64890Smrgstatic void _XConditionWait(
3411ab64890Smrg    xcondition_t cv,
3421ab64890Smrg    xmutex_t mutex)
3431ab64890Smrg#endif
3441ab64890Smrg{
3451ab64890Smrg#ifdef XTHREADS_WARN
3461ab64890Smrg    xthread_t self = xthread_self();
3471ab64890Smrg    char *old_file = locking_file;
3481ab64890Smrg    int old_line = locking_line;
34961b2299dSmrg
3501ab64890Smrg#ifdef XTHREADS_DEBUG
3511ab64890Smrg    printf("line %d thread %x in condition wait\n", line, self);
3521ab64890Smrg#endif
3531ab64890Smrg    xthread_clear_id(locking_thread);
3541ab64890Smrg
3551ab64890Smrg    locking_history[lock_hist_loc].file = file;
3561ab64890Smrg    locking_history[lock_hist_loc].line = line;
3571ab64890Smrg    locking_history[lock_hist_loc].thread = self;
3581ab64890Smrg    locking_history[lock_hist_loc].lockp = False;
3591ab64890Smrg    lock_hist_loc++;
3601ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
3611ab64890Smrg	lock_hist_loc = 0;
3621ab64890Smrg#endif /* XTHREADS_WARN */
3631ab64890Smrg
3641ab64890Smrg    xcondition_wait(cv, mutex);
3651ab64890Smrg
3661ab64890Smrg#ifdef XTHREADS_WARN
3671ab64890Smrg    locking_thread = self;
3681ab64890Smrg    locking_file = old_file;
3691ab64890Smrg    locking_line = old_line;
3701ab64890Smrg
3711ab64890Smrg    locking_history[lock_hist_loc].file = file;
3721ab64890Smrg    locking_history[lock_hist_loc].line = line;
3731ab64890Smrg    locking_history[lock_hist_loc].thread = self;
3741ab64890Smrg    locking_history[lock_hist_loc].lockp = True;
3751ab64890Smrg    lock_hist_loc++;
3761ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
3771ab64890Smrg	lock_hist_loc = 0;
3781ab64890Smrg#ifdef XTHREADS_DEBUG
3791ab64890Smrg    printf("line %d thread %x was signaled\n", line, self);
3801ab64890Smrg#endif /* XTHREADS_DEBUG */
3811ab64890Smrg#endif /* XTHREADS_WARN */
3821ab64890Smrg}
3831ab64890Smrg
3841ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
3851ab64890Smrgstatic void _XConditionSignal(cv,file,line)
3861ab64890Smrg    xcondition_t cv;
3871ab64890Smrg    char *file;
3881ab64890Smrg    int line;
3891ab64890Smrg#else
3901ab64890Smrgstatic void _XConditionSignal(
3911ab64890Smrg    xcondition_t cv)
3921ab64890Smrg#endif
3931ab64890Smrg{
3941ab64890Smrg#ifdef XTHREADS_WARN
3951ab64890Smrg#ifdef XTHREADS_DEBUG
3961ab64890Smrg    printf("line %d thread %x is signalling\n", line, xthread_self());
3971ab64890Smrg#endif
3981ab64890Smrg#endif
3991ab64890Smrg    xcondition_signal(cv);
4001ab64890Smrg}
40161b2299dSmrg
4021ab64890Smrg
4031ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
4041ab64890Smrgstatic void _XConditionBroadcast(cv,file,line)
4051ab64890Smrg    xcondition_t cv;
4061ab64890Smrg    char *file;
4071ab64890Smrg    int line;
4081ab64890Smrg#else
4091ab64890Smrgstatic void _XConditionBroadcast(
4101ab64890Smrg    xcondition_t cv)
4111ab64890Smrg#endif
4121ab64890Smrg{
4131ab64890Smrg#ifdef XTHREADS_WARN
4141ab64890Smrg#ifdef XTHREADS_DEBUG
4151ab64890Smrg    printf("line %d thread %x is broadcasting\n", line, xthread_self());
4161ab64890Smrg#endif
4171ab64890Smrg#endif
4181ab64890Smrg    xcondition_broadcast(cv);
4191ab64890Smrg}
42061b2299dSmrg
4211ab64890Smrg
4221ab64890Smrgstatic void _XFreeDisplayLock(
4231ab64890Smrg    Display *dpy)
4241ab64890Smrg{
4251ab64890Smrg    struct _XCVList *cvl;
4261ab64890Smrg
4271ab64890Smrg    if (dpy->lock != NULL) {
4281ab64890Smrg	if (dpy->lock->mutex != NULL) {
4291ab64890Smrg	    xmutex_clear(dpy->lock->mutex);
4301ab64890Smrg	    xmutex_free(dpy->lock->mutex);
4311ab64890Smrg	}
4321ab64890Smrg	if (dpy->lock->cv != NULL) {
4331ab64890Smrg	    xcondition_clear(dpy->lock->cv);
4341ab64890Smrg	    xcondition_free(dpy->lock->cv);
4351ab64890Smrg	}
4361ab64890Smrg	if (dpy->lock->writers != NULL) {
4371ab64890Smrg	    xcondition_clear(dpy->lock->writers);
4381ab64890Smrg	    xcondition_free(dpy->lock->writers);
4391ab64890Smrg	}
4401ab64890Smrg	while ((cvl = dpy->lock->free_cvls)) {
4411ab64890Smrg	    dpy->lock->free_cvls = cvl->next;
4421ab64890Smrg	    xcondition_clear(cvl->cv);
4431ab64890Smrg	    Xfree((char *)cvl->cv);
4441ab64890Smrg	    Xfree((char *)cvl);
4451ab64890Smrg	}
4461ab64890Smrg	Xfree((char *)dpy->lock);
4471ab64890Smrg	dpy->lock = NULL;
4481ab64890Smrg    }
4491ab64890Smrg    if (dpy->lock_fns != NULL) {
4501ab64890Smrg	Xfree((char *)dpy->lock_fns);
4511ab64890Smrg	dpy->lock_fns = NULL;
4521ab64890Smrg    }
4531ab64890Smrg}
4541ab64890Smrg
4551ab64890Smrg/*
4561ab64890Smrg * wait for thread with user-level display lock to release it.
4571ab64890Smrg */
4581ab64890Smrg
4591ab64890Smrgstatic void _XDisplayLockWait(
4601ab64890Smrg    Display *dpy)
4611ab64890Smrg{
4621ab64890Smrg    xthread_t self;
4631ab64890Smrg
4641ab64890Smrg    while (dpy->lock->locking_level > 0) {
4651ab64890Smrg	self = xthread_self();
4661ab64890Smrg	if (xthread_equal(dpy->lock->locking_thread, self))
4671ab64890Smrg	    break;
4681ab64890Smrg	ConditionWait(dpy, dpy->lock->cv);
4691ab64890Smrg    }
4701ab64890Smrg}
4711ab64890Smrg
4721ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
4731ab64890Smrgstatic void _XLockDisplay(dpy, file, line)
4741ab64890Smrg    Display *dpy;
4751ab64890Smrg    char *file;			/* source file, from macro */
4761ab64890Smrg    int line;
4771ab64890Smrg#else
4781ab64890Smrgstatic void _XLockDisplay(
4791ab64890Smrg    Display *dpy)
4801ab64890Smrg#endif
4811ab64890Smrg{
4821ab64890Smrg#ifdef XTHREADS_WARN
4831ab64890Smrg    _XLockDisplayWarn(dpy, file, line);
4841ab64890Smrg#else
4851ab64890Smrg    xmutex_lock(dpy->lock->mutex);
4861ab64890Smrg#endif
4871ab64890Smrg    if (dpy->lock->locking_level > 0)
4881ab64890Smrg	_XDisplayLockWait(dpy);
4891ab64890Smrg}
4901ab64890Smrg
4911ab64890Smrg/*
4921ab64890Smrg * _XReply is allowed to exit from select/poll and clean up even if a
4931ab64890Smrg * user-level lock is in force, so it uses this instead of _XFancyLockDisplay.
4941ab64890Smrg */
4951ab64890Smrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
4961ab64890Smrgstatic void _XInternalLockDisplay(dpy, wskip, file, line)
4971ab64890Smrg    Display *dpy;
4981ab64890Smrg    Bool wskip;
4991ab64890Smrg    char *file;			/* source file, from macro */
5001ab64890Smrg    int line;
5011ab64890Smrg#else
5021ab64890Smrgstatic void _XInternalLockDisplay(
5031ab64890Smrg    Display *dpy,
5041ab64890Smrg    Bool wskip)
5051ab64890Smrg#endif
5061ab64890Smrg{
5071ab64890Smrg#ifdef XTHREADS_WARN
5081ab64890Smrg    _XLockDisplayWarn(dpy, file, line);
5091ab64890Smrg#else
5101ab64890Smrg    xmutex_lock(dpy->lock->mutex);
5111ab64890Smrg#endif
5121ab64890Smrg    if (!wskip && dpy->lock->locking_level > 0)
5131ab64890Smrg	_XDisplayLockWait(dpy);
5141ab64890Smrg}
5151ab64890Smrg
5161ab64890Smrgstatic void _XUserLockDisplay(
5171ab64890Smrg    register Display* dpy)
5181ab64890Smrg{
5191ab64890Smrg    if (++dpy->lock->locking_level == 1) {
5201ab64890Smrg	dpy->lock->lock_wait = _XDisplayLockWait;
5211ab64890Smrg	dpy->lock->locking_thread = xthread_self();
5221ab64890Smrg    }
5231ab64890Smrg}
5241ab64890Smrg
5251ab64890Smrgstatic
5261ab64890Smrgvoid _XUserUnlockDisplay(
5271ab64890Smrg    register Display* dpy)
5281ab64890Smrg{
5291ab64890Smrg    if (dpy->lock->locking_level > 0 && --dpy->lock->locking_level == 0) {
5301ab64890Smrg	/* signal other threads that might be waiting in XLockDisplay */
5311ab64890Smrg	ConditionBroadcast(dpy, dpy->lock->cv);
5321ab64890Smrg	dpy->lock->lock_wait = NULL;
5331ab64890Smrg	xthread_clear_id(dpy->lock->locking_thread);
5341ab64890Smrg    }
5351ab64890Smrg}
5361ab64890Smrg
5371ab64890Smrg/* returns 0 if initialized ok, -1 if unable to allocate
5381ab64890Smrg   a mutex or other memory */
5391ab64890Smrg
5401ab64890Smrgstatic int _XInitDisplayLock(
5411ab64890Smrg    Display *dpy)
5421ab64890Smrg{
5431ab64890Smrg    dpy->lock_fns = (struct _XLockPtrs*)Xmalloc(sizeof(struct _XLockPtrs));
5441ab64890Smrg    if (dpy->lock_fns == NULL)
5451ab64890Smrg	return -1;
5461ab64890Smrg    dpy->lock = (struct _XLockInfo *)Xmalloc(sizeof(struct _XLockInfo));
5471ab64890Smrg    if (dpy->lock == NULL) {
5481ab64890Smrg	_XFreeDisplayLock(dpy);
5491ab64890Smrg	return -1;
5501ab64890Smrg    }
5511ab64890Smrg    dpy->lock->cv = xcondition_malloc();
5521ab64890Smrg    dpy->lock->mutex = xmutex_malloc();
5531ab64890Smrg    dpy->lock->writers = xcondition_malloc();
5541ab64890Smrg    if (!dpy->lock->cv || !dpy->lock->mutex || !dpy->lock->writers) {
5551ab64890Smrg	_XFreeDisplayLock(dpy);
5561ab64890Smrg	return -1;
5571ab64890Smrg    }
5581ab64890Smrg
5591ab64890Smrg    dpy->lock->reply_bytes_left = 0;
5601ab64890Smrg    dpy->lock->reply_was_read = False;
5611ab64890Smrg    dpy->lock->reply_awaiters = NULL;
5621ab64890Smrg    dpy->lock->reply_awaiters_tail = &dpy->lock->reply_awaiters;
5631ab64890Smrg    dpy->lock->event_awaiters = NULL;
5641ab64890Smrg    dpy->lock->event_awaiters_tail = &dpy->lock->event_awaiters;
5651ab64890Smrg    dpy->lock->reply_first = False;
5661ab64890Smrg    dpy->lock->locking_level = 0;
5671ab64890Smrg    dpy->lock->num_free_cvls = 0;
5681ab64890Smrg    dpy->lock->free_cvls = NULL;
5691ab64890Smrg    xthread_clear_id(dpy->lock->locking_thread);
5701ab64890Smrg    xthread_clear_id(dpy->lock->reading_thread);
5711ab64890Smrg    xthread_clear_id(dpy->lock->conni_thread);
5721ab64890Smrg    xmutex_init(dpy->lock->mutex);
5731ab64890Smrg    xmutex_set_name(dpy->lock->mutex, "Xlib Display");
5741ab64890Smrg    xcondition_init(dpy->lock->cv);
5751ab64890Smrg    xcondition_set_name(dpy->lock->cv, "XLockDisplay");
5761ab64890Smrg    xcondition_init(dpy->lock->writers);
5771ab64890Smrg    xcondition_set_name(dpy->lock->writers, "Xlib wait for writable");
5781ab64890Smrg    dpy->lock_fns->lock_display = _XLockDisplay;
5791ab64890Smrg    dpy->lock->internal_lock_display = _XInternalLockDisplay;
5801ab64890Smrg    dpy->lock_fns->unlock_display = _XUnlockDisplay;
5811ab64890Smrg    dpy->lock->user_lock_display = _XUserLockDisplay;
5821ab64890Smrg    dpy->lock->user_unlock_display = _XUserUnlockDisplay;
5831ab64890Smrg    dpy->lock->pop_reader = _XPopReader;
5841ab64890Smrg    dpy->lock->push_reader = _XPushReader;
5851ab64890Smrg    dpy->lock->condition_wait = _XConditionWait;
5861ab64890Smrg    dpy->lock->condition_signal = _XConditionSignal;
5871ab64890Smrg    dpy->lock->condition_broadcast = _XConditionBroadcast;
5881ab64890Smrg    dpy->lock->create_cvl = _XCreateCVL;
5891ab64890Smrg    dpy->lock->lock_wait = NULL; /* filled in by XLockDisplay() */
5901ab64890Smrg
5911ab64890Smrg    return 0;
5921ab64890Smrg}
5931ab64890Smrg
5941ab64890Smrg#ifdef __UNIXWARE__
5951ab64890Smrgxthread_t __x11_thr_self() { return 0; }
5961ab64890Smrgxthread_t (*_x11_thr_self)() = __x11_thr_self;
5971ab64890Smrg#endif
5981ab64890Smrg
5991ab64890Smrg
60061b2299dSmrgStatus XInitThreads(void)
6011ab64890Smrg{
6021ab64890Smrg    if (_Xglobal_lock)
6031ab64890Smrg	return 1;
6041ab64890Smrg#ifdef __UNIXWARE__
6051ab64890Smrg    else {
6061ab64890Smrg       void *dl_handle = dlopen(NULL, RTLD_LAZY);
6071ab64890Smrg       if (!dl_handle ||
6081ab64890Smrg         ((_x11_thr_self = (xthread_t(*)())dlsym(dl_handle,"thr_self")) == 0)) {
6091ab64890Smrg	       _x11_thr_self = __x11_thr_self;
6101ab64890Smrg	       (void) fprintf (stderr,
6111ab64890Smrg	"XInitThreads called, but no libthread in the calling program!\n" );
6121ab64890Smrg       }
6131ab64890Smrg    }
6141ab64890Smrg#endif /* __UNIXWARE__ */
6151ab64890Smrg#ifdef xthread_init
6161ab64890Smrg    xthread_init();		/* return value? */
6171ab64890Smrg#endif
6181ab64890Smrg    if (!(global_lock.lock = xmutex_malloc()))
6191ab64890Smrg	return 0;
6201ab64890Smrg    if (!(i18n_lock.lock = xmutex_malloc())) {
6211ab64890Smrg	xmutex_free(global_lock.lock);
6221ab64890Smrg	global_lock.lock = NULL;
6231ab64890Smrg	return 0;
6241ab64890Smrg    }
6251ab64890Smrg    _Xglobal_lock = &global_lock;
6261ab64890Smrg    xmutex_init(_Xglobal_lock->lock);
6271ab64890Smrg    xmutex_set_name(_Xglobal_lock->lock, "Xlib global");
6281ab64890Smrg    _Xi18n_lock = &i18n_lock;
6291ab64890Smrg    xmutex_init(_Xi18n_lock->lock);
6301ab64890Smrg    xmutex_set_name(_Xi18n_lock->lock, "Xlib i18n");
6311ab64890Smrg    _XLockMutex_fn = _XLockMutex;
6321ab64890Smrg    _XUnlockMutex_fn = _XUnlockMutex;
6331ab64890Smrg    _XCreateMutex_fn = _XCreateMutex;
6341ab64890Smrg    _XFreeMutex_fn = _XFreeMutex;
6351ab64890Smrg    _XInitDisplayLock_fn = _XInitDisplayLock;
6361ab64890Smrg    _XFreeDisplayLock_fn = _XFreeDisplayLock;
6371ab64890Smrg    _Xthread_self_fn = _Xthread_self;
6381ab64890Smrg
6391ab64890Smrg#ifdef XTHREADS_WARN
6401ab64890Smrg#ifdef XTHREADS_DEBUG
6411ab64890Smrg    setlinebuf(stdout);		/* for debugging messages */
6421ab64890Smrg#endif
6431ab64890Smrg#endif
6441ab64890Smrg
6451ab64890Smrg    return 1;
6461ab64890Smrg}
6471ab64890Smrg
6481ab64890Smrg#else /* XTHREADS */
6491ab64890SmrgStatus XInitThreads()
6501ab64890Smrg{
6511ab64890Smrg    return 0;
6521ab64890Smrg}
6531ab64890Smrg#endif /* XTHREADS */
654