tclThread.c

Go 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  doxygen 1.5.1