diff options
author | Mihai Moldovan <ionic@ionic.de> | 2017-08-25 12:44:49 +0200 |
---|---|---|
committer | Mihai Moldovan <ionic@ionic.de> | 2017-08-25 12:44:49 +0200 |
commit | ae0a2bfdeb9ceacb80aa03375353039d425b14b9 (patch) | |
tree | daec55145477bcec69273e03d5c9ff10c10a4137 /nx-X11/lib/src/locking.c | |
parent | cbe2c0e44f412d07024207f374c0f56684adb088 (diff) | |
parent | 3b7e5a42f5abecb903a9d730d163d704520efb07 (diff) | |
download | nx-libs-ae0a2bfdeb9ceacb80aa03375353039d425b14b9.tar.gz nx-libs-ae0a2bfdeb9ceacb80aa03375353039d425b14b9.tar.bz2 nx-libs-ae0a2bfdeb9ceacb80aa03375353039d425b14b9.zip |
Merge branch 'sunweaver-pr/libnx-x11-autoreconf' into 3.6.x
Attributes GH PR #498: https://github.com/ArcticaProject/nx-libs/pull/498
Diffstat (limited to 'nx-X11/lib/src/locking.c')
-rw-r--r-- | nx-X11/lib/src/locking.c | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/nx-X11/lib/src/locking.c b/nx-X11/lib/src/locking.c new file mode 100644 index 000000000..9f4fe0677 --- /dev/null +++ b/nx-X11/lib/src/locking.c @@ -0,0 +1,625 @@ +/* + +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 <config.h> +#endif +#include "Xlibint.h" +#undef _XLockMutex +#undef _XUnlockMutex +#undef _XCreateMutex +#undef _XFreeMutex + +#ifdef XTHREADS + +#ifdef __UNIXWARE__ +#include <dlfcn.h> +#endif + +#include "Xprivate.h" +#include "locking.h" +#ifdef XTHREADS_WARN +#include <stdio.h> /* 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 = 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 = 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(front->cv); + Xfree(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(cvl->cv); + Xfree(cvl); + } + Xfree(dpy->lock); + dpy->lock = NULL; + } + if (dpy->lock_fns != NULL) { + Xfree(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) +{ + _XDisplayLockWait(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 = Xmalloc(sizeof(struct _XLockPtrs)); + if (dpy->lock_fns == NULL) + return -1; + dpy->lock = 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 */ |