os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixThrd.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclUnixThrd.c --
sl@0
     3
 *
sl@0
     4
 *	This file implements the UNIX-specific thread support.
sl@0
     5
 *
sl@0
     6
 * Copyright (c) 1991-1994 The Regents of the University of California.
sl@0
     7
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
sl@0
     8
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
     9
 *
sl@0
    10
 * See the file "license.terms" for information on usage and redistribution
sl@0
    11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    12
 *
sl@0
    13
 * SCCS:  @(#) tclUnixThrd.c 1.18 98/02/19 14:24:12
sl@0
    14
 */
sl@0
    15
sl@0
    16
#include "tclInt.h"
sl@0
    17
#include "tclPort.h"
sl@0
    18
sl@0
    19
#ifdef TCL_THREADS
sl@0
    20
sl@0
    21
#include "pthread.h"
sl@0
    22
sl@0
    23
typedef struct ThreadSpecificData {
sl@0
    24
    char nabuf[16];
sl@0
    25
} ThreadSpecificData;
sl@0
    26
sl@0
    27
static Tcl_ThreadDataKey dataKey;
sl@0
    28
sl@0
    29
/*
sl@0
    30
 * masterLock is used to serialize creation of mutexes, condition
sl@0
    31
 * variables, and thread local storage.
sl@0
    32
 * This is the only place that can count on the ability to statically
sl@0
    33
 * initialize the mutex.
sl@0
    34
 */
sl@0
    35
sl@0
    36
static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER;
sl@0
    37
sl@0
    38
/*
sl@0
    39
 * initLock is used to serialize initialization and finalization
sl@0
    40
 * of Tcl.  It cannot use any dyamically allocated storage.
sl@0
    41
 */
sl@0
    42
sl@0
    43
static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER;
sl@0
    44
sl@0
    45
/*
sl@0
    46
 * allocLock is used by Tcl's version of malloc for synchronization.
sl@0
    47
 * For obvious reasons, cannot use any dyamically allocated storage.
sl@0
    48
 */
sl@0
    49
sl@0
    50
static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER;
sl@0
    51
static pthread_mutex_t *allocLockPtr = &allocLock;
sl@0
    52
sl@0
    53
/*
sl@0
    54
 * These are for the critical sections inside this file.
sl@0
    55
 */
sl@0
    56
sl@0
    57
#define MASTER_LOCK	pthread_mutex_lock(&masterLock)
sl@0
    58
#define MASTER_UNLOCK	pthread_mutex_unlock(&masterLock)
sl@0
    59
sl@0
    60
#endif /* TCL_THREADS */
sl@0
    61
sl@0
    62

sl@0
    63
/*
sl@0
    64
 *----------------------------------------------------------------------
sl@0
    65
 *
sl@0
    66
 * TclpThreadCreate --
sl@0
    67
 *
sl@0
    68
 *	This procedure creates a new thread.
sl@0
    69
 *
sl@0
    70
 * Results:
sl@0
    71
 *	TCL_OK if the thread could be created.  The thread ID is
sl@0
    72
 *	returned in a parameter.
sl@0
    73
 *
sl@0
    74
 * Side effects:
sl@0
    75
 *	A new thread is created.
sl@0
    76
 *
sl@0
    77
 *----------------------------------------------------------------------
sl@0
    78
 */
sl@0
    79
sl@0
    80
int
sl@0
    81
TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
sl@0
    82
    Tcl_ThreadId *idPtr;		/* Return, the ID of the thread */
sl@0
    83
    Tcl_ThreadCreateProc proc;		/* Main() function of the thread */
sl@0
    84
    ClientData clientData;		/* The one argument to Main() */
sl@0
    85
    int stackSize;			/* Size of stack for the new thread */
sl@0
    86
    int flags;				/* Flags controlling behaviour of
sl@0
    87
					 * the new thread */
sl@0
    88
{
sl@0
    89
#ifdef TCL_THREADS
sl@0
    90
    pthread_attr_t attr;
sl@0
    91
    pthread_t theThread;
sl@0
    92
    int result;
sl@0
    93
sl@0
    94
    pthread_attr_init(&attr);
sl@0
    95
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
sl@0
    96
sl@0
    97
#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
sl@0
    98
    if (stackSize != TCL_THREAD_STACK_DEFAULT) {
sl@0
    99
        pthread_attr_setstacksize(&attr, (size_t) stackSize);
sl@0
   100
#ifdef TCL_THREAD_STACK_MIN
sl@0
   101
    } else {
sl@0
   102
        /*
sl@0
   103
	 * Certain systems define a thread stack size that by default is
sl@0
   104
	 * too small for many operations.  The user has the option of
sl@0
   105
	 * defining TCL_THREAD_STACK_MIN to a value large enough to work
sl@0
   106
	 * for their needs.  This would look like (for 128K min stack):
sl@0
   107
	 *    make MEM_DEBUG_FLAGS=-DTCL_THREAD_STACK_MIN=131072L
sl@0
   108
	 *
sl@0
   109
	 * This solution is not optimal, as we should allow the user to
sl@0
   110
	 * specify a size at runtime, but we don't want to slow this function
sl@0
   111
	 * down, and that would still leave the main thread at the default.
sl@0
   112
	 */
sl@0
   113
sl@0
   114
        size_t size;
sl@0
   115
	result = pthread_attr_getstacksize(&attr, &size);
sl@0
   116
	if (!result && (size < TCL_THREAD_STACK_MIN)) {
sl@0
   117
	    pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN);
sl@0
   118
	}
sl@0
   119
#endif
sl@0
   120
    }
sl@0
   121
#endif
sl@0
   122
    if (! (flags & TCL_THREAD_JOINABLE)) {
sl@0
   123
        pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
sl@0
   124
    }
sl@0
   125
sl@0
   126
sl@0
   127
    if (pthread_create(&theThread, &attr,
sl@0
   128
	    (void * (*)())proc, (void *)clientData) &&
sl@0
   129
	    pthread_create(&theThread, NULL,
sl@0
   130
		    (void * (*)())proc, (void *)clientData)) {
sl@0
   131
	result = TCL_ERROR;
sl@0
   132
    } else {
sl@0
   133
	*idPtr = (Tcl_ThreadId)theThread;
sl@0
   134
	result = TCL_OK;
sl@0
   135
    }
sl@0
   136
    pthread_attr_destroy(&attr);
sl@0
   137
    return result;
sl@0
   138
#else
sl@0
   139
    return TCL_ERROR;
sl@0
   140
#endif /* TCL_THREADS */
sl@0
   141
}
sl@0
   142

sl@0
   143
/*
sl@0
   144
 *----------------------------------------------------------------------
sl@0
   145
 *
sl@0
   146
 * Tcl_JoinThread --
sl@0
   147
 *
sl@0
   148
 *	This procedure waits upon the exit of the specified thread.
sl@0
   149
 *
sl@0
   150
 * Results:
sl@0
   151
 *	TCL_OK if the wait was successful, TCL_ERROR else.
sl@0
   152
 *
sl@0
   153
 * Side effects:
sl@0
   154
 *	The result area is set to the exit code of the thread we
sl@0
   155
 *	waited upon.
sl@0
   156
 *
sl@0
   157
 *----------------------------------------------------------------------
sl@0
   158
 */
sl@0
   159
sl@0
   160
EXPORT_C int
sl@0
   161
Tcl_JoinThread(threadId, state)
sl@0
   162
    Tcl_ThreadId threadId; /* Id of the thread to wait upon */
sl@0
   163
    int*     state;	   /* Reference to the storage the result
sl@0
   164
			    * of the thread we wait upon will be
sl@0
   165
			    * written into. */
sl@0
   166
{
sl@0
   167
#ifdef TCL_THREADS
sl@0
   168
    int result;
sl@0
   169
sl@0
   170
    result = pthread_join ((pthread_t) threadId, (VOID**) state);
sl@0
   171
    return (result == 0) ? TCL_OK : TCL_ERROR;
sl@0
   172
#else
sl@0
   173
    return TCL_ERROR;
sl@0
   174
#endif
sl@0
   175
}
sl@0
   176

sl@0
   177
#ifdef TCL_THREADS
sl@0
   178
/*
sl@0
   179
 *----------------------------------------------------------------------
sl@0
   180
 *
sl@0
   181
 * TclpThreadExit --
sl@0
   182
 *
sl@0
   183
 *	This procedure terminates the current thread.
sl@0
   184
 *
sl@0
   185
 * Results:
sl@0
   186
 *	None.
sl@0
   187
 *
sl@0
   188
 * Side effects:
sl@0
   189
 *	This procedure terminates the current thread.
sl@0
   190
 *
sl@0
   191
 *----------------------------------------------------------------------
sl@0
   192
 */
sl@0
   193
sl@0
   194
void
sl@0
   195
TclpThreadExit(status)
sl@0
   196
    int status;
sl@0
   197
{
sl@0
   198
    pthread_exit((VOID *)status);
sl@0
   199
}
sl@0
   200
#endif /* TCL_THREADS */
sl@0
   201

sl@0
   202
/*
sl@0
   203
 *----------------------------------------------------------------------
sl@0
   204
 *
sl@0
   205
 * Tcl_GetCurrentThread --
sl@0
   206
 *
sl@0
   207
 *	This procedure returns the ID of the currently running thread.
sl@0
   208
 *
sl@0
   209
 * Results:
sl@0
   210
 *	A thread ID.
sl@0
   211
 *
sl@0
   212
 * Side effects:
sl@0
   213
 *	None.
sl@0
   214
 *
sl@0
   215
 *----------------------------------------------------------------------
sl@0
   216
 */
sl@0
   217
sl@0
   218
EXPORT_C Tcl_ThreadId
sl@0
   219
Tcl_GetCurrentThread()
sl@0
   220
{
sl@0
   221
#ifdef TCL_THREADS
sl@0
   222
    return (Tcl_ThreadId) pthread_self();
sl@0
   223
#else
sl@0
   224
    return (Tcl_ThreadId) 0;
sl@0
   225
#endif
sl@0
   226
}
sl@0
   227
sl@0
   228

sl@0
   229
/*
sl@0
   230
 *----------------------------------------------------------------------
sl@0
   231
 *
sl@0
   232
 * TclpInitLock
sl@0
   233
 *
sl@0
   234
 *	This procedure is used to grab a lock that serializes initialization
sl@0
   235
 *	and finalization of Tcl.  On some platforms this may also initialize
sl@0
   236
 *	the mutex used to serialize creation of more mutexes and thread
sl@0
   237
 *	local storage keys.
sl@0
   238
 *
sl@0
   239
 * Results:
sl@0
   240
 *	None.
sl@0
   241
 *
sl@0
   242
 * Side effects:
sl@0
   243
 *	Acquire the initialization mutex.
sl@0
   244
 *
sl@0
   245
 *----------------------------------------------------------------------
sl@0
   246
 */
sl@0
   247
sl@0
   248
void
sl@0
   249
TclpInitLock()
sl@0
   250
{
sl@0
   251
#ifdef TCL_THREADS
sl@0
   252
    pthread_mutex_lock(&initLock);
sl@0
   253
#endif
sl@0
   254
}
sl@0
   255

sl@0
   256
/*
sl@0
   257
 *----------------------------------------------------------------------
sl@0
   258
 *
sl@0
   259
 * TclpFinalizeLock
sl@0
   260
 *
sl@0
   261
 *	This procedure is used to destroy all private resources used in
sl@0
   262
 *	this file.
sl@0
   263
 *
sl@0
   264
 * Results:
sl@0
   265
 *	None.
sl@0
   266
 *
sl@0
   267
 * Side effects:
sl@0
   268
 *	Destroys everything private.  TclpInitLock must be held
sl@0
   269
 *	entering this function.
sl@0
   270
 *
sl@0
   271
 *----------------------------------------------------------------------
sl@0
   272
 */
sl@0
   273
sl@0
   274
void
sl@0
   275
TclFinalizeLock ()
sl@0
   276
{
sl@0
   277
#ifdef TCL_THREADS
sl@0
   278
    /*
sl@0
   279
     * You do not need to destroy mutexes that were created with the
sl@0
   280
     * PTHREAD_MUTEX_INITIALIZER macro.  These mutexes do not need
sl@0
   281
     * any destruction: masterLock, allocLock, and initLock.
sl@0
   282
     */
sl@0
   283
    pthread_mutex_unlock(&initLock);
sl@0
   284
#endif
sl@0
   285
}
sl@0
   286

sl@0
   287
/*
sl@0
   288
 *----------------------------------------------------------------------
sl@0
   289
 *
sl@0
   290
 * TclpInitUnlock
sl@0
   291
 *
sl@0
   292
 *	This procedure is used to release a lock that serializes initialization
sl@0
   293
 *	and finalization of Tcl.
sl@0
   294
 *
sl@0
   295
 * Results:
sl@0
   296
 *	None.
sl@0
   297
 *
sl@0
   298
 * Side effects:
sl@0
   299
 *	Release the initialization mutex.
sl@0
   300
 *
sl@0
   301
 *----------------------------------------------------------------------
sl@0
   302
 */
sl@0
   303
sl@0
   304
void
sl@0
   305
TclpInitUnlock()
sl@0
   306
{
sl@0
   307
#ifdef TCL_THREADS
sl@0
   308
    pthread_mutex_unlock(&initLock);
sl@0
   309
#endif
sl@0
   310
}
sl@0
   311

sl@0
   312
/*
sl@0
   313
 *----------------------------------------------------------------------
sl@0
   314
 *
sl@0
   315
 * TclpMasterLock
sl@0
   316
 *
sl@0
   317
 *	This procedure is used to grab a lock that serializes creation
sl@0
   318
 *	and finalization of serialization objects.  This interface is
sl@0
   319
 *	only needed in finalization; it is hidden during
sl@0
   320
 *	creation of the objects.
sl@0
   321
 *
sl@0
   322
 *	This lock must be different than the initLock because the
sl@0
   323
 *	initLock is held during creation of syncronization objects.
sl@0
   324
 *
sl@0
   325
 * Results:
sl@0
   326
 *	None.
sl@0
   327
 *
sl@0
   328
 * Side effects:
sl@0
   329
 *	Acquire the master mutex.
sl@0
   330
 *
sl@0
   331
 *----------------------------------------------------------------------
sl@0
   332
 */
sl@0
   333
sl@0
   334
void
sl@0
   335
TclpMasterLock()
sl@0
   336
{
sl@0
   337
#ifdef TCL_THREADS
sl@0
   338
    pthread_mutex_lock(&masterLock);
sl@0
   339
#endif
sl@0
   340
}
sl@0
   341
sl@0
   342

sl@0
   343
/*
sl@0
   344
 *----------------------------------------------------------------------
sl@0
   345
 *
sl@0
   346
 * TclpMasterUnlock
sl@0
   347
 *
sl@0
   348
 *	This procedure is used to release a lock that serializes creation
sl@0
   349
 *	and finalization of synchronization objects.
sl@0
   350
 *
sl@0
   351
 * Results:
sl@0
   352
 *	None.
sl@0
   353
 *
sl@0
   354
 * Side effects:
sl@0
   355
 *	Release the master mutex.
sl@0
   356
 *
sl@0
   357
 *----------------------------------------------------------------------
sl@0
   358
 */
sl@0
   359
sl@0
   360
void
sl@0
   361
TclpMasterUnlock()
sl@0
   362
{
sl@0
   363
#ifdef TCL_THREADS
sl@0
   364
    pthread_mutex_unlock(&masterLock);
sl@0
   365
#endif
sl@0
   366
}
sl@0
   367
sl@0
   368

sl@0
   369
/*
sl@0
   370
 *----------------------------------------------------------------------
sl@0
   371
 *
sl@0
   372
 * Tcl_GetAllocMutex
sl@0
   373
 *
sl@0
   374
 *	This procedure returns a pointer to a statically initialized
sl@0
   375
 *	mutex for use by the memory allocator.  The alloctor must
sl@0
   376
 *	use this lock, because all other locks are allocated...
sl@0
   377
 *
sl@0
   378
 * Results:
sl@0
   379
 *	A pointer to a mutex that is suitable for passing to
sl@0
   380
 *	Tcl_MutexLock and Tcl_MutexUnlock.
sl@0
   381
 *
sl@0
   382
 * Side effects:
sl@0
   383
 *	None.
sl@0
   384
 *
sl@0
   385
 *----------------------------------------------------------------------
sl@0
   386
 */
sl@0
   387
sl@0
   388
EXPORT_C Tcl_Mutex *
sl@0
   389
Tcl_GetAllocMutex()
sl@0
   390
{
sl@0
   391
#ifdef TCL_THREADS
sl@0
   392
    return (Tcl_Mutex *)&allocLockPtr;
sl@0
   393
#else
sl@0
   394
    return NULL;
sl@0
   395
#endif
sl@0
   396
}
sl@0
   397
sl@0
   398
#ifdef TCL_THREADS
sl@0
   399

sl@0
   400
/*
sl@0
   401
 *----------------------------------------------------------------------
sl@0
   402
 *
sl@0
   403
 * Tcl_MutexLock --
sl@0
   404
 *
sl@0
   405
 *	This procedure is invoked to lock a mutex.  This procedure
sl@0
   406
 *	handles initializing the mutex, if necessary.  The caller
sl@0
   407
 *	can rely on the fact that Tcl_Mutex is an opaque pointer.
sl@0
   408
 *	This routine will change that pointer from NULL after first use.
sl@0
   409
 *
sl@0
   410
 * Results:
sl@0
   411
 *	None.
sl@0
   412
 *
sl@0
   413
 * Side effects:
sl@0
   414
 *	May block the current thread.  The mutex is aquired when
sl@0
   415
 *	this returns.  Will allocate memory for a pthread_mutex_t
sl@0
   416
 *	and initialize this the first time this Tcl_Mutex is used.
sl@0
   417
 *
sl@0
   418
 *----------------------------------------------------------------------
sl@0
   419
 */
sl@0
   420
sl@0
   421
EXPORT_C void
sl@0
   422
Tcl_MutexLock(mutexPtr)
sl@0
   423
    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */
sl@0
   424
{
sl@0
   425
    pthread_mutex_t *pmutexPtr;
sl@0
   426
    if (*mutexPtr == NULL) {
sl@0
   427
	MASTER_LOCK;
sl@0
   428
	if (*mutexPtr == NULL) {
sl@0
   429
	    /* 
sl@0
   430
	     * Double inside master lock check to avoid a race condition.
sl@0
   431
	     */
sl@0
   432
    
sl@0
   433
	    pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t));
sl@0
   434
	    pthread_mutex_init(pmutexPtr, NULL);
sl@0
   435
	    *mutexPtr = (Tcl_Mutex)pmutexPtr;
sl@0
   436
	    TclRememberMutex(mutexPtr);
sl@0
   437
	}
sl@0
   438
	MASTER_UNLOCK;
sl@0
   439
    }
sl@0
   440
    pmutexPtr = *((pthread_mutex_t **)mutexPtr);
sl@0
   441
    pthread_mutex_lock(pmutexPtr);
sl@0
   442
}
sl@0
   443
sl@0
   444

sl@0
   445
/*
sl@0
   446
 *----------------------------------------------------------------------
sl@0
   447
 *
sl@0
   448
 * Tcl_MutexUnlock --
sl@0
   449
 *
sl@0
   450
 *	This procedure is invoked to unlock a mutex.  The mutex must
sl@0
   451
 *	have been locked by Tcl_MutexLock.
sl@0
   452
 *
sl@0
   453
 * Results:
sl@0
   454
 *	None.
sl@0
   455
 *
sl@0
   456
 * Side effects:
sl@0
   457
 *	The mutex is released when this returns.
sl@0
   458
 *
sl@0
   459
 *----------------------------------------------------------------------
sl@0
   460
 */
sl@0
   461
sl@0
   462
EXPORT_C void
sl@0
   463
Tcl_MutexUnlock(mutexPtr)
sl@0
   464
    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */
sl@0
   465
{
sl@0
   466
    pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
sl@0
   467
    pthread_mutex_unlock(pmutexPtr);
sl@0
   468
}
sl@0
   469
sl@0
   470

sl@0
   471
/*
sl@0
   472
 *----------------------------------------------------------------------
sl@0
   473
 *
sl@0
   474
 * TclpFinalizeMutex --
sl@0
   475
 *
sl@0
   476
 *	This procedure is invoked to clean up one mutex.  This is only
sl@0
   477
 *	safe to call at the end of time.
sl@0
   478
 *
sl@0
   479
 *	This assumes the Master Lock is held.
sl@0
   480
 *
sl@0
   481
 * Results:
sl@0
   482
 *	None.
sl@0
   483
 *
sl@0
   484
 * Side effects:
sl@0
   485
 *	The mutex list is deallocated.
sl@0
   486
 *
sl@0
   487
 *----------------------------------------------------------------------
sl@0
   488
 */
sl@0
   489
sl@0
   490
void
sl@0
   491
TclpFinalizeMutex(mutexPtr)
sl@0
   492
    Tcl_Mutex *mutexPtr;
sl@0
   493
{
sl@0
   494
    pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
sl@0
   495
    if (pmutexPtr != NULL) {
sl@0
   496
        pthread_mutex_destroy(pmutexPtr);
sl@0
   497
	ckfree((char *)pmutexPtr);
sl@0
   498
	*mutexPtr = NULL;
sl@0
   499
    }
sl@0
   500
}
sl@0
   501
sl@0
   502

sl@0
   503
/*
sl@0
   504
 *----------------------------------------------------------------------
sl@0
   505
 *
sl@0
   506
 * TclpThreadDataKeyInit --
sl@0
   507
 *
sl@0
   508
 *	This procedure initializes a thread specific data block key.
sl@0
   509
 *	Each thread has table of pointers to thread specific data.
sl@0
   510
 *	all threads agree on which table entry is used by each module.
sl@0
   511
 *	this is remembered in a "data key", that is just an index into
sl@0
   512
 *	this table.  To allow self initialization, the interface
sl@0
   513
 *	passes a pointer to this key and the first thread to use
sl@0
   514
 *	the key fills in the pointer to the key.  The key should be
sl@0
   515
 *	a process-wide static.
sl@0
   516
 *
sl@0
   517
 * Results:
sl@0
   518
 *	None.
sl@0
   519
 *
sl@0
   520
 * Side effects:
sl@0
   521
 *	Will allocate memory the first time this process calls for
sl@0
   522
 *	this key.  In this case it modifies its argument
sl@0
   523
 *	to hold the pointer to information about the key.
sl@0
   524
 *
sl@0
   525
 *----------------------------------------------------------------------
sl@0
   526
 */
sl@0
   527
sl@0
   528
void
sl@0
   529
TclpThreadDataKeyInit(keyPtr)
sl@0
   530
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   531
				 * really (pthread_key_t **) */
sl@0
   532
{
sl@0
   533
    pthread_key_t *pkeyPtr;
sl@0
   534
sl@0
   535
    MASTER_LOCK;
sl@0
   536
    if (*keyPtr == NULL) {
sl@0
   537
	pkeyPtr = (pthread_key_t *)ckalloc(sizeof(pthread_key_t));
sl@0
   538
	pthread_key_create(pkeyPtr, NULL);
sl@0
   539
	*keyPtr = (Tcl_ThreadDataKey)pkeyPtr;
sl@0
   540
	TclRememberDataKey(keyPtr);
sl@0
   541
    }
sl@0
   542
    MASTER_UNLOCK;
sl@0
   543
}
sl@0
   544

sl@0
   545
/*
sl@0
   546
 *----------------------------------------------------------------------
sl@0
   547
 *
sl@0
   548
 * TclpThreadDataKeyGet --
sl@0
   549
 *
sl@0
   550
 *	This procedure returns a pointer to a block of thread local storage.
sl@0
   551
 *
sl@0
   552
 * Results:
sl@0
   553
 *	A thread-specific pointer to the data structure, or NULL
sl@0
   554
 *	if the memory has not been assigned to this key for this thread.
sl@0
   555
 *
sl@0
   556
 * Side effects:
sl@0
   557
 *	None.
sl@0
   558
 *
sl@0
   559
 *----------------------------------------------------------------------
sl@0
   560
 */
sl@0
   561
sl@0
   562
VOID *
sl@0
   563
TclpThreadDataKeyGet(keyPtr)
sl@0
   564
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   565
				 * really (pthread_key_t **) */
sl@0
   566
{
sl@0
   567
    pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
sl@0
   568
    if (pkeyPtr == NULL) {
sl@0
   569
	return NULL;
sl@0
   570
    } else {
sl@0
   571
	return (VOID *)pthread_getspecific(*pkeyPtr);
sl@0
   572
    }
sl@0
   573
}
sl@0
   574
sl@0
   575

sl@0
   576
/*
sl@0
   577
 *----------------------------------------------------------------------
sl@0
   578
 *
sl@0
   579
 * TclpThreadDataKeySet --
sl@0
   580
 *
sl@0
   581
 *	This procedure sets the pointer to a block of thread local storage.
sl@0
   582
 *
sl@0
   583
 * Results:
sl@0
   584
 *	None.
sl@0
   585
 *
sl@0
   586
 * Side effects:
sl@0
   587
 *	Sets up the thread so future calls to TclpThreadDataKeyGet with
sl@0
   588
 *	this key will return the data pointer.
sl@0
   589
 *
sl@0
   590
 *----------------------------------------------------------------------
sl@0
   591
 */
sl@0
   592
sl@0
   593
void
sl@0
   594
TclpThreadDataKeySet(keyPtr, data)
sl@0
   595
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   596
				 * really (pthread_key_t **) */
sl@0
   597
    VOID *data;			/* Thread local storage */
sl@0
   598
{
sl@0
   599
    pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
sl@0
   600
    pthread_setspecific(*pkeyPtr, data);
sl@0
   601
}
sl@0
   602

sl@0
   603
/*
sl@0
   604
 *----------------------------------------------------------------------
sl@0
   605
 *
sl@0
   606
 * TclpFinalizeThreadData --
sl@0
   607
 *
sl@0
   608
 *	This procedure cleans up the thread-local storage.  This is
sl@0
   609
 *	called once for each thread.
sl@0
   610
 *
sl@0
   611
 * Results:
sl@0
   612
 *	None.
sl@0
   613
 *
sl@0
   614
 * Side effects:
sl@0
   615
 *	Frees up all thread local storage.
sl@0
   616
 *
sl@0
   617
 *----------------------------------------------------------------------
sl@0
   618
 */
sl@0
   619
sl@0
   620
void
sl@0
   621
TclpFinalizeThreadData(keyPtr)
sl@0
   622
    Tcl_ThreadDataKey *keyPtr;
sl@0
   623
{
sl@0
   624
    VOID *result;
sl@0
   625
    pthread_key_t *pkeyPtr;
sl@0
   626
sl@0
   627
    if (*keyPtr != NULL) {
sl@0
   628
	pkeyPtr = *(pthread_key_t **)keyPtr;
sl@0
   629
	result = (VOID *)pthread_getspecific(*pkeyPtr);
sl@0
   630
	if (result != NULL) {
sl@0
   631
	    ckfree((char *)result);
sl@0
   632
	    pthread_setspecific(*pkeyPtr, (void *)NULL);
sl@0
   633
	}
sl@0
   634
    }
sl@0
   635
}
sl@0
   636

sl@0
   637
/*
sl@0
   638
 *----------------------------------------------------------------------
sl@0
   639
 *
sl@0
   640
 * TclpFinalizeThreadDataKey --
sl@0
   641
 *
sl@0
   642
 *	This procedure is invoked to clean up one key.  This is a
sl@0
   643
 *	process-wide storage identifier.  The thread finalization code
sl@0
   644
 *	cleans up the thread local storage itself.
sl@0
   645
 *
sl@0
   646
 *	This assumes the master lock is held.
sl@0
   647
 *
sl@0
   648
 * Results:
sl@0
   649
 *	None.
sl@0
   650
 *
sl@0
   651
 * Side effects:
sl@0
   652
 *	The key is deallocated.
sl@0
   653
 *
sl@0
   654
 *----------------------------------------------------------------------
sl@0
   655
 */
sl@0
   656
sl@0
   657
void
sl@0
   658
TclpFinalizeThreadDataKey(keyPtr)
sl@0
   659
    Tcl_ThreadDataKey *keyPtr;
sl@0
   660
{
sl@0
   661
    pthread_key_t *pkeyPtr;
sl@0
   662
    if (*keyPtr != NULL) {
sl@0
   663
	pkeyPtr = *(pthread_key_t **)keyPtr;
sl@0
   664
	pthread_key_delete(*pkeyPtr);
sl@0
   665
	ckfree((char *)pkeyPtr);
sl@0
   666
	*keyPtr = NULL;
sl@0
   667
    }
sl@0
   668
}
sl@0
   669
sl@0
   670

sl@0
   671
/*
sl@0
   672
 *----------------------------------------------------------------------
sl@0
   673
 *
sl@0
   674
 * Tcl_ConditionWait --
sl@0
   675
 *
sl@0
   676
 *	This procedure is invoked to wait on a condition variable.
sl@0
   677
 *	The mutex is automically released as part of the wait, and
sl@0
   678
 *	automatically grabbed when the condition is signaled.
sl@0
   679
 *
sl@0
   680
 *	The mutex must be held when this procedure is called.
sl@0
   681
 *
sl@0
   682
 * Results:
sl@0
   683
 *	None.
sl@0
   684
 *
sl@0
   685
 * Side effects:
sl@0
   686
 *	May block the current thread.  The mutex is aquired when
sl@0
   687
 *	this returns.  Will allocate memory for a pthread_mutex_t
sl@0
   688
 *	and initialize this the first time this Tcl_Mutex is used.
sl@0
   689
 *
sl@0
   690
 *----------------------------------------------------------------------
sl@0
   691
 */
sl@0
   692
sl@0
   693
EXPORT_C void
sl@0
   694
Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
sl@0
   695
    Tcl_Condition *condPtr;	/* Really (pthread_cond_t **) */
sl@0
   696
    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */
sl@0
   697
    Tcl_Time *timePtr;		/* Timeout on waiting period */
sl@0
   698
{
sl@0
   699
    pthread_cond_t *pcondPtr;
sl@0
   700
    pthread_mutex_t *pmutexPtr;
sl@0
   701
    struct timespec ptime;
sl@0
   702
sl@0
   703
    if (*condPtr == NULL) {
sl@0
   704
	MASTER_LOCK;
sl@0
   705
sl@0
   706
	/* 
sl@0
   707
	 * Double check inside mutex to avoid race,
sl@0
   708
	 * then initialize condition variable if necessary.
sl@0
   709
	 */
sl@0
   710
sl@0
   711
	if (*condPtr == NULL) {
sl@0
   712
	    pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t));
sl@0
   713
	    pthread_cond_init(pcondPtr, NULL);
sl@0
   714
	    *condPtr = (Tcl_Condition)pcondPtr;
sl@0
   715
	    TclRememberCondition(condPtr);
sl@0
   716
	}
sl@0
   717
	MASTER_UNLOCK;
sl@0
   718
    }
sl@0
   719
    pmutexPtr = *((pthread_mutex_t **)mutexPtr);
sl@0
   720
    pcondPtr = *((pthread_cond_t **)condPtr);
sl@0
   721
    if (timePtr == NULL) {
sl@0
   722
	pthread_cond_wait(pcondPtr, pmutexPtr);
sl@0
   723
    } else {
sl@0
   724
	Tcl_Time now;
sl@0
   725
sl@0
   726
	/*
sl@0
   727
	 * Make sure to take into account the microsecond component of the
sl@0
   728
	 * current time, including possible overflow situations. [Bug #411603]
sl@0
   729
	 */
sl@0
   730
sl@0
   731
	Tcl_GetTime(&now);
sl@0
   732
	ptime.tv_sec = timePtr->sec + now.sec +
sl@0
   733
	    (timePtr->usec + now.usec) / 1000000;
sl@0
   734
	ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
sl@0
   735
	pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime);
sl@0
   736
    }
sl@0
   737
}
sl@0
   738

sl@0
   739
/*
sl@0
   740
 *----------------------------------------------------------------------
sl@0
   741
 *
sl@0
   742
 * Tcl_ConditionNotify --
sl@0
   743
 *
sl@0
   744
 *	This procedure is invoked to signal a condition variable.
sl@0
   745
 *
sl@0
   746
 *	The mutex must be held during this call to avoid races,
sl@0
   747
 *	but this interface does not enforce that.
sl@0
   748
 *
sl@0
   749
 * Results:
sl@0
   750
 *	None.
sl@0
   751
 *
sl@0
   752
 * Side effects:
sl@0
   753
 *	May unblock another thread.
sl@0
   754
 *
sl@0
   755
 *----------------------------------------------------------------------
sl@0
   756
 */
sl@0
   757
sl@0
   758
EXPORT_C void
sl@0
   759
Tcl_ConditionNotify(condPtr)
sl@0
   760
    Tcl_Condition *condPtr;
sl@0
   761
{
sl@0
   762
    pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr);
sl@0
   763
    if (pcondPtr != NULL) {
sl@0
   764
	pthread_cond_broadcast(pcondPtr);
sl@0
   765
    } else {
sl@0
   766
	/*
sl@0
   767
	 * Noone has used the condition variable, so there are no waiters.
sl@0
   768
	 */
sl@0
   769
    }
sl@0
   770
}
sl@0
   771
sl@0
   772

sl@0
   773
/*
sl@0
   774
 *----------------------------------------------------------------------
sl@0
   775
 *
sl@0
   776
 * TclpFinalizeCondition --
sl@0
   777
 *
sl@0
   778
 *	This procedure is invoked to clean up a condition variable.
sl@0
   779
 *	This is only safe to call at the end of time.
sl@0
   780
 *
sl@0
   781
 *	This assumes the Master Lock is held.
sl@0
   782
 *
sl@0
   783
 * Results:
sl@0
   784
 *	None.
sl@0
   785
 *
sl@0
   786
 * Side effects:
sl@0
   787
 *	The condition variable is deallocated.
sl@0
   788
 *
sl@0
   789
 *----------------------------------------------------------------------
sl@0
   790
 */
sl@0
   791
sl@0
   792
void
sl@0
   793
TclpFinalizeCondition(condPtr)
sl@0
   794
    Tcl_Condition *condPtr;
sl@0
   795
{
sl@0
   796
    pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr;
sl@0
   797
    if (pcondPtr != NULL) {
sl@0
   798
	pthread_cond_destroy(pcondPtr);
sl@0
   799
	ckfree((char *)pcondPtr);
sl@0
   800
	*condPtr = NULL;
sl@0
   801
    }
sl@0
   802
}
sl@0
   803
#endif /* TCL_THREADS */
sl@0
   804

sl@0
   805
/*
sl@0
   806
 *----------------------------------------------------------------------
sl@0
   807
 *
sl@0
   808
 * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa --
sl@0
   809
 *
sl@0
   810
 *	These procedures replace core C versions to be used in a
sl@0
   811
 *	threaded environment.
sl@0
   812
 *
sl@0
   813
 * Results:
sl@0
   814
 *	See documentation of C functions.
sl@0
   815
 *
sl@0
   816
 * Side effects:
sl@0
   817
 *	See documentation of C functions.
sl@0
   818
 *
sl@0
   819
 * Notes:
sl@0
   820
 * 	TclpReaddir is no longer used by the core (see 1095909),
sl@0
   821
 * 	but it appears in the internal stubs table (see #589526).
sl@0
   822
 *----------------------------------------------------------------------
sl@0
   823
 */
sl@0
   824
sl@0
   825
Tcl_DirEntry *
sl@0
   826
TclpReaddir(DIR * dir)
sl@0
   827
{
sl@0
   828
    return TclOSreaddir(dir);
sl@0
   829
}
sl@0
   830
sl@0
   831
char *
sl@0
   832
TclpInetNtoa(struct in_addr addr)
sl@0
   833
{
sl@0
   834
#ifdef TCL_THREADS
sl@0
   835
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
sl@0
   836
    unsigned char *b = (unsigned char*) &addr.s_addr;
sl@0
   837
sl@0
   838
    sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
sl@0
   839
    return tsdPtr->nabuf;
sl@0
   840
#else
sl@0
   841
    return inet_ntoa(addr);
sl@0
   842
#endif
sl@0
   843
}
sl@0
   844
sl@0
   845
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
sl@0
   846
/*
sl@0
   847
 * Additions by AOL for specialized thread memory allocator.
sl@0
   848
 */
sl@0
   849
#ifdef USE_THREAD_ALLOC
sl@0
   850
static volatile int initialized = 0;
sl@0
   851
static pthread_key_t	key;
sl@0
   852
sl@0
   853
typedef struct allocMutex {
sl@0
   854
    Tcl_Mutex       tlock;
sl@0
   855
    pthread_mutex_t plock;
sl@0
   856
} allocMutex;
sl@0
   857
sl@0
   858
Tcl_Mutex *
sl@0
   859
TclpNewAllocMutex(void)
sl@0
   860
{
sl@0
   861
    struct allocMutex *lockPtr;
sl@0
   862
sl@0
   863
    lockPtr = malloc(sizeof(struct allocMutex));
sl@0
   864
    if (lockPtr == NULL) {
sl@0
   865
	panic("could not allocate lock");
sl@0
   866
    }
sl@0
   867
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock;
sl@0
   868
    pthread_mutex_init(&lockPtr->plock, NULL);
sl@0
   869
    return &lockPtr->tlock;
sl@0
   870
}
sl@0
   871
sl@0
   872
void
sl@0
   873
TclpFreeAllocMutex(mutex)
sl@0
   874
    Tcl_Mutex *mutex; /* The alloc mutex to free. */
sl@0
   875
{
sl@0
   876
    allocMutex* lockPtr = (allocMutex*) mutex;
sl@0
   877
    if (!lockPtr) return;
sl@0
   878
    pthread_mutex_destroy(&lockPtr->plock);
sl@0
   879
    free(lockPtr);
sl@0
   880
}
sl@0
   881
sl@0
   882
void TclpFreeAllocCache(ptr)
sl@0
   883
    void *ptr;
sl@0
   884
{
sl@0
   885
    if (ptr != NULL) {
sl@0
   886
        /*
sl@0
   887
         * Called by the pthread lib when a thread exits
sl@0
   888
         */
sl@0
   889
        TclFreeAllocCache(ptr);
sl@0
   890
    } else if (initialized) {
sl@0
   891
        /*
sl@0
   892
         * Called by us in TclFinalizeThreadAlloc() during
sl@0
   893
         * the library finalization initiated from Tcl_Finalize()
sl@0
   894
         */
sl@0
   895
        pthread_key_delete(key);
sl@0
   896
        initialized = 0;
sl@0
   897
    }
sl@0
   898
}
sl@0
   899
sl@0
   900
void *
sl@0
   901
TclpGetAllocCache(void)
sl@0
   902
{
sl@0
   903
    if (!initialized) {
sl@0
   904
	pthread_mutex_lock(allocLockPtr);
sl@0
   905
	if (!initialized) {
sl@0
   906
	    pthread_key_create(&key, TclpFreeAllocCache);
sl@0
   907
	    initialized = 1;
sl@0
   908
	}
sl@0
   909
	pthread_mutex_unlock(allocLockPtr);
sl@0
   910
    }
sl@0
   911
    return pthread_getspecific(key);
sl@0
   912
}
sl@0
   913
sl@0
   914
void
sl@0
   915
TclpSetAllocCache(void *arg)
sl@0
   916
{
sl@0
   917
    pthread_setspecific(key, arg);
sl@0
   918
}
sl@0
   919
sl@0
   920
#endif /* USE_THREAD_ALLOC */
sl@0
   921
#endif /* TCL_THREADS */