os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinThrd.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
 * tclWinThread.c --
sl@0
     3
 *
sl@0
     4
 *	This file implements the Windows-specific thread operations.
sl@0
     5
 *
sl@0
     6
 * Copyright (c) 1998 by Sun Microsystems, Inc.
sl@0
     7
 * Copyright (c) 1999 by Scriptics Corporation
sl@0
     8
 *
sl@0
     9
 * See the file "license.terms" for information on usage and redistribution
sl@0
    10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    11
 *
sl@0
    12
 * RCS: @(#) $Id: tclWinThrd.c,v 1.24.2.12 2007/03/24 09:31:11 vasiljevic Exp $
sl@0
    13
 */
sl@0
    14
sl@0
    15
#include "tclWinInt.h"
sl@0
    16
sl@0
    17
#include <fcntl.h>
sl@0
    18
#include <io.h>
sl@0
    19
#include <sys/stat.h>
sl@0
    20
sl@0
    21
/*
sl@0
    22
 * This is the master lock used to serialize access to other
sl@0
    23
 * serialization data structures.
sl@0
    24
 */
sl@0
    25
sl@0
    26
static CRITICAL_SECTION masterLock;
sl@0
    27
static int init = 0;
sl@0
    28
#define MASTER_LOCK TclpMasterLock() 
sl@0
    29
#define MASTER_UNLOCK TclpMasterUnlock() 
sl@0
    30
sl@0
    31
sl@0
    32
/*
sl@0
    33
 * This is the master lock used to serialize initialization and finalization
sl@0
    34
 * of Tcl as a whole.
sl@0
    35
 */
sl@0
    36
sl@0
    37
static CRITICAL_SECTION initLock;
sl@0
    38
sl@0
    39
/*
sl@0
    40
 * allocLock is used by Tcl's version of malloc for synchronization.
sl@0
    41
 * For obvious reasons, cannot use any dyamically allocated storage.
sl@0
    42
 */
sl@0
    43
sl@0
    44
#ifdef TCL_THREADS
sl@0
    45
sl@0
    46
static CRITICAL_SECTION allocLock;
sl@0
    47
static Tcl_Mutex allocLockPtr = (Tcl_Mutex) &allocLock;
sl@0
    48
static int allocOnce = 0;
sl@0
    49
sl@0
    50
#endif /* TCL_THREADS */
sl@0
    51
sl@0
    52
/*
sl@0
    53
 * The joinLock serializes Create- and ExitThread. This is necessary to
sl@0
    54
 * prevent a race where a new joinable thread exits before the creating
sl@0
    55
 * thread had the time to create the necessary data structures in the
sl@0
    56
 * emulation layer.
sl@0
    57
 */
sl@0
    58
sl@0
    59
static CRITICAL_SECTION joinLock;
sl@0
    60
sl@0
    61
/*
sl@0
    62
 * Condition variables are implemented with a combination of a 
sl@0
    63
 * per-thread Windows Event and a per-condition waiting queue.
sl@0
    64
 * The idea is that each thread has its own Event that it waits
sl@0
    65
 * on when it is doing a ConditionWait; it uses the same event for
sl@0
    66
 * all condition variables because it only waits on one at a time.
sl@0
    67
 * Each condition variable has a queue of waiting threads, and a 
sl@0
    68
 * mutex used to serialize access to this queue.
sl@0
    69
 *
sl@0
    70
 * Special thanks to David Nichols and
sl@0
    71
 * Jim Davidson for advice on the Condition Variable implementation.
sl@0
    72
 */
sl@0
    73
sl@0
    74
/*
sl@0
    75
 * The per-thread event and queue pointers.
sl@0
    76
 */
sl@0
    77
sl@0
    78
#ifdef TCL_THREADS
sl@0
    79
sl@0
    80
typedef struct ThreadSpecificData {
sl@0
    81
    HANDLE condEvent;			/* Per-thread condition event */
sl@0
    82
    struct ThreadSpecificData *nextPtr;	/* Queue pointers */
sl@0
    83
    struct ThreadSpecificData *prevPtr;
sl@0
    84
    int flags;				/* See flags below */
sl@0
    85
} ThreadSpecificData;
sl@0
    86
static Tcl_ThreadDataKey dataKey;
sl@0
    87
sl@0
    88
#endif /* TCL_THREADS */
sl@0
    89
sl@0
    90
/*
sl@0
    91
 * Additions by AOL for specialized thread memory allocator.
sl@0
    92
 */
sl@0
    93
sl@0
    94
#if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
sl@0
    95
static int   once;
sl@0
    96
static DWORD tlsKey;
sl@0
    97
sl@0
    98
typedef struct allocMutex {
sl@0
    99
    Tcl_Mutex        tlock;
sl@0
   100
    CRITICAL_SECTION wlock;
sl@0
   101
} allocMutex;
sl@0
   102
#endif
sl@0
   103
sl@0
   104
/*
sl@0
   105
 * State bits for the thread.
sl@0
   106
 * WIN_THREAD_UNINIT		Uninitialized.  Must be zero because
sl@0
   107
 *				of the way ThreadSpecificData is created.
sl@0
   108
 * WIN_THREAD_RUNNING		Running, not waiting.
sl@0
   109
 * WIN_THREAD_BLOCKED		Waiting, or trying to wait.
sl@0
   110
 */ 
sl@0
   111
sl@0
   112
#define WIN_THREAD_UNINIT	0x0
sl@0
   113
#define WIN_THREAD_RUNNING	0x1
sl@0
   114
#define WIN_THREAD_BLOCKED	0x2
sl@0
   115
sl@0
   116
/*
sl@0
   117
 * The per condition queue pointers and the
sl@0
   118
 * Mutex used to serialize access to the queue.
sl@0
   119
 */
sl@0
   120
sl@0
   121
typedef struct WinCondition {
sl@0
   122
    CRITICAL_SECTION condLock;	/* Lock to serialize queuing on the condition */
sl@0
   123
    struct ThreadSpecificData *firstPtr;	/* Queue pointers */
sl@0
   124
    struct ThreadSpecificData *lastPtr;
sl@0
   125
} WinCondition;
sl@0
   126
sl@0
   127

sl@0
   128
/*
sl@0
   129
 *----------------------------------------------------------------------
sl@0
   130
 *
sl@0
   131
 * TclpThreadCreate --
sl@0
   132
 *
sl@0
   133
 *	This procedure creates a new thread.
sl@0
   134
 *
sl@0
   135
 * Results:
sl@0
   136
 *	TCL_OK if the thread could be created.  The thread ID is
sl@0
   137
 *	returned in a parameter.
sl@0
   138
 *
sl@0
   139
 * Side effects:
sl@0
   140
 *	A new thread is created.
sl@0
   141
 *
sl@0
   142
 *----------------------------------------------------------------------
sl@0
   143
 */
sl@0
   144
sl@0
   145
int
sl@0
   146
TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
sl@0
   147
    Tcl_ThreadId *idPtr;		/* Return, the ID of the thread */
sl@0
   148
    Tcl_ThreadCreateProc proc;		/* Main() function of the thread */
sl@0
   149
    ClientData clientData;		/* The one argument to Main() */
sl@0
   150
    int stackSize;			/* Size of stack for the new thread */
sl@0
   151
    int flags;				/* Flags controlling behaviour of
sl@0
   152
					 * the new thread */
sl@0
   153
{
sl@0
   154
    HANDLE tHandle;
sl@0
   155
sl@0
   156
    EnterCriticalSection(&joinLock);
sl@0
   157
sl@0
   158
#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
sl@0
   159
    tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, proc,
sl@0
   160
	clientData, 0, (unsigned *)idPtr);
sl@0
   161
#else
sl@0
   162
    tHandle = CreateThread(NULL, (DWORD) stackSize,
sl@0
   163
	    (LPTHREAD_START_ROUTINE) proc, (LPVOID) clientData,
sl@0
   164
	    (DWORD) 0, (LPDWORD)idPtr);
sl@0
   165
#endif
sl@0
   166
sl@0
   167
    if (tHandle == NULL) {
sl@0
   168
        LeaveCriticalSection(&joinLock);
sl@0
   169
	return TCL_ERROR;
sl@0
   170
    } else {
sl@0
   171
        if (flags & TCL_THREAD_JOINABLE) {
sl@0
   172
	    TclRememberJoinableThread (*idPtr);
sl@0
   173
	}
sl@0
   174
sl@0
   175
	/*
sl@0
   176
	 * The only purpose of this is to decrement the reference count so the
sl@0
   177
	 * OS resources will be reaquired when the thread closes.
sl@0
   178
	 */
sl@0
   179
sl@0
   180
	CloseHandle(tHandle);
sl@0
   181
	LeaveCriticalSection(&joinLock);
sl@0
   182
	return TCL_OK;
sl@0
   183
    }
sl@0
   184
}
sl@0
   185

sl@0
   186
/*
sl@0
   187
 *----------------------------------------------------------------------
sl@0
   188
 *
sl@0
   189
 * Tcl_JoinThread --
sl@0
   190
 *
sl@0
   191
 *	This procedure waits upon the exit of the specified thread.
sl@0
   192
 *
sl@0
   193
 * Results:
sl@0
   194
 *	TCL_OK if the wait was successful, TCL_ERROR else.
sl@0
   195
 *
sl@0
   196
 * Side effects:
sl@0
   197
 *	The result area is set to the exit code of the thread we
sl@0
   198
 *	waited upon.
sl@0
   199
 *
sl@0
   200
 *----------------------------------------------------------------------
sl@0
   201
 */
sl@0
   202
sl@0
   203
int
sl@0
   204
Tcl_JoinThread(threadId, result)
sl@0
   205
    Tcl_ThreadId threadId;  /* Id of the thread to wait upon */
sl@0
   206
    int*     result;	    /* Reference to the storage the result
sl@0
   207
			     * of the thread we wait upon will be
sl@0
   208
			     * written into. */
sl@0
   209
{
sl@0
   210
    return TclJoinThread (threadId, result);
sl@0
   211
}
sl@0
   212

sl@0
   213
/*
sl@0
   214
 *----------------------------------------------------------------------
sl@0
   215
 *
sl@0
   216
 * TclpThreadExit --
sl@0
   217
 *
sl@0
   218
 *	This procedure terminates the current thread.
sl@0
   219
 *
sl@0
   220
 * Results:
sl@0
   221
 *	None.
sl@0
   222
 *
sl@0
   223
 * Side effects:
sl@0
   224
 *	This procedure terminates the current thread.
sl@0
   225
 *
sl@0
   226
 *----------------------------------------------------------------------
sl@0
   227
 */
sl@0
   228
sl@0
   229
void
sl@0
   230
TclpThreadExit(status)
sl@0
   231
    int status;
sl@0
   232
{
sl@0
   233
    EnterCriticalSection(&joinLock);
sl@0
   234
    TclSignalExitThread (Tcl_GetCurrentThread (), status);
sl@0
   235
    LeaveCriticalSection(&joinLock);
sl@0
   236
sl@0
   237
#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
sl@0
   238
    _endthreadex((unsigned) status);
sl@0
   239
#else
sl@0
   240
    ExitThread((DWORD) status);
sl@0
   241
#endif
sl@0
   242
}
sl@0
   243

sl@0
   244
/*
sl@0
   245
 *----------------------------------------------------------------------
sl@0
   246
 *
sl@0
   247
 * Tcl_GetCurrentThread --
sl@0
   248
 *
sl@0
   249
 *	This procedure returns the ID of the currently running thread.
sl@0
   250
 *
sl@0
   251
 * Results:
sl@0
   252
 *	A thread ID.
sl@0
   253
 *
sl@0
   254
 * Side effects:
sl@0
   255
 *	None.
sl@0
   256
 *
sl@0
   257
 *----------------------------------------------------------------------
sl@0
   258
 */
sl@0
   259
sl@0
   260
Tcl_ThreadId
sl@0
   261
Tcl_GetCurrentThread()
sl@0
   262
{
sl@0
   263
    return (Tcl_ThreadId)GetCurrentThreadId();
sl@0
   264
}
sl@0
   265

sl@0
   266
/*
sl@0
   267
 *----------------------------------------------------------------------
sl@0
   268
 *
sl@0
   269
 * TclpInitLock
sl@0
   270
 *
sl@0
   271
 *	This procedure is used to grab a lock that serializes initialization
sl@0
   272
 *	and finalization of Tcl.  On some platforms this may also initialize
sl@0
   273
 *	the mutex used to serialize creation of more mutexes and thread
sl@0
   274
 *	local storage keys.
sl@0
   275
 *
sl@0
   276
 * Results:
sl@0
   277
 *	None.
sl@0
   278
 *
sl@0
   279
 * Side effects:
sl@0
   280
 *	Acquire the initialization mutex.
sl@0
   281
 *
sl@0
   282
 *----------------------------------------------------------------------
sl@0
   283
 */
sl@0
   284
sl@0
   285
void
sl@0
   286
TclpInitLock()
sl@0
   287
{
sl@0
   288
    if (!init) {
sl@0
   289
	/*
sl@0
   290
	 * There is a fundamental race here that is solved by creating
sl@0
   291
	 * the first Tcl interpreter in a single threaded environment.
sl@0
   292
	 * Once the interpreter has been created, it is safe to create
sl@0
   293
	 * more threads that create interpreters in parallel.
sl@0
   294
	 */
sl@0
   295
	init = 1;
sl@0
   296
	InitializeCriticalSection(&joinLock);
sl@0
   297
	InitializeCriticalSection(&initLock);
sl@0
   298
	InitializeCriticalSection(&masterLock);
sl@0
   299
    }
sl@0
   300
    EnterCriticalSection(&initLock);
sl@0
   301
}
sl@0
   302

sl@0
   303
/*
sl@0
   304
 *----------------------------------------------------------------------
sl@0
   305
 *
sl@0
   306
 * TclpInitUnlock
sl@0
   307
 *
sl@0
   308
 *	This procedure is used to release a lock that serializes initialization
sl@0
   309
 *	and finalization of Tcl.
sl@0
   310
 *
sl@0
   311
 * Results:
sl@0
   312
 *	None.
sl@0
   313
 *
sl@0
   314
 * Side effects:
sl@0
   315
 *	Release the initialization mutex.
sl@0
   316
 *
sl@0
   317
 *----------------------------------------------------------------------
sl@0
   318
 */
sl@0
   319
sl@0
   320
void
sl@0
   321
TclpInitUnlock()
sl@0
   322
{
sl@0
   323
    LeaveCriticalSection(&initLock);
sl@0
   324
}
sl@0
   325

sl@0
   326
/*
sl@0
   327
 *----------------------------------------------------------------------
sl@0
   328
 *
sl@0
   329
 * TclpMasterLock
sl@0
   330
 *
sl@0
   331
 *	This procedure is used to grab a lock that serializes creation
sl@0
   332
 *	of mutexes, condition variables, and thread local storage keys.
sl@0
   333
 *
sl@0
   334
 *	This lock must be different than the initLock because the
sl@0
   335
 *	initLock is held during creation of syncronization objects.
sl@0
   336
 *
sl@0
   337
 * Results:
sl@0
   338
 *	None.
sl@0
   339
 *
sl@0
   340
 * Side effects:
sl@0
   341
 *	Acquire the master mutex.
sl@0
   342
 *
sl@0
   343
 *----------------------------------------------------------------------
sl@0
   344
 */
sl@0
   345
sl@0
   346
void
sl@0
   347
TclpMasterLock()
sl@0
   348
{
sl@0
   349
    if (!init) {
sl@0
   350
	/*
sl@0
   351
	 * There is a fundamental race here that is solved by creating
sl@0
   352
	 * the first Tcl interpreter in a single threaded environment.
sl@0
   353
	 * Once the interpreter has been created, it is safe to create
sl@0
   354
	 * more threads that create interpreters in parallel.
sl@0
   355
	 */
sl@0
   356
	init = 1;
sl@0
   357
	InitializeCriticalSection(&joinLock);
sl@0
   358
	InitializeCriticalSection(&initLock);
sl@0
   359
	InitializeCriticalSection(&masterLock);
sl@0
   360
    }
sl@0
   361
    EnterCriticalSection(&masterLock);
sl@0
   362
}
sl@0
   363

sl@0
   364
/*
sl@0
   365
 *----------------------------------------------------------------------
sl@0
   366
 *
sl@0
   367
 * TclpMasterUnlock
sl@0
   368
 *
sl@0
   369
 *	This procedure is used to release a lock that serializes creation
sl@0
   370
 *	and deletion of synchronization objects.
sl@0
   371
 *
sl@0
   372
 * Results:
sl@0
   373
 *	None.
sl@0
   374
 *
sl@0
   375
 * Side effects:
sl@0
   376
 *	Release the master mutex.
sl@0
   377
 *
sl@0
   378
 *----------------------------------------------------------------------
sl@0
   379
 */
sl@0
   380
sl@0
   381
void
sl@0
   382
TclpMasterUnlock()
sl@0
   383
{
sl@0
   384
    LeaveCriticalSection(&masterLock);
sl@0
   385
}
sl@0
   386

sl@0
   387
/*
sl@0
   388
 *----------------------------------------------------------------------
sl@0
   389
 *
sl@0
   390
 * Tcl_GetAllocMutex
sl@0
   391
 *
sl@0
   392
 *	This procedure returns a pointer to a statically initialized
sl@0
   393
 *	mutex for use by the memory allocator.  The alloctor must
sl@0
   394
 *	use this lock, because all other locks are allocated...
sl@0
   395
 *
sl@0
   396
 * Results:
sl@0
   397
 *	A pointer to a mutex that is suitable for passing to
sl@0
   398
 *	Tcl_MutexLock and Tcl_MutexUnlock.
sl@0
   399
 *
sl@0
   400
 * Side effects:
sl@0
   401
 *	None.
sl@0
   402
 *
sl@0
   403
 *----------------------------------------------------------------------
sl@0
   404
 */
sl@0
   405
sl@0
   406
Tcl_Mutex *
sl@0
   407
Tcl_GetAllocMutex()
sl@0
   408
{
sl@0
   409
#ifdef TCL_THREADS
sl@0
   410
    if (!allocOnce) {
sl@0
   411
	InitializeCriticalSection(&allocLock);
sl@0
   412
	allocOnce = 1;
sl@0
   413
    }
sl@0
   414
    return &allocLockPtr;
sl@0
   415
#else
sl@0
   416
    return NULL;
sl@0
   417
#endif
sl@0
   418
}
sl@0
   419

sl@0
   420
/*
sl@0
   421
 *----------------------------------------------------------------------
sl@0
   422
 *
sl@0
   423
 * TclpFinalizeLock
sl@0
   424
 *
sl@0
   425
 *	This procedure is used to destroy all private resources used in
sl@0
   426
 *	this file.
sl@0
   427
 *
sl@0
   428
 * Results:
sl@0
   429
 *	None.
sl@0
   430
 *
sl@0
   431
 * Side effects:
sl@0
   432
 *	Destroys everything private.  TclpInitLock must be held
sl@0
   433
 *	entering this function.
sl@0
   434
 *
sl@0
   435
 *----------------------------------------------------------------------
sl@0
   436
 */
sl@0
   437
sl@0
   438
void
sl@0
   439
TclFinalizeLock ()
sl@0
   440
{
sl@0
   441
    MASTER_LOCK;
sl@0
   442
    DeleteCriticalSection(&joinLock);
sl@0
   443
    /* Destroy the critical section that we are holding! */
sl@0
   444
    DeleteCriticalSection(&masterLock);
sl@0
   445
    init = 0;
sl@0
   446
#ifdef TCL_THREADS
sl@0
   447
    DeleteCriticalSection(&allocLock);
sl@0
   448
    allocOnce = 0;
sl@0
   449
#endif
sl@0
   450
    /* Destroy the critical section that we are holding! */
sl@0
   451
    DeleteCriticalSection(&initLock);
sl@0
   452
}
sl@0
   453

sl@0
   454
#ifdef TCL_THREADS
sl@0
   455
sl@0
   456
/* locally used prototype */
sl@0
   457
static void FinalizeConditionEvent(ClientData data);
sl@0
   458
sl@0
   459

sl@0
   460
/*
sl@0
   461
 *----------------------------------------------------------------------
sl@0
   462
 *
sl@0
   463
 * Tcl_MutexLock --
sl@0
   464
 *
sl@0
   465
 *	This procedure is invoked to lock a mutex.  This is a self 
sl@0
   466
 *	initializing mutex that is automatically finalized during
sl@0
   467
 *	Tcl_Finalize.
sl@0
   468
 *
sl@0
   469
 * Results:
sl@0
   470
 *	None.
sl@0
   471
 *
sl@0
   472
 * Side effects:
sl@0
   473
 *	May block the current thread.  The mutex is aquired when
sl@0
   474
 *	this returns.
sl@0
   475
 *
sl@0
   476
 *----------------------------------------------------------------------
sl@0
   477
 */
sl@0
   478
sl@0
   479
void
sl@0
   480
Tcl_MutexLock(mutexPtr)
sl@0
   481
    Tcl_Mutex *mutexPtr;	/* The lock */
sl@0
   482
{
sl@0
   483
    CRITICAL_SECTION *csPtr;
sl@0
   484
    if (*mutexPtr == NULL) {
sl@0
   485
	MASTER_LOCK;
sl@0
   486
sl@0
   487
	/* 
sl@0
   488
	 * Double inside master lock check to avoid a race.
sl@0
   489
	 */
sl@0
   490
sl@0
   491
	if (*mutexPtr == NULL) {
sl@0
   492
	    csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION));
sl@0
   493
	    InitializeCriticalSection(csPtr);
sl@0
   494
	    *mutexPtr = (Tcl_Mutex)csPtr;
sl@0
   495
	    TclRememberMutex(mutexPtr);
sl@0
   496
	}
sl@0
   497
	MASTER_UNLOCK;
sl@0
   498
    }
sl@0
   499
    csPtr = *((CRITICAL_SECTION **)mutexPtr);
sl@0
   500
    EnterCriticalSection(csPtr);
sl@0
   501
}
sl@0
   502

sl@0
   503
/*
sl@0
   504
 *----------------------------------------------------------------------
sl@0
   505
 *
sl@0
   506
 * Tcl_MutexUnlock --
sl@0
   507
 *
sl@0
   508
 *	This procedure is invoked to unlock a mutex.
sl@0
   509
 *
sl@0
   510
 * Results:
sl@0
   511
 *	None.
sl@0
   512
 *
sl@0
   513
 * Side effects:
sl@0
   514
 *	The mutex is released when this returns.
sl@0
   515
 *
sl@0
   516
 *----------------------------------------------------------------------
sl@0
   517
 */
sl@0
   518
sl@0
   519
void
sl@0
   520
Tcl_MutexUnlock(mutexPtr)
sl@0
   521
    Tcl_Mutex *mutexPtr;	/* The lock */
sl@0
   522
{
sl@0
   523
    CRITICAL_SECTION *csPtr = *((CRITICAL_SECTION **)mutexPtr);
sl@0
   524
    LeaveCriticalSection(csPtr);
sl@0
   525
}
sl@0
   526

sl@0
   527
/*
sl@0
   528
 *----------------------------------------------------------------------
sl@0
   529
 *
sl@0
   530
 * TclpFinalizeMutex --
sl@0
   531
 *
sl@0
   532
 *	This procedure is invoked to clean up one mutex.  This is only
sl@0
   533
 *	safe to call at the end of time.
sl@0
   534
 *
sl@0
   535
 * Results:
sl@0
   536
 *	None.
sl@0
   537
 *
sl@0
   538
 * Side effects:
sl@0
   539
 *	The mutex list is deallocated.
sl@0
   540
 *
sl@0
   541
 *----------------------------------------------------------------------
sl@0
   542
 */
sl@0
   543
sl@0
   544
void
sl@0
   545
TclpFinalizeMutex(mutexPtr)
sl@0
   546
    Tcl_Mutex *mutexPtr;
sl@0
   547
{
sl@0
   548
    CRITICAL_SECTION *csPtr = *(CRITICAL_SECTION **)mutexPtr;
sl@0
   549
    if (csPtr != NULL) {
sl@0
   550
	DeleteCriticalSection(csPtr);
sl@0
   551
	ckfree((char *)csPtr);
sl@0
   552
	*mutexPtr = NULL;
sl@0
   553
    }
sl@0
   554
}
sl@0
   555

sl@0
   556
/*
sl@0
   557
 *----------------------------------------------------------------------
sl@0
   558
 *
sl@0
   559
 * TclpThreadDataKeyInit --
sl@0
   560
 *
sl@0
   561
 *	This procedure initializes a thread specific data block key.
sl@0
   562
 *	Each thread has table of pointers to thread specific data.
sl@0
   563
 *	all threads agree on which table entry is used by each module.
sl@0
   564
 *	this is remembered in a "data key", that is just an index into
sl@0
   565
 *	this table.  To allow self initialization, the interface
sl@0
   566
 *	passes a pointer to this key and the first thread to use
sl@0
   567
 *	the key fills in the pointer to the key.  The key should be
sl@0
   568
 *	a process-wide static.
sl@0
   569
 *
sl@0
   570
 * Results:
sl@0
   571
 *	None.
sl@0
   572
 *
sl@0
   573
 * Side effects:
sl@0
   574
 *	Will allocate memory the first time this process calls for
sl@0
   575
 *	this key.  In this case it modifies its argument
sl@0
   576
 *	to hold the pointer to information about the key.
sl@0
   577
 *
sl@0
   578
 *----------------------------------------------------------------------
sl@0
   579
 */
sl@0
   580
sl@0
   581
void
sl@0
   582
TclpThreadDataKeyInit(keyPtr)
sl@0
   583
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   584
				 * really (DWORD **) */
sl@0
   585
{
sl@0
   586
    DWORD *indexPtr;
sl@0
   587
    DWORD newKey;
sl@0
   588
sl@0
   589
    MASTER_LOCK;
sl@0
   590
    if (*keyPtr == NULL) {
sl@0
   591
	indexPtr = (DWORD *)ckalloc(sizeof(DWORD));
sl@0
   592
	newKey = TlsAlloc();
sl@0
   593
        if (newKey != TLS_OUT_OF_INDEXES) {
sl@0
   594
            *indexPtr = newKey;
sl@0
   595
        } else {
sl@0
   596
            panic("TlsAlloc failed from TclpThreadDataKeyInit!"); /* this should be a fatal error */
sl@0
   597
        }
sl@0
   598
	*keyPtr = (Tcl_ThreadDataKey)indexPtr;
sl@0
   599
	TclRememberDataKey(keyPtr);
sl@0
   600
    }
sl@0
   601
    MASTER_UNLOCK;
sl@0
   602
}
sl@0
   603

sl@0
   604
/*
sl@0
   605
 *----------------------------------------------------------------------
sl@0
   606
 *
sl@0
   607
 * TclpThreadDataKeyGet --
sl@0
   608
 *
sl@0
   609
 *	This procedure returns a pointer to a block of thread local storage.
sl@0
   610
 *
sl@0
   611
 * Results:
sl@0
   612
 *	A thread-specific pointer to the data structure, or NULL
sl@0
   613
 *	if the memory has not been assigned to this key for this thread.
sl@0
   614
 *
sl@0
   615
 * Side effects:
sl@0
   616
 *	None.
sl@0
   617
 *
sl@0
   618
 *----------------------------------------------------------------------
sl@0
   619
 */
sl@0
   620
sl@0
   621
VOID *
sl@0
   622
TclpThreadDataKeyGet(keyPtr)
sl@0
   623
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   624
				 * really (DWORD **) */
sl@0
   625
{
sl@0
   626
    DWORD *indexPtr = *(DWORD **)keyPtr;
sl@0
   627
    LPVOID result;
sl@0
   628
    if (indexPtr == NULL) {
sl@0
   629
	return NULL;
sl@0
   630
    } else {
sl@0
   631
        result = TlsGetValue(*indexPtr);
sl@0
   632
        if ((result == NULL) && (GetLastError() != NO_ERROR)) {
sl@0
   633
            panic("TlsGetValue failed from TclpThreadDataKeyGet!");
sl@0
   634
        }
sl@0
   635
	return result;
sl@0
   636
    }
sl@0
   637
}
sl@0
   638

sl@0
   639
/*
sl@0
   640
 *----------------------------------------------------------------------
sl@0
   641
 *
sl@0
   642
 * TclpThreadDataKeySet --
sl@0
   643
 *
sl@0
   644
 *	This procedure sets the pointer to a block of thread local storage.
sl@0
   645
 *
sl@0
   646
 * Results:
sl@0
   647
 *	None.
sl@0
   648
 *
sl@0
   649
 * Side effects:
sl@0
   650
 *	Sets up the thread so future calls to TclpThreadDataKeyGet with
sl@0
   651
 *	this key will return the data pointer.
sl@0
   652
 *
sl@0
   653
 *----------------------------------------------------------------------
sl@0
   654
 */
sl@0
   655
sl@0
   656
void
sl@0
   657
TclpThreadDataKeySet(keyPtr, data)
sl@0
   658
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   659
				 * really (pthread_key_t **) */
sl@0
   660
    VOID *data;			/* Thread local storage */
sl@0
   661
{
sl@0
   662
    DWORD *indexPtr = *(DWORD **)keyPtr;
sl@0
   663
    BOOL success;
sl@0
   664
    success = TlsSetValue(*indexPtr, (void *)data);
sl@0
   665
    if (!success) {
sl@0
   666
        panic("TlsSetValue failed from TclpThreadDataKeySet!");
sl@0
   667
    }
sl@0
   668
}
sl@0
   669

sl@0
   670
/*
sl@0
   671
 *----------------------------------------------------------------------
sl@0
   672
 *
sl@0
   673
 * TclpFinalizeThreadData --
sl@0
   674
 *
sl@0
   675
 *	This procedure cleans up the thread-local storage.  This is
sl@0
   676
 *	called once for each thread.
sl@0
   677
 *
sl@0
   678
 * Results:
sl@0
   679
 *	None.
sl@0
   680
 *
sl@0
   681
 * Side effects:
sl@0
   682
 *	Frees up the memory.
sl@0
   683
 *
sl@0
   684
 *----------------------------------------------------------------------
sl@0
   685
 */
sl@0
   686
sl@0
   687
void
sl@0
   688
TclpFinalizeThreadData(keyPtr)
sl@0
   689
    Tcl_ThreadDataKey *keyPtr;
sl@0
   690
{
sl@0
   691
    VOID *result;
sl@0
   692
    DWORD *indexPtr;
sl@0
   693
    BOOL success;
sl@0
   694
sl@0
   695
    if (*keyPtr != NULL) {
sl@0
   696
	indexPtr = *(DWORD **)keyPtr;
sl@0
   697
	result = (VOID *)TlsGetValue(*indexPtr);
sl@0
   698
	if (result != NULL) {
sl@0
   699
#if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
sl@0
   700
	    if (indexPtr == &tlsKey) {
sl@0
   701
		TclpFreeAllocCache(result);
sl@0
   702
		return;
sl@0
   703
	    }
sl@0
   704
#endif
sl@0
   705
	    ckfree((char *)result);
sl@0
   706
	    success = TlsSetValue(*indexPtr, (void *)NULL);
sl@0
   707
            if (!success) {
sl@0
   708
                panic("TlsSetValue failed from TclpFinalizeThreadData!");
sl@0
   709
            }
sl@0
   710
	} else {
sl@0
   711
            if (GetLastError() != NO_ERROR) {
sl@0
   712
                panic("TlsGetValue failed from TclpFinalizeThreadData!");
sl@0
   713
            }
sl@0
   714
	}
sl@0
   715
    }
sl@0
   716
}
sl@0
   717

sl@0
   718
/*
sl@0
   719
 *----------------------------------------------------------------------
sl@0
   720
 *
sl@0
   721
 * TclpFinalizeThreadDataKey --
sl@0
   722
 *
sl@0
   723
 *	This procedure is invoked to clean up one key.  This is a
sl@0
   724
 *	process-wide storage identifier.  The thread finalization code
sl@0
   725
 *	cleans up the thread local storage itself.
sl@0
   726
 *
sl@0
   727
 *	This assumes the master lock is held.
sl@0
   728
 *
sl@0
   729
 * Results:
sl@0
   730
 *	None.
sl@0
   731
 *
sl@0
   732
 * Side effects:
sl@0
   733
 *	The key is deallocated.
sl@0
   734
 *
sl@0
   735
 *----------------------------------------------------------------------
sl@0
   736
 */
sl@0
   737
sl@0
   738
void
sl@0
   739
TclpFinalizeThreadDataKey(keyPtr)
sl@0
   740
    Tcl_ThreadDataKey *keyPtr;
sl@0
   741
{
sl@0
   742
    DWORD *indexPtr;
sl@0
   743
    BOOL success;
sl@0
   744
    if (*keyPtr != NULL) {
sl@0
   745
	indexPtr = *(DWORD **)keyPtr;
sl@0
   746
	success = TlsFree(*indexPtr);
sl@0
   747
        if (!success) {
sl@0
   748
            panic("TlsFree failed from TclpFinalizeThreadDataKey!");
sl@0
   749
        }
sl@0
   750
	ckfree((char *)indexPtr);
sl@0
   751
	*keyPtr = NULL;
sl@0
   752
    }
sl@0
   753
}
sl@0
   754

sl@0
   755
/*
sl@0
   756
 *----------------------------------------------------------------------
sl@0
   757
 *
sl@0
   758
 * Tcl_ConditionWait --
sl@0
   759
 *
sl@0
   760
 *	This procedure is invoked to wait on a condition variable.
sl@0
   761
 *	The mutex is atomically released as part of the wait, and
sl@0
   762
 *	automatically grabbed when the condition is signaled.
sl@0
   763
 *
sl@0
   764
 *	The mutex must be held when this procedure is called.
sl@0
   765
 *
sl@0
   766
 * Results:
sl@0
   767
 *	None.
sl@0
   768
 *
sl@0
   769
 * Side effects:
sl@0
   770
 *	May block the current thread.  The mutex is aquired when
sl@0
   771
 *	this returns.  Will allocate memory for a HANDLE
sl@0
   772
 *	and initialize this the first time this Tcl_Condition is used.
sl@0
   773
 *
sl@0
   774
 *----------------------------------------------------------------------
sl@0
   775
 */
sl@0
   776
sl@0
   777
void
sl@0
   778
Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
sl@0
   779
    Tcl_Condition *condPtr;	/* Really (WinCondition **) */
sl@0
   780
    Tcl_Mutex *mutexPtr;	/* Really (CRITICAL_SECTION **) */
sl@0
   781
    Tcl_Time *timePtr;		/* Timeout on waiting period */
sl@0
   782
{
sl@0
   783
    WinCondition *winCondPtr;	/* Per-condition queue head */
sl@0
   784
    CRITICAL_SECTION *csPtr;	/* Caller's Mutex, after casting */
sl@0
   785
    DWORD wtime;		/* Windows time value */
sl@0
   786
    int timeout;		/* True if we got a timeout */
sl@0
   787
    int doExit = 0;		/* True if we need to do exit setup */
sl@0
   788
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
sl@0
   789
sl@0
   790
    /*
sl@0
   791
     * Self initialize the two parts of the condition.
sl@0
   792
     * The per-condition and per-thread parts need to be
sl@0
   793
     * handled independently.
sl@0
   794
     */
sl@0
   795
sl@0
   796
    if (tsdPtr->flags == WIN_THREAD_UNINIT) {
sl@0
   797
	MASTER_LOCK;
sl@0
   798
sl@0
   799
	/* 
sl@0
   800
	 * Create the per-thread event and queue pointers.
sl@0
   801
	 */
sl@0
   802
sl@0
   803
	if (tsdPtr->flags == WIN_THREAD_UNINIT) {
sl@0
   804
	    tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */,
sl@0
   805
			FALSE /* non signaled */, NULL);
sl@0
   806
	    tsdPtr->nextPtr = NULL;
sl@0
   807
	    tsdPtr->prevPtr = NULL;
sl@0
   808
	    tsdPtr->flags = WIN_THREAD_RUNNING;
sl@0
   809
	    doExit = 1;
sl@0
   810
	}
sl@0
   811
	MASTER_UNLOCK;
sl@0
   812
sl@0
   813
	if (doExit) {
sl@0
   814
	    /*
sl@0
   815
	     * Create a per-thread exit handler to clean up the condEvent.
sl@0
   816
	     * We must be careful to do this outside the Master Lock
sl@0
   817
	     * because Tcl_CreateThreadExitHandler uses its own
sl@0
   818
	     * ThreadSpecificData, and initializing that may drop
sl@0
   819
	     * back into the Master Lock.
sl@0
   820
	     */
sl@0
   821
	    
sl@0
   822
	    Tcl_CreateThreadExitHandler(FinalizeConditionEvent,
sl@0
   823
		    (ClientData) tsdPtr);
sl@0
   824
	}
sl@0
   825
    }
sl@0
   826
sl@0
   827
    if (*condPtr == NULL) {
sl@0
   828
	MASTER_LOCK;
sl@0
   829
sl@0
   830
	/*
sl@0
   831
	 * Initialize the per-condition queue pointers and Mutex.
sl@0
   832
	 */
sl@0
   833
sl@0
   834
	if (*condPtr == NULL) {
sl@0
   835
	    winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition));
sl@0
   836
	    InitializeCriticalSection(&winCondPtr->condLock);
sl@0
   837
	    winCondPtr->firstPtr = NULL;
sl@0
   838
	    winCondPtr->lastPtr = NULL;
sl@0
   839
	    *condPtr = (Tcl_Condition)winCondPtr;
sl@0
   840
	    TclRememberCondition(condPtr);
sl@0
   841
	}
sl@0
   842
	MASTER_UNLOCK;
sl@0
   843
    }
sl@0
   844
    csPtr = *((CRITICAL_SECTION **)mutexPtr);
sl@0
   845
    winCondPtr = *((WinCondition **)condPtr);
sl@0
   846
    if (timePtr == NULL) {
sl@0
   847
	wtime = INFINITE;
sl@0
   848
    } else {
sl@0
   849
	wtime = timePtr->sec * 1000 + timePtr->usec / 1000;
sl@0
   850
    }
sl@0
   851
sl@0
   852
    /*
sl@0
   853
     * Queue the thread on the condition, using
sl@0
   854
     * the per-condition lock for serialization.
sl@0
   855
     */
sl@0
   856
sl@0
   857
    tsdPtr->flags = WIN_THREAD_BLOCKED;
sl@0
   858
    tsdPtr->nextPtr = NULL;
sl@0
   859
    EnterCriticalSection(&winCondPtr->condLock);
sl@0
   860
    tsdPtr->prevPtr = winCondPtr->lastPtr;		/* A: */
sl@0
   861
    winCondPtr->lastPtr = tsdPtr;
sl@0
   862
    if (tsdPtr->prevPtr != NULL) {
sl@0
   863
        tsdPtr->prevPtr->nextPtr = tsdPtr;
sl@0
   864
    }
sl@0
   865
    if (winCondPtr->firstPtr == NULL) {
sl@0
   866
        winCondPtr->firstPtr = tsdPtr;
sl@0
   867
    }
sl@0
   868
sl@0
   869
    /*
sl@0
   870
     * Unlock the caller's mutex and wait for the condition, or a timeout.
sl@0
   871
     * There is a minor issue here in that we don't count down the
sl@0
   872
     * timeout if we get notified, but another thread grabs the condition
sl@0
   873
     * before we do.  In that race condition we'll wait again for the
sl@0
   874
     * full timeout.  Timed waits are dubious anyway.  Either you have
sl@0
   875
     * the locking protocol wrong and are masking a deadlock,
sl@0
   876
     * or you are using conditions to pause your thread.
sl@0
   877
     */
sl@0
   878
    
sl@0
   879
    LeaveCriticalSection(csPtr);
sl@0
   880
    timeout = 0;
sl@0
   881
    while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
sl@0
   882
	ResetEvent(tsdPtr->condEvent);
sl@0
   883
	LeaveCriticalSection(&winCondPtr->condLock);
sl@0
   884
	if (WaitForSingleObject(tsdPtr->condEvent, wtime) == WAIT_TIMEOUT) {
sl@0
   885
	    timeout = 1;
sl@0
   886
	}
sl@0
   887
	EnterCriticalSection(&winCondPtr->condLock);
sl@0
   888
    }
sl@0
   889
sl@0
   890
    /*
sl@0
   891
     * Be careful on timeouts because the signal might arrive right around
sl@0
   892
     * the time limit and someone else could have taken us off the queue.
sl@0
   893
     */
sl@0
   894
    
sl@0
   895
    if (timeout) {
sl@0
   896
	if (tsdPtr->flags & WIN_THREAD_RUNNING) {
sl@0
   897
	    timeout = 0;
sl@0
   898
	} else {
sl@0
   899
	    /*
sl@0
   900
	     * When dequeuing, we can leave the tsdPtr->nextPtr
sl@0
   901
	     * and tsdPtr->prevPtr with dangling pointers because
sl@0
   902
	     * they are reinitialilzed w/out reading them when the
sl@0
   903
	     * thread is enqueued later.
sl@0
   904
	     */
sl@0
   905
sl@0
   906
            if (winCondPtr->firstPtr == tsdPtr) {
sl@0
   907
                winCondPtr->firstPtr = tsdPtr->nextPtr;
sl@0
   908
            } else {
sl@0
   909
                tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
sl@0
   910
            }
sl@0
   911
            if (winCondPtr->lastPtr == tsdPtr) {
sl@0
   912
                winCondPtr->lastPtr = tsdPtr->prevPtr;
sl@0
   913
            } else {
sl@0
   914
                tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
sl@0
   915
            }
sl@0
   916
            tsdPtr->flags = WIN_THREAD_RUNNING;
sl@0
   917
	}
sl@0
   918
    }
sl@0
   919
sl@0
   920
    LeaveCriticalSection(&winCondPtr->condLock);
sl@0
   921
    EnterCriticalSection(csPtr);
sl@0
   922
}
sl@0
   923

sl@0
   924
/*
sl@0
   925
 *----------------------------------------------------------------------
sl@0
   926
 *
sl@0
   927
 * Tcl_ConditionNotify --
sl@0
   928
 *
sl@0
   929
 *	This procedure is invoked to signal a condition variable.
sl@0
   930
 *
sl@0
   931
 *	The mutex must be held during this call to avoid races,
sl@0
   932
 *	but this interface does not enforce that.
sl@0
   933
 *
sl@0
   934
 * Results:
sl@0
   935
 *	None.
sl@0
   936
 *
sl@0
   937
 * Side effects:
sl@0
   938
 *	May unblock another thread.
sl@0
   939
 *
sl@0
   940
 *----------------------------------------------------------------------
sl@0
   941
 */
sl@0
   942
sl@0
   943
void
sl@0
   944
Tcl_ConditionNotify(condPtr)
sl@0
   945
    Tcl_Condition *condPtr;
sl@0
   946
{
sl@0
   947
    WinCondition *winCondPtr;
sl@0
   948
    ThreadSpecificData *tsdPtr;
sl@0
   949
sl@0
   950
    if (condPtr != NULL) {
sl@0
   951
	winCondPtr = *((WinCondition **)condPtr);
sl@0
   952
sl@0
   953
	if (winCondPtr == NULL) {
sl@0
   954
	    return;
sl@0
   955
	}
sl@0
   956
sl@0
   957
	/*
sl@0
   958
	 * Loop through all the threads waiting on the condition
sl@0
   959
	 * and notify them (i.e., broadcast semantics).  The queue
sl@0
   960
	 * manipulation is guarded by the per-condition coordinating mutex.
sl@0
   961
	 */
sl@0
   962
sl@0
   963
	EnterCriticalSection(&winCondPtr->condLock);
sl@0
   964
	while (winCondPtr->firstPtr != NULL) {
sl@0
   965
	    tsdPtr = winCondPtr->firstPtr;
sl@0
   966
	    winCondPtr->firstPtr = tsdPtr->nextPtr;
sl@0
   967
	    if (winCondPtr->lastPtr == tsdPtr) {
sl@0
   968
		winCondPtr->lastPtr = NULL;
sl@0
   969
	    }
sl@0
   970
	    tsdPtr->flags = WIN_THREAD_RUNNING;
sl@0
   971
	    tsdPtr->nextPtr = NULL;
sl@0
   972
	    tsdPtr->prevPtr = NULL;	/* Not strictly necessary, see A: */
sl@0
   973
	    SetEvent(tsdPtr->condEvent);
sl@0
   974
	}
sl@0
   975
	LeaveCriticalSection(&winCondPtr->condLock);
sl@0
   976
    } else {
sl@0
   977
	/*
sl@0
   978
	 * Noone has used the condition variable, so there are no waiters.
sl@0
   979
	 */
sl@0
   980
    }
sl@0
   981
}
sl@0
   982

sl@0
   983
/*
sl@0
   984
 *----------------------------------------------------------------------
sl@0
   985
 *
sl@0
   986
 * FinalizeConditionEvent --
sl@0
   987
 *
sl@0
   988
 *	This procedure is invoked to clean up the per-thread
sl@0
   989
 *	event used to implement condition waiting.
sl@0
   990
 *	This is only safe to call at the end of time.
sl@0
   991
 *
sl@0
   992
 * Results:
sl@0
   993
 *	None.
sl@0
   994
 *
sl@0
   995
 * Side effects:
sl@0
   996
 *	The per-thread event is closed.
sl@0
   997
 *
sl@0
   998
 *----------------------------------------------------------------------
sl@0
   999
 */
sl@0
  1000
sl@0
  1001
static void
sl@0
  1002
FinalizeConditionEvent(data)
sl@0
  1003
    ClientData data;
sl@0
  1004
{
sl@0
  1005
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data;
sl@0
  1006
    tsdPtr->flags = WIN_THREAD_UNINIT;
sl@0
  1007
    CloseHandle(tsdPtr->condEvent);
sl@0
  1008
}
sl@0
  1009

sl@0
  1010
/*
sl@0
  1011
 *----------------------------------------------------------------------
sl@0
  1012
 *
sl@0
  1013
 * TclpFinalizeCondition --
sl@0
  1014
 *
sl@0
  1015
 *	This procedure is invoked to clean up a condition variable.
sl@0
  1016
 *	This is only safe to call at the end of time.
sl@0
  1017
 *
sl@0
  1018
 *	This assumes the Master Lock is held.
sl@0
  1019
 *
sl@0
  1020
 * Results:
sl@0
  1021
 *	None.
sl@0
  1022
 *
sl@0
  1023
 * Side effects:
sl@0
  1024
 *	The condition variable is deallocated.
sl@0
  1025
 *
sl@0
  1026
 *----------------------------------------------------------------------
sl@0
  1027
 */
sl@0
  1028
sl@0
  1029
void
sl@0
  1030
TclpFinalizeCondition(condPtr)
sl@0
  1031
    Tcl_Condition *condPtr;
sl@0
  1032
{
sl@0
  1033
    WinCondition *winCondPtr = *(WinCondition **)condPtr;
sl@0
  1034
sl@0
  1035
    /*
sl@0
  1036
     * Note - this is called long after the thread-local storage is
sl@0
  1037
     * reclaimed.  The per-thread condition waiting event is
sl@0
  1038
     * reclaimed earlier in a per-thread exit handler, which is
sl@0
  1039
     * called before thread local storage is reclaimed.
sl@0
  1040
     */
sl@0
  1041
sl@0
  1042
    if (winCondPtr != NULL) {
sl@0
  1043
	DeleteCriticalSection(&winCondPtr->condLock);
sl@0
  1044
	ckfree((char *)winCondPtr);
sl@0
  1045
	*condPtr = NULL;
sl@0
  1046
    }
sl@0
  1047
}
sl@0
  1048
sl@0
  1049
/*
sl@0
  1050
 * Additions by AOL for specialized thread memory allocator.
sl@0
  1051
 */
sl@0
  1052
sl@0
  1053
#if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
sl@0
  1054
Tcl_Mutex *
sl@0
  1055
TclpNewAllocMutex(void)
sl@0
  1056
{
sl@0
  1057
    struct allocMutex *lockPtr;
sl@0
  1058
sl@0
  1059
    lockPtr = malloc(sizeof(struct allocMutex));
sl@0
  1060
    if (lockPtr == NULL) {
sl@0
  1061
	panic("could not allocate lock");
sl@0
  1062
    }
sl@0
  1063
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock;
sl@0
  1064
    InitializeCriticalSection(&lockPtr->wlock);
sl@0
  1065
    return &lockPtr->tlock;
sl@0
  1066
}
sl@0
  1067
sl@0
  1068
void
sl@0
  1069
TclpFreeAllocMutex(mutex)
sl@0
  1070
    Tcl_Mutex *mutex; /* The alloc mutex to free. */
sl@0
  1071
{
sl@0
  1072
    allocMutex* lockPtr = (allocMutex*) mutex;
sl@0
  1073
    if (!lockPtr) return;
sl@0
  1074
    DeleteCriticalSection(&lockPtr->wlock);
sl@0
  1075
    free(lockPtr);
sl@0
  1076
}
sl@0
  1077
sl@0
  1078
void *
sl@0
  1079
TclpGetAllocCache(void)
sl@0
  1080
{
sl@0
  1081
    VOID *result;
sl@0
  1082
sl@0
  1083
    if (!once) {
sl@0
  1084
	/*
sl@0
  1085
	 * We need to make sure that TclpFreeAllocCache is called
sl@0
  1086
	 * on each thread that calls this, but only on threads that
sl@0
  1087
	 * call this.
sl@0
  1088
	 */
sl@0
  1089
    	tlsKey = TlsAlloc();
sl@0
  1090
	once = 1;
sl@0
  1091
	if (tlsKey == TLS_OUT_OF_INDEXES) {
sl@0
  1092
	    panic("could not allocate thread local storage");
sl@0
  1093
	}
sl@0
  1094
    }
sl@0
  1095
sl@0
  1096
    result = TlsGetValue(tlsKey);
sl@0
  1097
    if ((result == NULL) && (GetLastError() != NO_ERROR)) {
sl@0
  1098
        panic("TlsGetValue failed from TclpGetAllocCache!");
sl@0
  1099
    }
sl@0
  1100
    return result;
sl@0
  1101
}
sl@0
  1102
sl@0
  1103
void
sl@0
  1104
TclpSetAllocCache(void *ptr)
sl@0
  1105
{
sl@0
  1106
    BOOL success;
sl@0
  1107
    success = TlsSetValue(tlsKey, ptr);
sl@0
  1108
    if (!success) {
sl@0
  1109
        panic("TlsSetValue failed from TclpSetAllocCache!");
sl@0
  1110
    }
sl@0
  1111
}
sl@0
  1112
sl@0
  1113
void
sl@0
  1114
TclpFreeAllocCache(void *ptr)
sl@0
  1115
{
sl@0
  1116
    BOOL success;
sl@0
  1117
sl@0
  1118
    if (ptr != NULL) {
sl@0
  1119
        /*
sl@0
  1120
         * Called by the pthread lib when a thread exits
sl@0
  1121
         */
sl@0
  1122
        TclFreeAllocCache(ptr);
sl@0
  1123
        success = TlsSetValue(tlsKey, NULL);
sl@0
  1124
        if (!success) {
sl@0
  1125
            panic("TlsSetValue failed from TclpFreeAllocCache!");
sl@0
  1126
        }
sl@0
  1127
    } else if (once) { 
sl@0
  1128
        /*
sl@0
  1129
         * Called by us in TclFinalizeThreadAlloc() during
sl@0
  1130
         * the library finalization initiated from Tcl_Finalize()
sl@0
  1131
         */
sl@0
  1132
        success = TlsFree(tlsKey);
sl@0
  1133
        if (!success) {
sl@0
  1134
            Tcl_Panic("TlsFree failed from TclpFreeAllocCache!");
sl@0
  1135
        }
sl@0
  1136
        once = 0; /* reset for next time. */
sl@0
  1137
    }
sl@0
  1138
}
sl@0
  1139
sl@0
  1140
#endif /* USE_THREAD_ALLOC */
sl@0
  1141
#endif /* TCL_THREADS */