tclThread.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:13k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclThread.c --
  3.  *
  4.  * This file implements   Platform independent thread operations.
  5.  * Most of the real work is done in the platform dependent files.
  6.  *
  7.  * Copyright (c) 1998 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclThread.c,v 1.6.2.3 2007/11/26 14:05:10 vasiljevic Exp $
  13.  */
  14. #include "tclInt.h"
  15. /*
  16.  * There are three classes of synchronization objects:
  17.  * mutexes, thread data keys, and condition variables.
  18.  * The following are used to record the memory used for these
  19.  * objects so they can be finalized.
  20.  *
  21.  * These statics are guarded by the mutex in the caller of
  22.  * TclRememberThreadData, e.g., TclpThreadDataKeyInit
  23.  */
  24. typedef struct {
  25.     int num; /* Number of objects remembered */
  26.     int max; /* Max size of the array */
  27.     char **list; /* List of pointers */
  28. } SyncObjRecord;
  29. static SyncObjRecord keyRecord = {0, 0, NULL};
  30. static SyncObjRecord mutexRecord = {0, 0, NULL};
  31. static SyncObjRecord condRecord = {0, 0, NULL};
  32. /*
  33.  * Prototypes of functions used only in this file
  34.  */
  35.  
  36. static void RememberSyncObject _ANSI_ARGS_((char *objPtr,
  37.     SyncObjRecord *recPtr));
  38. static void ForgetSyncObject _ANSI_ARGS_((char *objPtr,
  39.     SyncObjRecord *recPtr));
  40. /* 
  41.  * Several functions are #defined to nothing in tcl.h if TCL_THREADS is not
  42.  * specified.  Here we undo that so the procedures are defined in the
  43.  * stubs table.
  44.  */
  45. #ifndef TCL_THREADS
  46. #undef Tcl_MutexLock
  47. #undef Tcl_MutexUnlock
  48. #undef Tcl_MutexFinalize
  49. #undef Tcl_ConditionNotify
  50. #undef Tcl_ConditionWait
  51. #undef Tcl_ConditionFinalize
  52. #endif
  53. /*
  54.  *----------------------------------------------------------------------
  55.  *
  56.  * Tcl_GetThreadData --
  57.  *
  58.  * This procedure allocates and initializes a chunk of thread
  59.  * local storage.
  60.  *
  61.  * Results:
  62.  * A thread-specific pointer to the data structure.
  63.  *
  64.  * Side effects:
  65.  * Will allocate memory the first time this thread calls for
  66.  * this chunk of storage.
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70. VOID *
  71. Tcl_GetThreadData(keyPtr, size)
  72.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk */
  73.     int size; /* Size of storage block */
  74. {
  75.     VOID *result;
  76. #ifdef TCL_THREADS
  77.     /*
  78.      * See if this is the first thread to init this key.
  79.      */
  80.     if (*keyPtr == NULL) {
  81. TclpThreadDataKeyInit(keyPtr);
  82.     }
  83.     /*
  84.      * Initialize the key for this thread.
  85.      */
  86.     result = TclpThreadDataKeyGet(keyPtr);
  87.     if (result == NULL) {
  88. result  = (VOID *)ckalloc((size_t)size);
  89. memset(result, 0, (size_t)size);
  90. TclpThreadDataKeySet(keyPtr, result);
  91.     }
  92. #else
  93.     if (*keyPtr == NULL) {
  94. result = (VOID *)ckalloc((size_t)size);
  95. memset((char *)result, 0, (size_t)size);
  96. *keyPtr = (Tcl_ThreadDataKey)result;
  97. TclRememberDataKey(keyPtr);
  98.     }
  99.     result = *(VOID **)keyPtr;
  100. #endif
  101.     return result;
  102. }
  103. /*
  104.  *----------------------------------------------------------------------
  105.  *
  106.  * TclThreadDataKeyGet --
  107.  *
  108.  * This procedure returns a pointer to a block of thread local storage.
  109.  *
  110.  * Results:
  111.  * A thread-specific pointer to the data structure, or NULL
  112.  * if the memory has not been assigned to this key for this thread.
  113.  *
  114.  * Side effects:
  115.  * None.
  116.  *
  117.  *----------------------------------------------------------------------
  118.  */
  119. VOID *
  120. TclThreadDataKeyGet(keyPtr)
  121.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  122.  * really (pthread_key_t **) */
  123. {
  124. #ifdef TCL_THREADS
  125.     return (VOID *)TclpThreadDataKeyGet(keyPtr);
  126. #else
  127.     char *result = *(char **)keyPtr;
  128.     return (VOID *)result;
  129. #endif /* TCL_THREADS */
  130. }
  131. /*
  132.  *----------------------------------------------------------------------
  133.  *
  134.  * TclThreadDataKeySet --
  135.  *
  136.  * This procedure sets a thread local storage pointer.
  137.  *
  138.  * Results:
  139.  * None.
  140.  *
  141.  * Side effects:
  142.  * The assigned value will be returned by TclpThreadDataKeyGet.
  143.  *
  144.  *----------------------------------------------------------------------
  145.  */
  146. void
  147. TclThreadDataKeySet(keyPtr, data)
  148.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  149.  * really (pthread_key_t **) */
  150.     VOID *data; /* Thread local storage */
  151. {
  152. #ifdef TCL_THREADS
  153.     if (*keyPtr == NULL) {
  154. TclpThreadDataKeyInit(keyPtr);
  155.     }
  156.     TclpThreadDataKeySet(keyPtr, data);
  157. #else
  158.     *keyPtr = (Tcl_ThreadDataKey)data;
  159. #endif /* TCL_THREADS */
  160. }
  161. /*
  162.  *----------------------------------------------------------------------
  163.  *
  164.  * RememberSyncObject
  165.  *
  166.  *      Keep a list of (mutexes/condition variable/data key)
  167.  * used during finalization.
  168.  *
  169.  * Assume master lock is held.
  170.  *
  171.  * Results:
  172.  * None.
  173.  *
  174.  * Side effects:
  175.  * Add to the appropriate list.
  176.  *
  177.  *----------------------------------------------------------------------
  178.  */
  179. static void
  180. RememberSyncObject(objPtr, recPtr)
  181.     char *objPtr; /* Pointer to sync object */
  182.     SyncObjRecord *recPtr; /* Record of sync objects */
  183. {
  184.     char **newList;
  185.     int i, j;
  186.     /*
  187.      * Reuse any free slot in the list. 
  188.      */
  189.     for (i=0 ; i < recPtr->num ; ++i) {
  190. if (recPtr->list[i] == NULL) {
  191.     recPtr->list[i] = objPtr;
  192.     return;
  193.     }
  194.     /*
  195.      * Grow the list of pointers if necessary, copying only non-NULL
  196.      * pointers to the new list.
  197.      */
  198.     if (recPtr->num >= recPtr->max) {
  199. recPtr->max += 8;
  200. newList = (char **)ckalloc(recPtr->max * sizeof(char *));
  201. for (i=0, j=0 ; i < recPtr->num ; i++) {
  202.             if (recPtr->list[i] != NULL) {
  203. newList[j++] = recPtr->list[i];
  204.             }
  205. }
  206. if (recPtr->list != NULL) {
  207.     ckfree((char *)recPtr->list);
  208. }
  209. recPtr->list = newList;
  210. recPtr->num = j;
  211.     }
  212.     recPtr->list[recPtr->num] = objPtr;
  213.     recPtr->num++;
  214. }
  215. /*
  216.  *----------------------------------------------------------------------
  217.  *
  218.  * ForgetSyncObject
  219.  *
  220.  *      Remove a single object from the list.
  221.  * Assume master lock is held.
  222.  *
  223.  * Results:
  224.  * None.
  225.  *
  226.  * Side effects:
  227.  * Remove from the appropriate list.
  228.  *
  229.  *----------------------------------------------------------------------
  230.  */
  231. static void
  232. ForgetSyncObject(objPtr, recPtr)
  233.     char *objPtr; /* Pointer to sync object */
  234.     SyncObjRecord *recPtr; /* Record of sync objects */
  235. {
  236.     int i;
  237.     for (i=0 ; i<recPtr->num ; i++) {
  238. if (objPtr == recPtr->list[i]) {
  239.     recPtr->list[i] = NULL;
  240.     return;
  241. }
  242.     }
  243. }
  244. /*
  245.  *----------------------------------------------------------------------
  246.  *
  247.  * TclRememberMutex
  248.  *
  249.  *      Keep a list of mutexes used during finalization.
  250.  * Assume master lock is held.
  251.  *
  252.  * Results:
  253.  * None.
  254.  *
  255.  * Side effects:
  256.  * Add to the mutex list.
  257.  *
  258.  *----------------------------------------------------------------------
  259.  */
  260. void
  261. TclRememberMutex(mutexPtr)
  262.     Tcl_Mutex *mutexPtr;
  263. {
  264.     RememberSyncObject((char *)mutexPtr, &mutexRecord);
  265. }
  266. /*
  267.  *----------------------------------------------------------------------
  268.  *
  269.  * Tcl_MutexFinalize
  270.  *
  271.  *      Finalize a single mutex and remove it from the
  272.  * list of remembered objects.
  273.  *
  274.  * Results:
  275.  * None.
  276.  *
  277.  * Side effects:
  278.  * Remove the mutex from the list.
  279.  *
  280.  *----------------------------------------------------------------------
  281.  */
  282. void
  283. Tcl_MutexFinalize(mutexPtr)
  284.     Tcl_Mutex *mutexPtr;
  285. {
  286. #ifdef TCL_THREADS
  287.     TclpFinalizeMutex(mutexPtr);
  288. #endif
  289.     TclpMasterLock();
  290.     ForgetSyncObject((char *)mutexPtr, &mutexRecord);
  291.     TclpMasterUnlock();
  292. }
  293. /*
  294.  *----------------------------------------------------------------------
  295.  *
  296.  * TclRememberDataKey
  297.  *
  298.  *      Keep a list of thread data keys used during finalization.
  299.  * Assume master lock is held.
  300.  *
  301.  * Results:
  302.  * None.
  303.  *
  304.  * Side effects:
  305.  * Add to the key list.
  306.  *
  307.  *----------------------------------------------------------------------
  308.  */
  309. void
  310. TclRememberDataKey(keyPtr)
  311.     Tcl_ThreadDataKey *keyPtr;
  312. {
  313.     RememberSyncObject((char *)keyPtr, &keyRecord);
  314. }
  315. /*
  316.  *----------------------------------------------------------------------
  317.  *
  318.  * TclRememberCondition
  319.  *
  320.  *      Keep a list of condition variables used during finalization.
  321.  * Assume master lock is held.
  322.  *
  323.  * Results:
  324.  * None.
  325.  *
  326.  * Side effects:
  327.  * Add to the condition variable list.
  328.  *
  329.  *----------------------------------------------------------------------
  330.  */
  331. void
  332. TclRememberCondition(condPtr)
  333.     Tcl_Condition *condPtr;
  334. {
  335.     RememberSyncObject((char *)condPtr, &condRecord);
  336. }
  337. /*
  338.  *----------------------------------------------------------------------
  339.  *
  340.  * Tcl_ConditionFinalize
  341.  *
  342.  *      Finalize a single condition variable and remove it from the
  343.  * list of remembered objects.
  344.  *
  345.  * Results:
  346.  * None.
  347.  *
  348.  * Side effects:
  349.  * Remove the condition variable from the list.
  350.  *
  351.  *----------------------------------------------------------------------
  352.  */
  353. void
  354. Tcl_ConditionFinalize(condPtr)
  355.     Tcl_Condition *condPtr;
  356. {
  357. #ifdef TCL_THREADS
  358.     TclpFinalizeCondition(condPtr);
  359. #endif
  360.     TclpMasterLock();
  361.     ForgetSyncObject((char *)condPtr, &condRecord);
  362.     TclpMasterUnlock();
  363. }
  364. /*
  365.  *----------------------------------------------------------------------
  366.  *
  367.  * TclFinalizeThreadData --
  368.  *
  369.  * This procedure cleans up the thread-local storage.  This is
  370.  * called once for each thread.
  371.  *
  372.  * Results:
  373.  * None.
  374.  *
  375.  * Side effects:
  376.  * Frees up all thread local storage.
  377.  *
  378.  *----------------------------------------------------------------------
  379.  */
  380. void
  381. TclFinalizeThreadData()
  382. {
  383.     int i;
  384.     Tcl_ThreadDataKey *keyPtr;
  385.     TclpMasterLock();
  386.     for (i=0 ; i<keyRecord.num ; i++) {
  387. keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i];
  388. #ifdef TCL_THREADS
  389. TclpFinalizeThreadData(keyPtr);
  390. #else
  391. if (*keyPtr != NULL) {
  392.     ckfree((char *)*keyPtr);
  393.     *keyPtr = NULL;
  394. }
  395. #endif
  396.     }
  397.     TclpMasterUnlock();
  398. }
  399. /*
  400.  *----------------------------------------------------------------------
  401.  *
  402.  * TclFinalizeSynchronization --
  403.  *
  404.  *      This procedure cleans up all synchronization objects:
  405.  *      mutexes, condition variables, and thread-local storage.
  406.  *
  407.  * Results:
  408.  * None.
  409.  *
  410.  * Side effects:
  411.  * Frees up the memory.
  412.  *
  413.  *----------------------------------------------------------------------
  414.  */
  415. void
  416. TclFinalizeSynchronization()
  417. {
  418. #ifdef TCL_THREADS
  419.     Tcl_ThreadDataKey *keyPtr;
  420.     Tcl_Mutex *mutexPtr;
  421.     Tcl_Condition *condPtr;
  422.     int i;
  423.     TclpMasterLock();
  424.     for (i=0 ; i<keyRecord.num ; i++) {
  425. keyPtr = (Tcl_ThreadDataKey *)keyRecord.list[i];
  426. TclpFinalizeThreadDataKey(keyPtr);
  427.     }
  428.     if (keyRecord.list != NULL) {
  429. ckfree((char *)keyRecord.list);
  430. keyRecord.list = NULL;
  431.     }
  432.     keyRecord.max = 0;
  433.     keyRecord.num = 0;
  434.     for (i=0 ; i<mutexRecord.num ; i++) {
  435. mutexPtr = (Tcl_Mutex *)mutexRecord.list[i];
  436. if (mutexPtr != NULL) {
  437.     TclpFinalizeMutex(mutexPtr);
  438. }
  439.     }
  440.     if (mutexRecord.list != NULL) {
  441. ckfree((char *)mutexRecord.list);
  442. mutexRecord.list = NULL;
  443.     }
  444.     mutexRecord.max = 0;
  445.     mutexRecord.num = 0;
  446.     for (i=0 ; i<condRecord.num ; i++) {
  447. condPtr = (Tcl_Condition *)condRecord.list[i];
  448. if (condPtr != NULL) {
  449.     TclpFinalizeCondition(condPtr);
  450. }
  451.     }
  452.     if (condRecord.list != NULL) {
  453. ckfree((char *)condRecord.list);
  454. condRecord.list = NULL;
  455.     }
  456.     condRecord.max = 0;
  457.     condRecord.num = 0;
  458.     TclpMasterUnlock();
  459. #else
  460.     if (keyRecord.list != NULL) {
  461. ckfree((char *)keyRecord.list);
  462. keyRecord.list = NULL;
  463.     }
  464.     keyRecord.max = 0;
  465.     keyRecord.num = 0;
  466. #endif
  467. }
  468. /*
  469.  *----------------------------------------------------------------------
  470.  *
  471.  * Tcl_ExitThread --
  472.  *
  473.  * This procedure is called to terminate the current thread.
  474.  * This should be used by extensions that create threads with
  475.  * additional interpreters in them.
  476.  *
  477.  * Results:
  478.  * None.
  479.  *
  480.  * Side effects:
  481.  * All thread exit handlers are invoked, then the thread dies.
  482.  *
  483.  *----------------------------------------------------------------------
  484.  */
  485. void
  486. Tcl_ExitThread(status)
  487.     int status;
  488. {
  489.     Tcl_FinalizeThread();
  490. #ifdef TCL_THREADS
  491.     TclpThreadExit(status);
  492. #endif
  493. }
  494. #ifndef TCL_THREADS
  495. /*
  496.  *----------------------------------------------------------------------
  497.  *
  498.  * Tcl_ConditionWait, et al. --
  499.  *
  500.  * These noop procedures are provided so the stub table does
  501.  * not have to be conditionalized for threads.  The real
  502.  * implementations of these functions live in the platform
  503.  * specific files.
  504.  *
  505.  * Results:
  506.  * None.
  507.  *
  508.  * Side effects:
  509.  * None.
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513. #undef Tcl_ConditionWait
  514. void
  515. Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
  516.     Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
  517.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  518.     Tcl_Time *timePtr; /* Timeout on waiting period */
  519. {
  520. }
  521. #undef Tcl_ConditionNotify
  522. void
  523. Tcl_ConditionNotify(condPtr)
  524.     Tcl_Condition *condPtr;
  525. {
  526. }
  527. #undef Tcl_MutexLock
  528. void
  529. Tcl_MutexLock(mutexPtr)
  530.     Tcl_Mutex *mutexPtr;
  531. {
  532. }
  533. #undef Tcl_MutexUnlock
  534. void
  535. Tcl_MutexUnlock(mutexPtr)
  536.     Tcl_Mutex *mutexPtr;
  537. {
  538. }
  539. #endif