From 153f5cafa19da4e4c0cf21e9c909958359ed8ebd Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 19 May 2010 09:25:26 +0000 Subject: libX11 git update 19/10/2010 --- libX11/src/locking.c | 1243 +++++++++++++++++++++++++------------------------- 1 file changed, 623 insertions(+), 620 deletions(-) (limited to 'libX11/src/locking.c') diff --git a/libX11/src/locking.c b/libX11/src/locking.c index 3f93d0cd8..008a14863 100644 --- a/libX11/src/locking.c +++ b/libX11/src/locking.c @@ -1,620 +1,623 @@ -/* - -Copyright 1992, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - -*/ - -/* - * Author: Stephen Gildea, MIT X Consortium - * - * locking.c - multi-thread locking routines implemented in C Threads - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "Xlibint.h" -#undef _XLockMutex -#undef _XUnlockMutex -#undef _XCreateMutex -#undef _XFreeMutex - -#ifdef XTHREADS - -#ifdef __UNIXWARE__ -#include -#endif - -#include "locking.h" -#ifdef XTHREADS_WARN -#include /* for warn/debug stuff */ -#endif - -/* Additional arguments for source code location lock call was made from */ -#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) -# define XTHREADS_FILE_LINE_ARGS \ - , \ - char* file, /* source file, from macro */ \ - int line -#else -# define XTHREADS_FILE_LINE_ARGS /* None */ -#endif - - -#define NUM_FREE_CVLS 4 - -/* in lcWrap.c */ -extern LockInfoPtr _Xi18n_lock; - -#ifdef WIN32 -static DWORD _X_TlsIndex = (DWORD)-1; - -void _Xthread_init(void) -{ - if (_X_TlsIndex == (DWORD)-1) - _X_TlsIndex = TlsAlloc(); -} - -struct _xthread_waiter * -_Xthread_waiter(void) -{ - struct _xthread_waiter *me; - - if (!(me = TlsGetValue(_X_TlsIndex))) { - me = (struct _xthread_waiter *)xmalloc(sizeof(struct _xthread_waiter)); - me->sem = CreateSemaphore(NULL, 0, 1, NULL); - me->next = NULL; - TlsSetValue(_X_TlsIndex, me); - } - return me; -} -#endif /* WIN32 */ - -static xthread_t _Xthread_self(void) -{ - return xthread_self(); -} - -static LockInfoRec global_lock; -static LockInfoRec i18n_lock; - -static void _XLockMutex( - LockInfoPtr lip - XTHREADS_FILE_LINE_ARGS - ) -{ - xmutex_lock(lip->lock); -} - -static void _XUnlockMutex( - LockInfoPtr lip - XTHREADS_FILE_LINE_ARGS - ) -{ - xmutex_unlock(lip->lock); -} - -static void _XCreateMutex( - LockInfoPtr lip) -{ - lip->lock = xmutex_malloc(); - if (lip->lock) { - xmutex_init(lip->lock); - xmutex_set_name(lip->lock, "Xlib"); - } -} - -static void _XFreeMutex( - LockInfoPtr lip) -{ - xmutex_clear(lip->lock); - xmutex_free(lip->lock); -} - -#ifdef XTHREADS_WARN -static char *locking_file; -static int locking_line; -static xthread_t locking_thread; -static Bool xlibint_unlock = False; /* XlibInt.c may Unlock and re-Lock */ - -/* history that is useful to examine in a debugger */ -#define LOCK_HIST_SIZE 21 - -static struct { - Bool lockp; /* True for lock, False for unlock */ - xthread_t thread; - char *file; - int line; -} locking_history[LOCK_HIST_SIZE]; - -int lock_hist_loc = 0; /* next slot to fill */ - -static void _XLockDisplayWarn( - Display *dpy, - char *file, /* source file, from macro */ - int line) -{ - xthread_t self; - xthread_t old_locker; - - self = xthread_self(); - old_locker = locking_thread; - if (xthread_have_id(old_locker)) { - if (xthread_equal(old_locker, self)) - printf("Xlib ERROR: %s line %d thread %x: locking display already locked at %s line %d\n", - file, line, self, locking_file, locking_line); -#ifdef XTHREADS_DEBUG - else - printf("%s line %d: thread %x waiting on lock held by %s line %d thread %x\n", - file, line, self, - locking_file, locking_line, old_locker); -#endif /* XTHREADS_DEBUG */ - } - - xmutex_lock(dpy->lock->mutex); - - if (strcmp(file, "XlibInt.c") == 0) { - if (!xlibint_unlock) - printf("Xlib ERROR: XlibInt.c line %d thread %x locking display it did not unlock\n", - line, self); - xlibint_unlock = False; - } - -#ifdef XTHREADS_DEBUG - /* if (old_locker && old_locker != self) */ - if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */ - printf("%s line %d: thread %x got display lock\n", file, line, self); -#endif /* XTHREADS_DEBUG */ - - locking_thread = self; - if (strcmp(file, "XlibInt.c") != 0) { - locking_file = file; - locking_line = line; - } - locking_history[lock_hist_loc].file = file; - locking_history[lock_hist_loc].line = line; - locking_history[lock_hist_loc].thread = self; - locking_history[lock_hist_loc].lockp = True; - lock_hist_loc++; - if (lock_hist_loc >= LOCK_HIST_SIZE) - lock_hist_loc = 0; -} -#endif /* XTHREADS_WARN */ - -static void _XUnlockDisplay( - Display *dpy - XTHREADS_FILE_LINE_ARGS - ) -{ -#ifdef XTHREADS_WARN - xthread_t self = xthread_self(); - -#ifdef XTHREADS_DEBUG - if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */ - printf("%s line %d: thread %x unlocking display\n", file, line, self); -#endif /* XTHREADS_DEBUG */ - - if (!xthread_have_id(locking_thread)) - printf("Xlib ERROR: %s line %d thread %x: unlocking display that is not locked\n", - file, line, self); - else if (strcmp(file, "XlibInt.c") == 0) - xlibint_unlock = True; -#ifdef XTHREADS_DEBUG - else if (strcmp(file, locking_file) != 0) - /* not always an error because locking_file is not per-thread */ - printf("%s line %d: unlocking display locked from %s line %d (probably okay)\n", - file, line, locking_file, locking_line); -#endif /* XTHREADS_DEBUG */ - xthread_clear_id(locking_thread); - - locking_history[lock_hist_loc].file = file; - locking_history[lock_hist_loc].line = line; - locking_history[lock_hist_loc].thread = self; - locking_history[lock_hist_loc].lockp = False; - lock_hist_loc++; - if (lock_hist_loc >= LOCK_HIST_SIZE) - lock_hist_loc = 0; -#endif /* XTHREADS_WARN */ - xmutex_unlock(dpy->lock->mutex); -} - - -static struct _XCVList *_XCreateCVL( - Display *dpy) -{ - struct _XCVList *cvl; - - if ((cvl = dpy->lock->free_cvls) != NULL) { - dpy->lock->free_cvls = cvl->next; - dpy->lock->num_free_cvls--; - } else { - cvl = (struct _XCVList *)Xmalloc(sizeof(struct _XCVList)); - if (!cvl) - return NULL; - cvl->cv = xcondition_malloc(); - if (!cvl->cv) { - Xfree(cvl); - return NULL; - } - xcondition_init(cvl->cv); - xcondition_set_name(cvl->cv, "Xlib read queue"); - } - cvl->next = NULL; - return cvl; -} - -/* Put ourselves on the queue to read the connection. - Allocates and returns a queue element. */ - -static struct _XCVList * -_XPushReader( - Display *dpy, - struct _XCVList ***tail) -{ - struct _XCVList *cvl; - - cvl = _XCreateCVL(dpy); -#ifdef XTHREADS_DEBUG - printf("_XPushReader called in thread %x, pushing %x\n", - xthread_self(), cvl); -#endif - **tail = cvl; - *tail = &cvl->next; - return cvl; -} - -/* signal the next thread waiting to read the connection */ - -static void _XPopReader( - Display *dpy, - struct _XCVList **list, - struct _XCVList ***tail) -{ - register struct _XCVList *front = *list; - -#ifdef XTHREADS_DEBUG - printf("_XPopReader called in thread %x, popping %x\n", - xthread_self(), front); -#endif - - if (dpy->flags & XlibDisplayProcConni) - /* we never added ourself in the first place */ - return; - - if (front) { /* check "front" for paranoia */ - *list = front->next; - if (*tail == &front->next) /* did we free the last elt? */ - *tail = list; - if (dpy->lock->num_free_cvls < NUM_FREE_CVLS) { - front->next = dpy->lock->free_cvls; - dpy->lock->free_cvls = front; - dpy->lock->num_free_cvls++; - } else { - xcondition_clear(front->cv); - Xfree((char *)front->cv); - Xfree((char *)front); - } - } - - /* signal new front after it is in place */ - if ((dpy->lock->reply_first = (dpy->lock->reply_awaiters != NULL))) { - ConditionSignal(dpy, dpy->lock->reply_awaiters->cv); - } else if (dpy->lock->event_awaiters) { - ConditionSignal(dpy, dpy->lock->event_awaiters->cv); - } -} - -static void _XConditionWait( - xcondition_t cv, - xmutex_t mutex - XTHREADS_FILE_LINE_ARGS - ) -{ -#ifdef XTHREADS_WARN - xthread_t self = xthread_self(); - char *old_file = locking_file; - int old_line = locking_line; - -#ifdef XTHREADS_DEBUG - printf("line %d thread %x in condition wait\n", line, self); -#endif - xthread_clear_id(locking_thread); - - locking_history[lock_hist_loc].file = file; - locking_history[lock_hist_loc].line = line; - locking_history[lock_hist_loc].thread = self; - locking_history[lock_hist_loc].lockp = False; - lock_hist_loc++; - if (lock_hist_loc >= LOCK_HIST_SIZE) - lock_hist_loc = 0; -#endif /* XTHREADS_WARN */ - - xcondition_wait(cv, mutex); - -#ifdef XTHREADS_WARN - locking_thread = self; - locking_file = old_file; - locking_line = old_line; - - locking_history[lock_hist_loc].file = file; - locking_history[lock_hist_loc].line = line; - locking_history[lock_hist_loc].thread = self; - locking_history[lock_hist_loc].lockp = True; - lock_hist_loc++; - if (lock_hist_loc >= LOCK_HIST_SIZE) - lock_hist_loc = 0; -#ifdef XTHREADS_DEBUG - printf("line %d thread %x was signaled\n", line, self); -#endif /* XTHREADS_DEBUG */ -#endif /* XTHREADS_WARN */ -} - -static void _XConditionSignal( - xcondition_t cv - XTHREADS_FILE_LINE_ARGS - ) -{ -#ifdef XTHREADS_WARN -#ifdef XTHREADS_DEBUG - printf("line %d thread %x is signalling\n", line, xthread_self()); -#endif -#endif - xcondition_signal(cv); -} - - -static void _XConditionBroadcast( - xcondition_t cv - XTHREADS_FILE_LINE_ARGS - ) -{ -#ifdef XTHREADS_WARN -#ifdef XTHREADS_DEBUG - printf("line %d thread %x is broadcasting\n", line, xthread_self()); -#endif -#endif - xcondition_broadcast(cv); -} - - -static void _XFreeDisplayLock( - Display *dpy) -{ - struct _XCVList *cvl; - - if (dpy->lock != NULL) { - if (dpy->lock->mutex != NULL) { - xmutex_clear(dpy->lock->mutex); - xmutex_free(dpy->lock->mutex); - } - if (dpy->lock->cv != NULL) { - xcondition_clear(dpy->lock->cv); - xcondition_free(dpy->lock->cv); - } - if (dpy->lock->writers != NULL) { - xcondition_clear(dpy->lock->writers); - xcondition_free(dpy->lock->writers); - } - while ((cvl = dpy->lock->free_cvls)) { - dpy->lock->free_cvls = cvl->next; - xcondition_clear(cvl->cv); - Xfree((char *)cvl->cv); - Xfree((char *)cvl); - } - Xfree((char *)dpy->lock); - dpy->lock = NULL; - } - if (dpy->lock_fns != NULL) { - Xfree((char *)dpy->lock_fns); - dpy->lock_fns = NULL; - } -} - -/* - * wait for thread with user-level display lock to release it. - */ - -static void _XDisplayLockWait( - Display *dpy) -{ - xthread_t self; - - while (dpy->lock->locking_level > 0) { - self = xthread_self(); - if (xthread_equal(dpy->lock->locking_thread, self)) - break; - ConditionWait(dpy, dpy->lock->cv); - } -} - -static void _XLockDisplay( - Display *dpy - XTHREADS_FILE_LINE_ARGS - ) -{ -#ifdef XTHREADS_WARN - _XLockDisplayWarn(dpy, file, line); -#else - xmutex_lock(dpy->lock->mutex); -#endif - if (dpy->lock->locking_level > 0) - _XDisplayLockWait(dpy); -} - -/* - * _XReply is allowed to exit from select/poll and clean up even if a - * user-level lock is in force, so it uses this instead of _XFancyLockDisplay. - */ -static void _XInternalLockDisplay( - Display *dpy, - Bool wskip - XTHREADS_FILE_LINE_ARGS - ) -{ -#ifdef XTHREADS_WARN - _XLockDisplayWarn(dpy, file, line); -#else - xmutex_lock(dpy->lock->mutex); -#endif - if (!wskip && dpy->lock->locking_level > 0) - _XDisplayLockWait(dpy); -} - -static void _XUserLockDisplay( - register Display* dpy) -{ - if (++dpy->lock->locking_level == 1) { - dpy->lock->lock_wait = _XDisplayLockWait; - dpy->lock->locking_thread = xthread_self(); - } -} - -static -void _XUserUnlockDisplay( - register Display* dpy) -{ - if (dpy->lock->locking_level > 0 && --dpy->lock->locking_level == 0) { - /* signal other threads that might be waiting in XLockDisplay */ - ConditionBroadcast(dpy, dpy->lock->cv); - dpy->lock->lock_wait = NULL; - xthread_clear_id(dpy->lock->locking_thread); - } -} - -/* returns 0 if initialized ok, -1 if unable to allocate - a mutex or other memory */ - -static int _XInitDisplayLock( - Display *dpy) -{ - dpy->lock_fns = (struct _XLockPtrs*)Xmalloc(sizeof(struct _XLockPtrs)); - if (dpy->lock_fns == NULL) - return -1; - dpy->lock = (struct _XLockInfo *)Xmalloc(sizeof(struct _XLockInfo)); - if (dpy->lock == NULL) { - _XFreeDisplayLock(dpy); - return -1; - } - dpy->lock->cv = xcondition_malloc(); - dpy->lock->mutex = xmutex_malloc(); - dpy->lock->writers = xcondition_malloc(); - if (!dpy->lock->cv || !dpy->lock->mutex || !dpy->lock->writers) { - _XFreeDisplayLock(dpy); - return -1; - } - - dpy->lock->reply_bytes_left = 0; - dpy->lock->reply_was_read = False; - dpy->lock->reply_awaiters = NULL; - dpy->lock->reply_awaiters_tail = &dpy->lock->reply_awaiters; - dpy->lock->event_awaiters = NULL; - dpy->lock->event_awaiters_tail = &dpy->lock->event_awaiters; - dpy->lock->reply_first = False; - dpy->lock->locking_level = 0; - dpy->lock->num_free_cvls = 0; - dpy->lock->free_cvls = NULL; - xthread_clear_id(dpy->lock->locking_thread); - xthread_clear_id(dpy->lock->reading_thread); - xthread_clear_id(dpy->lock->conni_thread); - xmutex_init(dpy->lock->mutex); - xmutex_set_name(dpy->lock->mutex, "Xlib Display"); - xcondition_init(dpy->lock->cv); - xcondition_set_name(dpy->lock->cv, "XLockDisplay"); - xcondition_init(dpy->lock->writers); - xcondition_set_name(dpy->lock->writers, "Xlib wait for writable"); - dpy->lock_fns->lock_display = _XLockDisplay; - dpy->lock->internal_lock_display = _XInternalLockDisplay; - dpy->lock_fns->unlock_display = _XUnlockDisplay; - dpy->lock->user_lock_display = _XUserLockDisplay; - dpy->lock->user_unlock_display = _XUserUnlockDisplay; - dpy->lock->pop_reader = _XPopReader; - dpy->lock->push_reader = _XPushReader; - dpy->lock->condition_wait = _XConditionWait; - dpy->lock->condition_signal = _XConditionSignal; - dpy->lock->condition_broadcast = _XConditionBroadcast; - dpy->lock->create_cvl = _XCreateCVL; - dpy->lock->lock_wait = NULL; /* filled in by XLockDisplay() */ - - return 0; -} - -#ifdef __UNIXWARE__ -xthread_t __x11_thr_self() { return 0; } -xthread_t (*_x11_thr_self)() = __x11_thr_self; -#endif - - -Status XInitThreads(void) -{ - if (_Xglobal_lock) - return 1; -#ifdef __UNIXWARE__ - else { - void *dl_handle = dlopen(NULL, RTLD_LAZY); - if (!dl_handle || - ((_x11_thr_self = (xthread_t(*)())dlsym(dl_handle,"thr_self")) == 0)) { - _x11_thr_self = __x11_thr_self; - (void) fprintf (stderr, - "XInitThreads called, but no libthread in the calling program!\n" ); - } - } -#endif /* __UNIXWARE__ */ -#ifdef xthread_init - xthread_init(); /* return value? */ -#endif - if (!(global_lock.lock = xmutex_malloc())) - return 0; - if (!(i18n_lock.lock = xmutex_malloc())) { - xmutex_free(global_lock.lock); - global_lock.lock = NULL; - return 0; - } - _Xglobal_lock = &global_lock; - xmutex_init(_Xglobal_lock->lock); - xmutex_set_name(_Xglobal_lock->lock, "Xlib global"); - _Xi18n_lock = &i18n_lock; - xmutex_init(_Xi18n_lock->lock); - xmutex_set_name(_Xi18n_lock->lock, "Xlib i18n"); - _XLockMutex_fn = _XLockMutex; - _XUnlockMutex_fn = _XUnlockMutex; - _XCreateMutex_fn = _XCreateMutex; - _XFreeMutex_fn = _XFreeMutex; - _XInitDisplayLock_fn = _XInitDisplayLock; - _XFreeDisplayLock_fn = _XFreeDisplayLock; - _Xthread_self_fn = _Xthread_self; - -#ifdef XTHREADS_WARN -#ifdef XTHREADS_DEBUG - setlinebuf(stdout); /* for debugging messages */ -#endif -#endif - - return 1; -} - -#else /* XTHREADS */ -Status XInitThreads(void) -{ - return 0; -} -#endif /* XTHREADS */ +/* + +Copyright 1992, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * Author: Stephen Gildea, MIT X Consortium + * + * locking.c - multi-thread locking routines implemented in C Threads + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "Xlibint.h" +#undef _XLockMutex +#undef _XUnlockMutex +#undef _XCreateMutex +#undef _XFreeMutex + +#ifdef XTHREADS + +#ifdef __UNIXWARE__ +#include +#endif + +#include "Xprivate.h" +#include "locking.h" +#ifdef XTHREADS_WARN +#include /* for warn/debug stuff */ +#endif + +/* Additional arguments for source code location lock call was made from */ +#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) +# define XTHREADS_FILE_LINE_ARGS \ + , \ + char* file, /* source file, from macro */ \ + int line +#else +# define XTHREADS_FILE_LINE_ARGS /* None */ +#endif + + +#define NUM_FREE_CVLS 4 + +/* in lcWrap.c */ +extern LockInfoPtr _Xi18n_lock; + +#ifdef WIN32 +static DWORD _X_TlsIndex = (DWORD)-1; + +void _Xthread_init(void) +{ + if (_X_TlsIndex == (DWORD)-1) + _X_TlsIndex = TlsAlloc(); +} + +struct _xthread_waiter * +_Xthread_waiter(void) +{ + struct _xthread_waiter *me; + + if (!(me = TlsGetValue(_X_TlsIndex))) { + me = (struct _xthread_waiter *)xmalloc(sizeof(struct _xthread_waiter)); + me->sem = CreateSemaphore(NULL, 0, 1, NULL); + me->next = NULL; + TlsSetValue(_X_TlsIndex, me); + } + return me; +} +#endif /* WIN32 */ + +static xthread_t _Xthread_self(void) +{ + return xthread_self(); +} + +static LockInfoRec global_lock; +static LockInfoRec i18n_lock; + +static void _XLockMutex( + LockInfoPtr lip + XTHREADS_FILE_LINE_ARGS + ) +{ + xmutex_lock(lip->lock); +} + +static void _XUnlockMutex( + LockInfoPtr lip + XTHREADS_FILE_LINE_ARGS + ) +{ + xmutex_unlock(lip->lock); +} + +static void _XCreateMutex( + LockInfoPtr lip) +{ + lip->lock = xmutex_malloc(); + if (lip->lock) { + xmutex_init(lip->lock); + xmutex_set_name(lip->lock, "Xlib"); + } +} + +static void _XFreeMutex( + LockInfoPtr lip) +{ + xmutex_clear(lip->lock); + xmutex_free(lip->lock); +} + +#ifdef XTHREADS_WARN +static char *locking_file; +static int locking_line; +static xthread_t locking_thread; +static Bool xlibint_unlock = False; /* XlibInt.c may Unlock and re-Lock */ + +/* history that is useful to examine in a debugger */ +#define LOCK_HIST_SIZE 21 + +static struct { + Bool lockp; /* True for lock, False for unlock */ + xthread_t thread; + char *file; + int line; +} locking_history[LOCK_HIST_SIZE]; + +int lock_hist_loc = 0; /* next slot to fill */ + +static void _XLockDisplayWarn( + Display *dpy, + char *file, /* source file, from macro */ + int line) +{ + xthread_t self; + xthread_t old_locker; + + self = xthread_self(); + old_locker = locking_thread; + if (xthread_have_id(old_locker)) { + if (xthread_equal(old_locker, self)) + printf("Xlib ERROR: %s line %d thread %x: locking display already locked at %s line %d\n", + file, line, self, locking_file, locking_line); +#ifdef XTHREADS_DEBUG + else + printf("%s line %d: thread %x waiting on lock held by %s line %d thread %x\n", + file, line, self, + locking_file, locking_line, old_locker); +#endif /* XTHREADS_DEBUG */ + } + + xmutex_lock(dpy->lock->mutex); + + if (strcmp(file, "XlibInt.c") == 0) { + if (!xlibint_unlock) + printf("Xlib ERROR: XlibInt.c line %d thread %x locking display it did not unlock\n", + line, self); + xlibint_unlock = False; + } + +#ifdef XTHREADS_DEBUG + /* if (old_locker && old_locker != self) */ + if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */ + printf("%s line %d: thread %x got display lock\n", file, line, self); +#endif /* XTHREADS_DEBUG */ + + locking_thread = self; + if (strcmp(file, "XlibInt.c") != 0) { + locking_file = file; + locking_line = line; + } + locking_history[lock_hist_loc].file = file; + locking_history[lock_hist_loc].line = line; + locking_history[lock_hist_loc].thread = self; + locking_history[lock_hist_loc].lockp = True; + lock_hist_loc++; + if (lock_hist_loc >= LOCK_HIST_SIZE) + lock_hist_loc = 0; +} +#endif /* XTHREADS_WARN */ + +static void _XUnlockDisplay( + Display *dpy + XTHREADS_FILE_LINE_ARGS + ) +{ +#ifdef XTHREADS_WARN + xthread_t self = xthread_self(); + +#ifdef XTHREADS_DEBUG + if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */ + printf("%s line %d: thread %x unlocking display\n", file, line, self); +#endif /* XTHREADS_DEBUG */ + + if (!xthread_have_id(locking_thread)) + printf("Xlib ERROR: %s line %d thread %x: unlocking display that is not locked\n", + file, line, self); + else if (strcmp(file, "XlibInt.c") == 0) + xlibint_unlock = True; +#ifdef XTHREADS_DEBUG + else if (strcmp(file, locking_file) != 0) + /* not always an error because locking_file is not per-thread */ + printf("%s line %d: unlocking display locked from %s line %d (probably okay)\n", + file, line, locking_file, locking_line); +#endif /* XTHREADS_DEBUG */ + xthread_clear_id(locking_thread); + + locking_history[lock_hist_loc].file = file; + locking_history[lock_hist_loc].line = line; + locking_history[lock_hist_loc].thread = self; + locking_history[lock_hist_loc].lockp = False; + lock_hist_loc++; + if (lock_hist_loc >= LOCK_HIST_SIZE) + lock_hist_loc = 0; +#endif /* XTHREADS_WARN */ + xmutex_unlock(dpy->lock->mutex); +} + + +static struct _XCVList *_XCreateCVL( + Display *dpy) +{ + struct _XCVList *cvl; + + if ((cvl = dpy->lock->free_cvls) != NULL) { + dpy->lock->free_cvls = cvl->next; + dpy->lock->num_free_cvls--; + } else { + cvl = (struct _XCVList *)Xmalloc(sizeof(struct _XCVList)); + if (!cvl) + return NULL; + cvl->cv = xcondition_malloc(); + if (!cvl->cv) { + Xfree(cvl); + return NULL; + } + xcondition_init(cvl->cv); + xcondition_set_name(cvl->cv, "Xlib read queue"); + } + cvl->next = NULL; + return cvl; +} + +/* Put ourselves on the queue to read the connection. + Allocates and returns a queue element. */ + +static struct _XCVList * +_XPushReader( + Display *dpy, + struct _XCVList ***tail) +{ + struct _XCVList *cvl; + + cvl = _XCreateCVL(dpy); +#ifdef XTHREADS_DEBUG + printf("_XPushReader called in thread %x, pushing %x\n", + xthread_self(), cvl); +#endif + **tail = cvl; + *tail = &cvl->next; + return cvl; +} + +/* signal the next thread waiting to read the connection */ + +static void _XPopReader( + Display *dpy, + struct _XCVList **list, + struct _XCVList ***tail) +{ + register struct _XCVList *front = *list; + +#ifdef XTHREADS_DEBUG + printf("_XPopReader called in thread %x, popping %x\n", + xthread_self(), front); +#endif + + if (dpy->flags & XlibDisplayProcConni) + /* we never added ourself in the first place */ + return; + + if (front) { /* check "front" for paranoia */ + *list = front->next; + if (*tail == &front->next) /* did we free the last elt? */ + *tail = list; + if (dpy->lock->num_free_cvls < NUM_FREE_CVLS) { + front->next = dpy->lock->free_cvls; + dpy->lock->free_cvls = front; + dpy->lock->num_free_cvls++; + } else { + xcondition_clear(front->cv); + Xfree((char *)front->cv); + Xfree((char *)front); + } + } + + /* signal new front after it is in place */ + if ((dpy->lock->reply_first = (dpy->lock->reply_awaiters != NULL))) { + ConditionSignal(dpy, dpy->lock->reply_awaiters->cv); + } else if (dpy->lock->event_awaiters) { + ConditionSignal(dpy, dpy->lock->event_awaiters->cv); + } +} + +static void _XConditionWait( + xcondition_t cv, + xmutex_t mutex + XTHREADS_FILE_LINE_ARGS + ) +{ +#ifdef XTHREADS_WARN + xthread_t self = xthread_self(); + char *old_file = locking_file; + int old_line = locking_line; + +#ifdef XTHREADS_DEBUG + printf("line %d thread %x in condition wait\n", line, self); +#endif + xthread_clear_id(locking_thread); + + locking_history[lock_hist_loc].file = file; + locking_history[lock_hist_loc].line = line; + locking_history[lock_hist_loc].thread = self; + locking_history[lock_hist_loc].lockp = False; + lock_hist_loc++; + if (lock_hist_loc >= LOCK_HIST_SIZE) + lock_hist_loc = 0; +#endif /* XTHREADS_WARN */ + + xcondition_wait(cv, mutex); + +#ifdef XTHREADS_WARN + locking_thread = self; + locking_file = old_file; + locking_line = old_line; + + locking_history[lock_hist_loc].file = file; + locking_history[lock_hist_loc].line = line; + locking_history[lock_hist_loc].thread = self; + locking_history[lock_hist_loc].lockp = True; + lock_hist_loc++; + if (lock_hist_loc >= LOCK_HIST_SIZE) + lock_hist_loc = 0; +#ifdef XTHREADS_DEBUG + printf("line %d thread %x was signaled\n", line, self); +#endif /* XTHREADS_DEBUG */ +#endif /* XTHREADS_WARN */ +} + +static void _XConditionSignal( + xcondition_t cv + XTHREADS_FILE_LINE_ARGS + ) +{ +#ifdef XTHREADS_WARN +#ifdef XTHREADS_DEBUG + printf("line %d thread %x is signalling\n", line, xthread_self()); +#endif +#endif + xcondition_signal(cv); +} + + +static void _XConditionBroadcast( + xcondition_t cv + XTHREADS_FILE_LINE_ARGS + ) +{ +#ifdef XTHREADS_WARN +#ifdef XTHREADS_DEBUG + printf("line %d thread %x is broadcasting\n", line, xthread_self()); +#endif +#endif + xcondition_broadcast(cv); +} + + +static void _XFreeDisplayLock( + Display *dpy) +{ + struct _XCVList *cvl; + + if (dpy->lock != NULL) { + if (dpy->lock->mutex != NULL) { + xmutex_clear(dpy->lock->mutex); + xmutex_free(dpy->lock->mutex); + } + if (dpy->lock->cv != NULL) { + xcondition_clear(dpy->lock->cv); + xcondition_free(dpy->lock->cv); + } + if (dpy->lock->writers != NULL) { + xcondition_clear(dpy->lock->writers); + xcondition_free(dpy->lock->writers); + } + while ((cvl = dpy->lock->free_cvls)) { + dpy->lock->free_cvls = cvl->next; + xcondition_clear(cvl->cv); + Xfree((char *)cvl->cv); + Xfree((char *)cvl); + } + Xfree((char *)dpy->lock); + dpy->lock = NULL; + } + if (dpy->lock_fns != NULL) { + Xfree((char *)dpy->lock_fns); + dpy->lock_fns = NULL; + } +} + +/* + * wait for thread with user-level display lock to release it. + */ + +static void _XDisplayLockWait( + Display *dpy) +{ + xthread_t self; + + while (dpy->lock->locking_level > 0) { + self = xthread_self(); + if (xthread_equal(dpy->lock->locking_thread, self)) + break; + ConditionWait(dpy, dpy->lock->cv); + } +} + +static void _XLockDisplay( + Display *dpy + XTHREADS_FILE_LINE_ARGS + ) +{ +#ifdef XTHREADS_WARN + _XLockDisplayWarn(dpy, file, line); +#else + xmutex_lock(dpy->lock->mutex); +#endif + if (dpy->lock->locking_level > 0) + _XDisplayLockWait(dpy); + _XIDHandler(dpy); + _XSeqSyncFunction(dpy); +} + +/* + * _XReply is allowed to exit from select/poll and clean up even if a + * user-level lock is in force, so it uses this instead of _XFancyLockDisplay. + */ +static void _XInternalLockDisplay( + Display *dpy, + Bool wskip + XTHREADS_FILE_LINE_ARGS + ) +{ +#ifdef XTHREADS_WARN + _XLockDisplayWarn(dpy, file, line); +#else + xmutex_lock(dpy->lock->mutex); +#endif + if (!wskip && dpy->lock->locking_level > 0) + _XDisplayLockWait(dpy); +} + +static void _XUserLockDisplay( + register Display* dpy) +{ + if (++dpy->lock->locking_level == 1) { + dpy->lock->lock_wait = _XDisplayLockWait; + dpy->lock->locking_thread = xthread_self(); + } +} + +static +void _XUserUnlockDisplay( + register Display* dpy) +{ + if (dpy->lock->locking_level > 0 && --dpy->lock->locking_level == 0) { + /* signal other threads that might be waiting in XLockDisplay */ + ConditionBroadcast(dpy, dpy->lock->cv); + dpy->lock->lock_wait = NULL; + xthread_clear_id(dpy->lock->locking_thread); + } +} + +/* returns 0 if initialized ok, -1 if unable to allocate + a mutex or other memory */ + +static int _XInitDisplayLock( + Display *dpy) +{ + dpy->lock_fns = (struct _XLockPtrs*)Xmalloc(sizeof(struct _XLockPtrs)); + if (dpy->lock_fns == NULL) + return -1; + dpy->lock = (struct _XLockInfo *)Xmalloc(sizeof(struct _XLockInfo)); + if (dpy->lock == NULL) { + _XFreeDisplayLock(dpy); + return -1; + } + dpy->lock->cv = xcondition_malloc(); + dpy->lock->mutex = xmutex_malloc(); + dpy->lock->writers = xcondition_malloc(); + if (!dpy->lock->cv || !dpy->lock->mutex || !dpy->lock->writers) { + _XFreeDisplayLock(dpy); + return -1; + } + + dpy->lock->reply_bytes_left = 0; + dpy->lock->reply_was_read = False; + dpy->lock->reply_awaiters = NULL; + dpy->lock->reply_awaiters_tail = &dpy->lock->reply_awaiters; + dpy->lock->event_awaiters = NULL; + dpy->lock->event_awaiters_tail = &dpy->lock->event_awaiters; + dpy->lock->reply_first = False; + dpy->lock->locking_level = 0; + dpy->lock->num_free_cvls = 0; + dpy->lock->free_cvls = NULL; + xthread_clear_id(dpy->lock->locking_thread); + xthread_clear_id(dpy->lock->reading_thread); + xthread_clear_id(dpy->lock->conni_thread); + xmutex_init(dpy->lock->mutex); + xmutex_set_name(dpy->lock->mutex, "Xlib Display"); + xcondition_init(dpy->lock->cv); + xcondition_set_name(dpy->lock->cv, "XLockDisplay"); + xcondition_init(dpy->lock->writers); + xcondition_set_name(dpy->lock->writers, "Xlib wait for writable"); + dpy->lock_fns->lock_display = _XLockDisplay; + dpy->lock->internal_lock_display = _XInternalLockDisplay; + dpy->lock_fns->unlock_display = _XUnlockDisplay; + dpy->lock->user_lock_display = _XUserLockDisplay; + dpy->lock->user_unlock_display = _XUserUnlockDisplay; + dpy->lock->pop_reader = _XPopReader; + dpy->lock->push_reader = _XPushReader; + dpy->lock->condition_wait = _XConditionWait; + dpy->lock->condition_signal = _XConditionSignal; + dpy->lock->condition_broadcast = _XConditionBroadcast; + dpy->lock->create_cvl = _XCreateCVL; + dpy->lock->lock_wait = NULL; /* filled in by XLockDisplay() */ + + return 0; +} + +#ifdef __UNIXWARE__ +xthread_t __x11_thr_self() { return 0; } +xthread_t (*_x11_thr_self)() = __x11_thr_self; +#endif + + +Status XInitThreads(void) +{ + if (_Xglobal_lock) + return 1; +#ifdef __UNIXWARE__ + else { + void *dl_handle = dlopen(NULL, RTLD_LAZY); + if (!dl_handle || + ((_x11_thr_self = (xthread_t(*)())dlsym(dl_handle,"thr_self")) == 0)) { + _x11_thr_self = __x11_thr_self; + (void) fprintf (stderr, + "XInitThreads called, but no libthread in the calling program!\n" ); + } + } +#endif /* __UNIXWARE__ */ +#ifdef xthread_init + xthread_init(); /* return value? */ +#endif + if (!(global_lock.lock = xmutex_malloc())) + return 0; + if (!(i18n_lock.lock = xmutex_malloc())) { + xmutex_free(global_lock.lock); + global_lock.lock = NULL; + return 0; + } + _Xglobal_lock = &global_lock; + xmutex_init(_Xglobal_lock->lock); + xmutex_set_name(_Xglobal_lock->lock, "Xlib global"); + _Xi18n_lock = &i18n_lock; + xmutex_init(_Xi18n_lock->lock); + xmutex_set_name(_Xi18n_lock->lock, "Xlib i18n"); + _XLockMutex_fn = _XLockMutex; + _XUnlockMutex_fn = _XUnlockMutex; + _XCreateMutex_fn = _XCreateMutex; + _XFreeMutex_fn = _XFreeMutex; + _XInitDisplayLock_fn = _XInitDisplayLock; + _XFreeDisplayLock_fn = _XFreeDisplayLock; + _Xthread_self_fn = _Xthread_self; + +#ifdef XTHREADS_WARN +#ifdef XTHREADS_DEBUG + setlinebuf(stdout); /* for debugging messages */ +#endif +#endif + + return 1; +} + +#else /* XTHREADS */ +Status XInitThreads(void) +{ + return 0; +} +#endif /* XTHREADS */ -- cgit v1.2.3