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