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