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