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