tclThread.cGo to the documentation of this file.00001 /* 00002 * tclThread.c -- 00003 * 00004 * This file implements Platform independent thread operations. Most of 00005 * the real work is done in the platform dependent files. 00006 * 00007 * Copyright (c) 1998 by Sun Microsystems, Inc. 00008 * 00009 * See the file "license.terms" for information on usage and redistribution of 00010 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00011 * 00012 * RCS: @(#) $Id: tclThread.c,v 1.19 2007/12/13 15:23:20 dgp Exp $ 00013 */ 00014 00015 #include "tclInt.h" 00016 00017 /* 00018 * There are three classes of synchronization objects: mutexes, thread data 00019 * keys, and condition variables. The following are used to record the memory 00020 * used for these objects so they can be finalized. 00021 * 00022 * These statics are guarded by the mutex in the caller of 00023 * TclRememberThreadData, e.g., TclpThreadDataKeyInit 00024 */ 00025 00026 typedef struct { 00027 int num; /* Number of objects remembered */ 00028 int max; /* Max size of the array */ 00029 char **list; /* List of pointers */ 00030 } SyncObjRecord; 00031 00032 static SyncObjRecord keyRecord = {0, 0, NULL}; 00033 static SyncObjRecord mutexRecord = {0, 0, NULL}; 00034 static SyncObjRecord condRecord = {0, 0, NULL}; 00035 00036 /* 00037 * Prototypes of functions used only in this file. 00038 */ 00039 00040 static void ForgetSyncObject(char *objPtr, SyncObjRecord *recPtr); 00041 static void RememberSyncObject(char *objPtr, 00042 SyncObjRecord *recPtr); 00043 00044 /* 00045 * Several functions are #defined to nothing in tcl.h if TCL_THREADS is not 00046 * specified. Here we undo that so the functions are defined in the stubs 00047 * table. 00048 */ 00049 00050 #ifndef TCL_THREADS 00051 #undef Tcl_MutexLock 00052 #undef Tcl_MutexUnlock 00053 #undef Tcl_MutexFinalize 00054 #undef Tcl_ConditionNotify 00055 #undef Tcl_ConditionWait 00056 #undef Tcl_ConditionFinalize 00057 #endif 00058 00059 /* 00060 *---------------------------------------------------------------------- 00061 * 00062 * Tcl_GetThreadData -- 00063 * 00064 * This function allocates and initializes a chunk of thread local 00065 * storage. 00066 * 00067 * Results: 00068 * A thread-specific pointer to the data structure. 00069 * 00070 * Side effects: 00071 * Will allocate memory the first time this thread calls for this chunk 00072 * of storage. 00073 * 00074 *---------------------------------------------------------------------- 00075 */ 00076 00077 void * 00078 Tcl_GetThreadData( 00079 Tcl_ThreadDataKey *keyPtr, /* Identifier for the data chunk */ 00080 int size) /* Size of storage block */ 00081 { 00082 void *result; 00083 #ifdef TCL_THREADS 00084 /* 00085 * Initialize the key for this thread. 00086 */ 00087 result = TclpThreadDataKeyGet(keyPtr); 00088 00089 if (result == NULL) { 00090 result = ckalloc((size_t) size); 00091 memset(result, 0, (size_t) size); 00092 TclpThreadDataKeySet(keyPtr, result); 00093 } 00094 #else /* TCL_THREADS */ 00095 if (*keyPtr == NULL) { 00096 result = ckalloc((size_t) size); 00097 memset(result, 0, (size_t) size); 00098 *keyPtr = (Tcl_ThreadDataKey)result; 00099 RememberSyncObject((char *) keyPtr, &keyRecord); 00100 } 00101 result = * (void **) keyPtr; 00102 #endif /* TCL_THREADS */ 00103 return result; 00104 } 00105 00106 /* 00107 *---------------------------------------------------------------------- 00108 * 00109 * TclThreadDataKeyGet -- 00110 * 00111 * This function returns a pointer to a block of thread local storage. 00112 * 00113 * Results: 00114 * A thread-specific pointer to the data structure, or NULL if the memory 00115 * has not been assigned to this key for this thread. 00116 * 00117 * Side effects: 00118 * None. 00119 * 00120 *---------------------------------------------------------------------- 00121 */ 00122 00123 void * 00124 TclThreadDataKeyGet( 00125 Tcl_ThreadDataKey *keyPtr) /* Identifier for the data chunk, really 00126 * (pthread_key_t **) */ 00127 { 00128 #ifdef TCL_THREADS 00129 return TclpThreadDataKeyGet(keyPtr); 00130 #else /* TCL_THREADS */ 00131 char *result = *(char **) keyPtr; 00132 return result; 00133 #endif /* TCL_THREADS */ 00134 } 00135 00136 00137 /* 00138 *---------------------------------------------------------------------- 00139 * 00140 * RememberSyncObject 00141 * 00142 * Keep a list of (mutexes/condition variable/data key) used during 00143 * finalization. 00144 * 00145 * Assume master lock is held. 00146 * 00147 * Results: 00148 * None. 00149 * 00150 * Side effects: 00151 * Add to the appropriate list. 00152 * 00153 *---------------------------------------------------------------------- 00154 */ 00155 00156 static void 00157 RememberSyncObject( 00158 char *objPtr, /* Pointer to sync object */ 00159 SyncObjRecord *recPtr) /* Record of sync objects */ 00160 { 00161 char **newList; 00162 int i, j; 00163 00164 00165 /* 00166 * Reuse any free slot in the list. 00167 */ 00168 00169 for (i=0 ; i < recPtr->num ; ++i) { 00170 if (recPtr->list[i] == NULL) { 00171 recPtr->list[i] = objPtr; 00172 return; 00173 } 00174 } 00175 00176 /* 00177 * Grow the list of pointers if necessary, copying only non-NULL 00178 * pointers to the new list. 00179 */ 00180 00181 if (recPtr->num >= recPtr->max) { 00182 recPtr->max += 8; 00183 newList = (char **) ckalloc(recPtr->max * sizeof(char *)); 00184 for (i=0,j=0 ; i<recPtr->num ; i++) { 00185 if (recPtr->list[i] != NULL) { 00186 newList[j++] = recPtr->list[i]; 00187 } 00188 } 00189 if (recPtr->list != NULL) { 00190 ckfree((char *) recPtr->list); 00191 } 00192 recPtr->list = newList; 00193 recPtr->num = j; 00194 } 00195 00196 recPtr->list[recPtr->num] = objPtr; 00197 recPtr->num++; 00198 } 00199 00200 /* 00201 *---------------------------------------------------------------------- 00202 * 00203 * ForgetSyncObject 00204 * 00205 * Remove a single object from the list. 00206 * Assume master lock is held. 00207 * 00208 * Results: 00209 * None. 00210 * 00211 * Side effects: 00212 * Remove from the appropriate list. 00213 * 00214 *---------------------------------------------------------------------- 00215 */ 00216 00217 static void 00218 ForgetSyncObject( 00219 char *objPtr, /* Pointer to sync object */ 00220 SyncObjRecord *recPtr) /* Record of sync objects */ 00221 { 00222 int i; 00223 00224 for (i=0 ; i<recPtr->num ; i++) { 00225 if (objPtr == recPtr->list[i]) { 00226 recPtr->list[i] = NULL; 00227 return; 00228 } 00229 } 00230 } 00231 00232 /* 00233 *---------------------------------------------------------------------- 00234 * 00235 * TclRememberMutex 00236 * 00237 * Keep a list of mutexes used during finalization. 00238 * Assume master lock is held. 00239 * 00240 * Results: 00241 * None. 00242 * 00243 * Side effects: 00244 * Add to the mutex list. 00245 * 00246 *---------------------------------------------------------------------- 00247 */ 00248 00249 void 00250 TclRememberMutex( 00251 Tcl_Mutex *mutexPtr) 00252 { 00253 RememberSyncObject((char *)mutexPtr, &mutexRecord); 00254 } 00255 00256 /* 00257 *---------------------------------------------------------------------- 00258 * 00259 * Tcl_MutexFinalize -- 00260 * 00261 * Finalize a single mutex and remove it from the list of remembered 00262 * objects. 00263 * 00264 * Results: 00265 * None. 00266 * 00267 * Side effects: 00268 * Remove the mutex from the list. 00269 * 00270 *---------------------------------------------------------------------- 00271 */ 00272 00273 void 00274 Tcl_MutexFinalize( 00275 Tcl_Mutex *mutexPtr) 00276 { 00277 #ifdef TCL_THREADS 00278 TclpFinalizeMutex(mutexPtr); 00279 #endif 00280 TclpMasterLock(); 00281 ForgetSyncObject((char *) mutexPtr, &mutexRecord); 00282 TclpMasterUnlock(); 00283 } 00284 00285 /* 00286 *---------------------------------------------------------------------- 00287 * 00288 * TclRememberCondition 00289 * 00290 * Keep a list of condition variables used during finalization. 00291 * Assume master lock is held. 00292 * 00293 * Results: 00294 * None. 00295 * 00296 * Side effects: 00297 * Add to the condition variable list. 00298 * 00299 *---------------------------------------------------------------------- 00300 */ 00301 00302 void 00303 TclRememberCondition( 00304 Tcl_Condition *condPtr) 00305 { 00306 RememberSyncObject((char *) condPtr, &condRecord); 00307 } 00308 00309 /* 00310 *---------------------------------------------------------------------- 00311 * 00312 * Tcl_ConditionFinalize -- 00313 * 00314 * Finalize a single condition variable and remove it from the list of 00315 * remembered objects. 00316 * 00317 * Results: 00318 * None. 00319 * 00320 * Side effects: 00321 * Remove the condition variable from the list. 00322 * 00323 *---------------------------------------------------------------------- 00324 */ 00325 00326 void 00327 Tcl_ConditionFinalize( 00328 Tcl_Condition *condPtr) 00329 { 00330 #ifdef TCL_THREADS 00331 TclpFinalizeCondition(condPtr); 00332 #endif 00333 TclpMasterLock(); 00334 ForgetSyncObject((char *) condPtr, &condRecord); 00335 TclpMasterUnlock(); 00336 } 00337 00338 /* 00339 *---------------------------------------------------------------------- 00340 * 00341 * TclFinalizeThreadData -- 00342 * 00343 * This function cleans up the thread-local storage. This is called once 00344 * for each thread. 00345 * 00346 * Results: 00347 * None. 00348 * 00349 * Side effects: 00350 * Frees up all thread local storage. 00351 * 00352 *---------------------------------------------------------------------- 00353 */ 00354 00355 void 00356 TclFinalizeThreadData(void) 00357 { 00358 TclpFinalizeThreadDataThread(); 00359 } 00360 00361 /* 00362 *---------------------------------------------------------------------- 00363 * 00364 * TclFinalizeSynchronization -- 00365 * 00366 * This function cleans up all synchronization objects: mutexes, 00367 * condition variables, and thread-local storage. 00368 * 00369 * Results: 00370 * None. 00371 * 00372 * Side effects: 00373 * Frees up the memory. 00374 * 00375 *---------------------------------------------------------------------- 00376 */ 00377 00378 void 00379 TclFinalizeSynchronization(void) 00380 { 00381 int i; 00382 void *blockPtr; 00383 Tcl_ThreadDataKey *keyPtr; 00384 #ifdef TCL_THREADS 00385 Tcl_Mutex *mutexPtr; 00386 Tcl_Condition *condPtr; 00387 00388 TclpMasterLock(); 00389 #endif 00390 00391 /* 00392 * If we're running unthreaded, the TSD blocks are simply stored inside 00393 * their thread data keys. Free them here. 00394 */ 00395 00396 if (keyRecord.list != NULL) { 00397 for (i=0 ; i<keyRecord.num ; i++) { 00398 keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i]; 00399 blockPtr = (void *) *keyPtr; 00400 ckfree(blockPtr); 00401 } 00402 ckfree((char *) keyRecord.list); 00403 keyRecord.list = NULL; 00404 } 00405 keyRecord.max = 0; 00406 keyRecord.num = 0; 00407 00408 #ifdef TCL_THREADS 00409 /* 00410 * Call thread storage master cleanup. 00411 */ 00412 00413 TclFinalizeThreadStorage(); 00414 00415 for (i=0 ; i<mutexRecord.num ; i++) { 00416 mutexPtr = (Tcl_Mutex *)mutexRecord.list[i]; 00417 if (mutexPtr != NULL) { 00418 TclpFinalizeMutex(mutexPtr); 00419 } 00420 } 00421 if (mutexRecord.list != NULL) { 00422 ckfree((char *) mutexRecord.list); 00423 mutexRecord.list = NULL; 00424 } 00425 mutexRecord.max = 0; 00426 mutexRecord.num = 0; 00427 00428 for (i=0 ; i<condRecord.num ; i++) { 00429 condPtr = (Tcl_Condition *) condRecord.list[i]; 00430 if (condPtr != NULL) { 00431 TclpFinalizeCondition(condPtr); 00432 } 00433 } 00434 if (condRecord.list != NULL) { 00435 ckfree((char *) condRecord.list); 00436 condRecord.list = NULL; 00437 } 00438 condRecord.max = 0; 00439 condRecord.num = 0; 00440 00441 TclpMasterUnlock(); 00442 #endif /* TCL_THREADS */ 00443 } 00444 00445 /* 00446 *---------------------------------------------------------------------- 00447 * 00448 * Tcl_ExitThread -- 00449 * 00450 * This function is called to terminate the current thread. This should 00451 * be used by extensions that create threads with additional interpreters 00452 * in them. 00453 * 00454 * Results: 00455 * None. 00456 * 00457 * Side effects: 00458 * All thread exit handlers are invoked, then the thread dies. 00459 * 00460 *---------------------------------------------------------------------- 00461 */ 00462 00463 void 00464 Tcl_ExitThread( 00465 int status) 00466 { 00467 Tcl_FinalizeThread(); 00468 #ifdef TCL_THREADS 00469 TclpThreadExit(status); 00470 #endif 00471 } 00472 00473 #ifndef TCL_THREADS 00474 00475 /* 00476 *---------------------------------------------------------------------- 00477 * 00478 * Tcl_ConditionWait, et al. -- 00479 * 00480 * These noop functions are provided so the stub table does not have to 00481 * be conditionalized for threads. The real implementations of these 00482 * functions live in the platform specific files. 00483 * 00484 * Results: 00485 * None. 00486 * 00487 * Side effects: 00488 * None. 00489 * 00490 *---------------------------------------------------------------------- 00491 */ 00492 00493 #undef Tcl_ConditionWait 00494 void 00495 Tcl_ConditionWait( 00496 Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */ 00497 Tcl_Mutex *mutexPtr, /* Really (pthread_mutex_t **) */ 00498 Tcl_Time *timePtr) /* Timeout on waiting period */ 00499 { 00500 } 00501 00502 #undef Tcl_ConditionNotify 00503 void 00504 Tcl_ConditionNotify( 00505 Tcl_Condition *condPtr) 00506 { 00507 } 00508 00509 #undef Tcl_MutexLock 00510 void 00511 Tcl_MutexLock( 00512 Tcl_Mutex *mutexPtr) 00513 { 00514 } 00515 00516 #undef Tcl_MutexUnlock 00517 void 00518 Tcl_MutexUnlock( 00519 Tcl_Mutex *mutexPtr) 00520 { 00521 } 00522 #endif /* !TCL_THREADS */ 00523 00524 /* 00525 * Local Variables: 00526 * mode: c 00527 * c-basic-offset: 4 00528 * fill-column: 78 00529 * End: 00530 */
Generated on Wed Mar 12 12:18:22 2008 by 1.5.1 |