os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacThrd.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* 
sl@0
     2
 * tclMacThrd.c --
sl@0
     3
 *
sl@0
     4
 *	This file implements the Mac-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-1998 Sun Microsystems, Inc.
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
 * SCCS:  @(#) tclMacThrd.c 1.2 98/02/23 16:48:07
sl@0
    13
 */
sl@0
    14
sl@0
    15
#include "tclInt.h"
sl@0
    16
#include "tclPort.h"
sl@0
    17
#include "tclMacInt.h"
sl@0
    18
#include <Threads.h>
sl@0
    19
#include <Gestalt.h>
sl@0
    20
sl@0
    21
#define TCL_MAC_THRD_DEFAULT_STACK (256*1024)
sl@0
    22
sl@0
    23
sl@0
    24
typedef struct TclMacThrdData {
sl@0
    25
    ThreadID threadID;
sl@0
    26
    VOID *data;
sl@0
    27
    struct TclMacThrdData *next;
sl@0
    28
} TclMacThrdData;
sl@0
    29
sl@0
    30
/*
sl@0
    31
 * This is an array of the Thread Data Keys.  It is a process-wide table.
sl@0
    32
 * Its size is originally set to 32, but it can grow if needed.
sl@0
    33
 */
sl@0
    34
 
sl@0
    35
static TclMacThrdData **tclMacDataKeyArray;
sl@0
    36
#define TCL_MAC_INITIAL_KEYSIZE 32
sl@0
    37
sl@0
    38
/*
sl@0
    39
 * These two bits of data store the current maximum number of keys
sl@0
    40
 * and the keyCounter (which is the number of occupied slots in the
sl@0
    41
 * KeyData array.
sl@0
    42
 * 
sl@0
    43
 */
sl@0
    44
 
sl@0
    45
static int maxNumKeys = 0;
sl@0
    46
static int keyCounter = 0;
sl@0
    47
sl@0
    48
/*
sl@0
    49
 * Prototypes for functions used only in this file
sl@0
    50
 */
sl@0
    51
 
sl@0
    52
TclMacThrdData *GetThreadDataStruct(Tcl_ThreadDataKey keyVal);
sl@0
    53
TclMacThrdData *RemoveThreadDataStruct(Tcl_ThreadDataKey keyVal);
sl@0
    54
sl@0
    55
/*
sl@0
    56
 * Note: The race evoked by the emulation layer for joinable threads
sl@0
    57
 * (see ../win/tclWinThrd.c) cannot occur on this platform due to
sl@0
    58
 * the cooperative implementation of multithreading.
sl@0
    59
 */
sl@0
    60

sl@0
    61
/*
sl@0
    62
 *----------------------------------------------------------------------
sl@0
    63
 *
sl@0
    64
 * TclMacHaveThreads --
sl@0
    65
 *
sl@0
    66
 *	Do we have the Thread Manager?
sl@0
    67
 *
sl@0
    68
 * Results:
sl@0
    69
 *	1 if the ThreadManager is present, 0 otherwise.
sl@0
    70
 *
sl@0
    71
 * Side effects:
sl@0
    72
 *	If this is the first time this is called, the return is cached.
sl@0
    73
 *
sl@0
    74
 *----------------------------------------------------------------------
sl@0
    75
 */
sl@0
    76
sl@0
    77
int
sl@0
    78
TclMacHaveThreads(void)
sl@0
    79
{
sl@0
    80
    static initialized = false;
sl@0
    81
    static int tclMacHaveThreads = false;
sl@0
    82
    long response = 0;
sl@0
    83
    OSErr err = noErr;
sl@0
    84
    
sl@0
    85
    if (!initialized) {
sl@0
    86
	err = Gestalt(gestaltThreadMgrAttr, &response);
sl@0
    87
	if (err == noErr) {
sl@0
    88
	    tclMacHaveThreads = response | (1 << gestaltThreadMgrPresent);
sl@0
    89
	}
sl@0
    90
    }
sl@0
    91
sl@0
    92
    return tclMacHaveThreads;
sl@0
    93
}
sl@0
    94

sl@0
    95
/*
sl@0
    96
 *----------------------------------------------------------------------
sl@0
    97
 *
sl@0
    98
 * Tcl_CreateThread --
sl@0
    99
 *
sl@0
   100
 *	This procedure creates a new thread.
sl@0
   101
 *
sl@0
   102
 * Results:
sl@0
   103
 *	TCL_OK if the thread could be created.  The thread ID is
sl@0
   104
 *	returned in a parameter.
sl@0
   105
 *
sl@0
   106
 * Side effects:
sl@0
   107
 *	A new thread is created.
sl@0
   108
 *
sl@0
   109
 *----------------------------------------------------------------------
sl@0
   110
 */
sl@0
   111
sl@0
   112
int
sl@0
   113
Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
sl@0
   114
    Tcl_ThreadId *idPtr;		/* Return, the ID of the thread */
sl@0
   115
    Tcl_ThreadCreateProc proc;		/* Main() function of the thread */
sl@0
   116
    ClientData clientData;		/* The one argument to Main() */
sl@0
   117
    int stackSize;			/* Size of stack for the new thread */
sl@0
   118
    int flags;				/* Flags controlling behaviour of
sl@0
   119
					 * the new thread */
sl@0
   120
{
sl@0
   121
    if (!TclMacHaveThreads()) {
sl@0
   122
        return TCL_ERROR;
sl@0
   123
    }
sl@0
   124
sl@0
   125
    if (stackSize == TCL_THREAD_STACK_DEFAULT) {
sl@0
   126
        stackSize = TCL_MAC_THRD_DEFAULT_STACK;
sl@0
   127
    }
sl@0
   128
sl@0
   129
#if TARGET_CPU_68K && TARGET_RT_MAC_CFM
sl@0
   130
    {
sl@0
   131
        ThreadEntryProcPtr entryProc;
sl@0
   132
        entryProc = NewThreadEntryUPP(proc);
sl@0
   133
        
sl@0
   134
        NewThread(kCooperativeThread, entryProc, (void *) clientData, 
sl@0
   135
            stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
sl@0
   136
    }
sl@0
   137
#else
sl@0
   138
    NewThread(kCooperativeThread, proc, (void *) clientData, 
sl@0
   139
        stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
sl@0
   140
#endif        
sl@0
   141
    if ((ThreadID) *idPtr == kNoThreadID) {
sl@0
   142
        return TCL_ERROR;
sl@0
   143
    } else {
sl@0
   144
        if (flags & TCL_THREAD_JOINABLE) {
sl@0
   145
	    TclRememberJoinableThread (*idPtr);
sl@0
   146
	}
sl@0
   147
sl@0
   148
        return TCL_OK;
sl@0
   149
    }
sl@0
   150
sl@0
   151
}
sl@0
   152

sl@0
   153
/*
sl@0
   154
 *----------------------------------------------------------------------
sl@0
   155
 *
sl@0
   156
 * Tcl_JoinThread --
sl@0
   157
 *
sl@0
   158
 *	This procedure waits upon the exit of the specified thread.
sl@0
   159
 *
sl@0
   160
 * Results:
sl@0
   161
 *	TCL_OK if the wait was successful, TCL_ERROR else.
sl@0
   162
 *
sl@0
   163
 * Side effects:
sl@0
   164
 *	The result area is set to the exit code of the thread we
sl@0
   165
 *	waited upon.
sl@0
   166
 *
sl@0
   167
 *----------------------------------------------------------------------
sl@0
   168
 */
sl@0
   169
sl@0
   170
int
sl@0
   171
Tcl_JoinThread(threadId, result)
sl@0
   172
    Tcl_ThreadId threadId; /* Id of the thread to wait upon */
sl@0
   173
    int*     result;	   /* Reference to the storage the result
sl@0
   174
			    * of the thread we wait upon will be
sl@0
   175
			    * written into. */
sl@0
   176
{
sl@0
   177
    if (!TclMacHaveThreads()) {
sl@0
   178
        return TCL_ERROR;
sl@0
   179
    }
sl@0
   180
sl@0
   181
    return TclJoinThread (threadId, result);
sl@0
   182
}
sl@0
   183

sl@0
   184
/*
sl@0
   185
 *----------------------------------------------------------------------
sl@0
   186
 *
sl@0
   187
 * TclpThreadExit --
sl@0
   188
 *
sl@0
   189
 *	This procedure terminates the current thread.
sl@0
   190
 *
sl@0
   191
 * Results:
sl@0
   192
 *	None.
sl@0
   193
 *
sl@0
   194
 * Side effects:
sl@0
   195
 *	This procedure terminates the current thread.
sl@0
   196
 *
sl@0
   197
 *----------------------------------------------------------------------
sl@0
   198
 */
sl@0
   199
sl@0
   200
void
sl@0
   201
TclpThreadExit(status)
sl@0
   202
    int status;
sl@0
   203
{
sl@0
   204
    ThreadID curThread;
sl@0
   205
    
sl@0
   206
    if (!TclMacHaveThreads()) {
sl@0
   207
        return;
sl@0
   208
    }
sl@0
   209
    
sl@0
   210
    GetCurrentThread(&curThread);
sl@0
   211
    TclSignalExitThread ((Tcl_ThreadId) curThread, status);
sl@0
   212
sl@0
   213
    DisposeThread(curThread, NULL, false);
sl@0
   214
}
sl@0
   215
sl@0
   216

sl@0
   217
/*
sl@0
   218
 *----------------------------------------------------------------------
sl@0
   219
 *
sl@0
   220
 * Tcl_GetCurrentThread --
sl@0
   221
 *
sl@0
   222
 *	This procedure returns the ID of the currently running thread.
sl@0
   223
 *
sl@0
   224
 * Results:
sl@0
   225
 *	A thread ID.
sl@0
   226
 *
sl@0
   227
 * Side effects:
sl@0
   228
 *	None.
sl@0
   229
 *
sl@0
   230
 *----------------------------------------------------------------------
sl@0
   231
 */
sl@0
   232
sl@0
   233
Tcl_ThreadId
sl@0
   234
Tcl_GetCurrentThread()
sl@0
   235
{
sl@0
   236
#ifdef TCL_THREADS
sl@0
   237
    ThreadID curThread;
sl@0
   238
sl@0
   239
    if (!TclMacHaveThreads()) {
sl@0
   240
        return (Tcl_ThreadId) 0;
sl@0
   241
    } else {
sl@0
   242
        GetCurrentThread(&curThread);
sl@0
   243
        return (Tcl_ThreadId) curThread;
sl@0
   244
    }
sl@0
   245
#else
sl@0
   246
    return (Tcl_ThreadId) 0;
sl@0
   247
#endif
sl@0
   248
}
sl@0
   249
sl@0
   250

sl@0
   251
/*
sl@0
   252
 *----------------------------------------------------------------------
sl@0
   253
 *
sl@0
   254
 * TclpInitLock
sl@0
   255
 *
sl@0
   256
 *	This procedure is used to grab a lock that serializes initialization
sl@0
   257
 *	and finalization of Tcl.  On some platforms this may also initialize
sl@0
   258
 *	the mutex used to serialize creation of more mutexes and thread
sl@0
   259
 *	local storage keys.
sl@0
   260
 *
sl@0
   261
 * Results:
sl@0
   262
 *	None.
sl@0
   263
 *
sl@0
   264
 * Side effects:
sl@0
   265
 *	Acquire the initialization mutex.
sl@0
   266
 *
sl@0
   267
 *----------------------------------------------------------------------
sl@0
   268
 */
sl@0
   269
sl@0
   270
void
sl@0
   271
TclpInitLock()
sl@0
   272
{
sl@0
   273
#ifdef TCL_THREADS
sl@0
   274
    /* There is nothing to do on the Mac. */;
sl@0
   275
#endif
sl@0
   276
}
sl@0
   277
sl@0
   278

sl@0
   279
/*
sl@0
   280
 *----------------------------------------------------------------------
sl@0
   281
 *
sl@0
   282
 * TclpInitUnlock
sl@0
   283
 *
sl@0
   284
 *	This procedure is used to release a lock that serializes initialization
sl@0
   285
 *	and finalization of Tcl.
sl@0
   286
 *
sl@0
   287
 * Results:
sl@0
   288
 *	None.
sl@0
   289
 *
sl@0
   290
 * Side effects:
sl@0
   291
 *	Release the initialization mutex.
sl@0
   292
 *
sl@0
   293
 *----------------------------------------------------------------------
sl@0
   294
 */
sl@0
   295
sl@0
   296
void
sl@0
   297
TclpInitUnlock()
sl@0
   298
{
sl@0
   299
#ifdef TCL_THREADS
sl@0
   300
    /* There is nothing to do on the Mac */;
sl@0
   301
#endif
sl@0
   302
}
sl@0
   303

sl@0
   304
/*
sl@0
   305
 *----------------------------------------------------------------------
sl@0
   306
 *
sl@0
   307
 * TclpMasterLock
sl@0
   308
 *
sl@0
   309
 *	This procedure is used to grab a lock that serializes creation
sl@0
   310
 *	and finalization of serialization objects.  This interface is
sl@0
   311
 *	only needed in finalization; it is hidden during
sl@0
   312
 *	creation of the objects.
sl@0
   313
 *
sl@0
   314
 *	This lock must be different than the initLock because the
sl@0
   315
 *	initLock is held during creation of syncronization objects.
sl@0
   316
 *
sl@0
   317
 * Results:
sl@0
   318
 *	None.
sl@0
   319
 *
sl@0
   320
 * Side effects:
sl@0
   321
 *	Acquire the master mutex.
sl@0
   322
 *
sl@0
   323
 *----------------------------------------------------------------------
sl@0
   324
 */
sl@0
   325
sl@0
   326
void
sl@0
   327
TclpMasterLock()
sl@0
   328
{
sl@0
   329
#ifdef TCL_THREADS
sl@0
   330
    /* There is nothing to do on the Mac */;
sl@0
   331
#endif
sl@0
   332
}
sl@0
   333
sl@0
   334

sl@0
   335
/*
sl@0
   336
 *----------------------------------------------------------------------
sl@0
   337
 *
sl@0
   338
 * TclpMasterUnlock
sl@0
   339
 *
sl@0
   340
 *	This procedure is used to release a lock that serializes creation
sl@0
   341
 *	and finalization of synchronization objects.
sl@0
   342
 *
sl@0
   343
 * Results:
sl@0
   344
 *	None.
sl@0
   345
 *
sl@0
   346
 * Side effects:
sl@0
   347
 *	Release the master mutex.
sl@0
   348
 *
sl@0
   349
 *----------------------------------------------------------------------
sl@0
   350
 */
sl@0
   351
sl@0
   352
void
sl@0
   353
TclpMasterUnlock()
sl@0
   354
{
sl@0
   355
#ifdef TCL_THREADS
sl@0
   356
    /* There is nothing to do on the Mac */
sl@0
   357
#endif
sl@0
   358
}
sl@0
   359
sl@0
   360

sl@0
   361
/*
sl@0
   362
 *----------------------------------------------------------------------
sl@0
   363
 *
sl@0
   364
 * Tcl_GetAllocMutex
sl@0
   365
 *
sl@0
   366
 *	This procedure returns a pointer to a statically initialized
sl@0
   367
 *	mutex for use by the memory allocator.  The alloctor must
sl@0
   368
 *	use this lock, because all other locks are allocated...
sl@0
   369
 *
sl@0
   370
 * Results:
sl@0
   371
 *	A pointer to a mutex that is suitable for passing to
sl@0
   372
 *	Tcl_MutexLock and Tcl_MutexUnlock.
sl@0
   373
 *
sl@0
   374
 * Side effects:
sl@0
   375
 *	None.
sl@0
   376
 *
sl@0
   377
 *----------------------------------------------------------------------
sl@0
   378
 */
sl@0
   379
sl@0
   380
Tcl_Mutex *
sl@0
   381
Tcl_GetAllocMutex()
sl@0
   382
{
sl@0
   383
    /* There is nothing to do on the Mac */
sl@0
   384
    return NULL;
sl@0
   385
}
sl@0
   386
sl@0
   387
#ifdef TCL_THREADS
sl@0
   388

sl@0
   389
/*
sl@0
   390
 *----------------------------------------------------------------------
sl@0
   391
 *
sl@0
   392
 * Tcl_MutexLock --
sl@0
   393
 *
sl@0
   394
 *	This procedure is invoked to lock a mutex.  This procedure
sl@0
   395
 *	handles initializing the mutex, if necessary.  The caller
sl@0
   396
 *	can rely on the fact that Tcl_Mutex is an opaque pointer.
sl@0
   397
 *	This routine will change that pointer from NULL after first use.
sl@0
   398
 *
sl@0
   399
 * Results:
sl@0
   400
 *	None.
sl@0
   401
 *
sl@0
   402
 * Side effects:
sl@0
   403
 *	May block the current thread.  The mutex is aquired when
sl@0
   404
 *	this returns.  Will allocate memory for a pthread_mutex_t
sl@0
   405
 *	and initialize this the first time this Tcl_Mutex is used.
sl@0
   406
 *
sl@0
   407
 *----------------------------------------------------------------------
sl@0
   408
 */
sl@0
   409
sl@0
   410
void
sl@0
   411
Tcl_MutexLock(mutexPtr)
sl@0
   412
    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */
sl@0
   413
{
sl@0
   414
/* There is nothing to do on the Mac */
sl@0
   415
}
sl@0
   416
sl@0
   417

sl@0
   418
/*
sl@0
   419
 *----------------------------------------------------------------------
sl@0
   420
 *
sl@0
   421
 * TclpMutexUnlock --
sl@0
   422
 *
sl@0
   423
 *	This procedure is invoked to unlock a mutex.  The mutex must
sl@0
   424
 *	have been locked by Tcl_MutexLock.
sl@0
   425
 *
sl@0
   426
 * Results:
sl@0
   427
 *	None.
sl@0
   428
 *
sl@0
   429
 * Side effects:
sl@0
   430
 *	The mutex is released when this returns.
sl@0
   431
 *
sl@0
   432
 *----------------------------------------------------------------------
sl@0
   433
 */
sl@0
   434
sl@0
   435
void
sl@0
   436
Tcl_MutexUnlock(mutexPtr)
sl@0
   437
    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */
sl@0
   438
{
sl@0
   439
/* There is nothing to do on the Mac */
sl@0
   440
}
sl@0
   441
sl@0
   442

sl@0
   443
/*
sl@0
   444
 *----------------------------------------------------------------------
sl@0
   445
 *
sl@0
   446
 * TclpFinalizeMutex --
sl@0
   447
 *
sl@0
   448
 *	This procedure is invoked to clean up one mutex.  This is only
sl@0
   449
 *	safe to call at the end of time.
sl@0
   450
 *
sl@0
   451
 *	This assumes the Master Lock is held.
sl@0
   452
 *
sl@0
   453
 * Results:
sl@0
   454
 *	None.
sl@0
   455
 *
sl@0
   456
 * Side effects:
sl@0
   457
 *	The mutex list is deallocated.
sl@0
   458
 *
sl@0
   459
 *----------------------------------------------------------------------
sl@0
   460
 */
sl@0
   461
sl@0
   462
void
sl@0
   463
TclpFinalizeMutex(mutexPtr)
sl@0
   464
    Tcl_Mutex *mutexPtr;
sl@0
   465
{
sl@0
   466
/* There is nothing to do on the Mac */
sl@0
   467
}
sl@0
   468
sl@0
   469

sl@0
   470
/*
sl@0
   471
 *----------------------------------------------------------------------
sl@0
   472
 *
sl@0
   473
 * TclpThreadDataKeyInit --
sl@0
   474
 *
sl@0
   475
 *	This procedure initializes a thread specific data block key.
sl@0
   476
 *	Each thread has table of pointers to thread specific data.
sl@0
   477
 *	all threads agree on which table entry is used by each module.
sl@0
   478
 *	this is remembered in a "data key", that is just an index into
sl@0
   479
 *	this table.  To allow self initialization, the interface
sl@0
   480
 *	passes a pointer to this key and the first thread to use
sl@0
   481
 *	the key fills in the pointer to the key.  The key should be
sl@0
   482
 *	a process-wide static.
sl@0
   483
 *
sl@0
   484
 *      There is no system-wide support for thread specific data on the 
sl@0
   485
 *	Mac.  So we implement this as an array of pointers.  The keys are
sl@0
   486
 *	allocated sequentially, and each key maps to a slot in the table.
sl@0
   487
 *      The table element points to a linked list of the instances of
sl@0
   488
 *	the data for each thread.
sl@0
   489
 *
sl@0
   490
 * Results:
sl@0
   491
 *	None.
sl@0
   492
 *
sl@0
   493
 * Side effects:
sl@0
   494
 *	Will bump the key counter if this is the first time this key
sl@0
   495
 *      has been initialized.  May grow the DataKeyArray if that is
sl@0
   496
 *	necessary.
sl@0
   497
 *
sl@0
   498
 *----------------------------------------------------------------------
sl@0
   499
 */
sl@0
   500
sl@0
   501
void
sl@0
   502
TclpThreadDataKeyInit(keyPtr)
sl@0
   503
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   504
				 * really (pthread_key_t **) */
sl@0
   505
{
sl@0
   506
            
sl@0
   507
    if (*keyPtr == NULL) {
sl@0
   508
        keyCounter += 1;
sl@0
   509
	*keyPtr = (Tcl_ThreadDataKey) keyCounter;
sl@0
   510
	if (keyCounter > maxNumKeys) {
sl@0
   511
	    TclMacThrdData **newArray;
sl@0
   512
	    int i, oldMax = maxNumKeys;
sl@0
   513
	     
sl@0
   514
	    maxNumKeys = maxNumKeys + TCL_MAC_INITIAL_KEYSIZE;
sl@0
   515
	     
sl@0
   516
	    newArray = (TclMacThrdData **) 
sl@0
   517
	            ckalloc(maxNumKeys * sizeof(TclMacThrdData *));
sl@0
   518
	     
sl@0
   519
	    for (i = 0; i < oldMax; i++) {
sl@0
   520
	        newArray[i] = tclMacDataKeyArray[i];
sl@0
   521
	    }
sl@0
   522
	    for (i = oldMax; i < maxNumKeys; i++) {
sl@0
   523
	        newArray[i] = NULL;
sl@0
   524
	    }
sl@0
   525
	     
sl@0
   526
	    if (tclMacDataKeyArray != NULL) {
sl@0
   527
		ckfree((char *) tclMacDataKeyArray);
sl@0
   528
	    }
sl@0
   529
	    tclMacDataKeyArray = newArray;
sl@0
   530
	     
sl@0
   531
	}             
sl@0
   532
	/* TclRememberDataKey(keyPtr); */
sl@0
   533
    }
sl@0
   534
}
sl@0
   535

sl@0
   536
/*
sl@0
   537
 *----------------------------------------------------------------------
sl@0
   538
 *
sl@0
   539
 * TclpThreadDataKeyGet --
sl@0
   540
 *
sl@0
   541
 *	This procedure returns a pointer to a block of thread local storage.
sl@0
   542
 *
sl@0
   543
 * Results:
sl@0
   544
 *	A thread-specific pointer to the data structure, or NULL
sl@0
   545
 *	if the memory has not been assigned to this key for this thread.
sl@0
   546
 *
sl@0
   547
 * Side effects:
sl@0
   548
 *	None.
sl@0
   549
 *
sl@0
   550
 *----------------------------------------------------------------------
sl@0
   551
 */
sl@0
   552
sl@0
   553
VOID *
sl@0
   554
TclpThreadDataKeyGet(keyPtr)
sl@0
   555
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   556
				 * really (pthread_key_t **) */
sl@0
   557
{
sl@0
   558
    TclMacThrdData *dataPtr;
sl@0
   559
    
sl@0
   560
    dataPtr = GetThreadDataStruct(*keyPtr);
sl@0
   561
    
sl@0
   562
    if (dataPtr == NULL) {
sl@0
   563
        return NULL;
sl@0
   564
    } else {
sl@0
   565
        return dataPtr->data;
sl@0
   566
    }
sl@0
   567
}
sl@0
   568
sl@0
   569

sl@0
   570
/*
sl@0
   571
 *----------------------------------------------------------------------
sl@0
   572
 *
sl@0
   573
 * TclpThreadDataKeySet --
sl@0
   574
 *
sl@0
   575
 *	This procedure sets the pointer to a block of thread local storage.
sl@0
   576
 *
sl@0
   577
 * Results:
sl@0
   578
 *	None.
sl@0
   579
 *
sl@0
   580
 * Side effects:
sl@0
   581
 *	Sets up the thread so future calls to TclpThreadDataKeyGet with
sl@0
   582
 *	this key will return the data pointer.
sl@0
   583
 *
sl@0
   584
 *----------------------------------------------------------------------
sl@0
   585
 */
sl@0
   586
sl@0
   587
void
sl@0
   588
TclpThreadDataKeySet(keyPtr, data)
sl@0
   589
    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk,
sl@0
   590
				 * really (pthread_key_t **) */
sl@0
   591
    VOID *data;			/* Thread local storage */
sl@0
   592
{
sl@0
   593
    TclMacThrdData *dataPtr;
sl@0
   594
    ThreadID curThread;
sl@0
   595
    
sl@0
   596
    dataPtr = GetThreadDataStruct(*keyPtr);
sl@0
   597
    
sl@0
   598
    /* 
sl@0
   599
     * Is it legal to reset the thread data like this?
sl@0
   600
     * And if so, who owns the memory?
sl@0
   601
     */
sl@0
   602
     
sl@0
   603
    if (dataPtr != NULL) {
sl@0
   604
        dataPtr->data = data;
sl@0
   605
    } else {
sl@0
   606
        dataPtr = (TclMacThrdData *) ckalloc(sizeof(TclMacThrdData));
sl@0
   607
        GetCurrentThread(&curThread);
sl@0
   608
        dataPtr->threadID = curThread;
sl@0
   609
        dataPtr->data = data;
sl@0
   610
        dataPtr->next = tclMacDataKeyArray[(int) *keyPtr - 1];
sl@0
   611
        tclMacDataKeyArray[(int) *keyPtr - 1] = dataPtr;
sl@0
   612
   }
sl@0
   613
}
sl@0
   614

sl@0
   615
/*
sl@0
   616
 *----------------------------------------------------------------------
sl@0
   617
 *
sl@0
   618
 * TclpFinalizeThreadData --
sl@0
   619
 *
sl@0
   620
 *	This procedure cleans up the thread-local storage.  This is
sl@0
   621
 *	called once for each thread.
sl@0
   622
 *
sl@0
   623
 * Results:
sl@0
   624
 *	None.
sl@0
   625
 *
sl@0
   626
 * Side effects:
sl@0
   627
 *	Frees up all thread local storage.
sl@0
   628
 *
sl@0
   629
 *----------------------------------------------------------------------
sl@0
   630
 */
sl@0
   631
sl@0
   632
void
sl@0
   633
TclpFinalizeThreadData(keyPtr)
sl@0
   634
    Tcl_ThreadDataKey *keyPtr;
sl@0
   635
{
sl@0
   636
    TclMacThrdData *dataPtr;
sl@0
   637
    
sl@0
   638
    if (*keyPtr != NULL) {
sl@0
   639
        dataPtr = RemoveThreadDataStruct(*keyPtr);
sl@0
   640
        
sl@0
   641
	if ((dataPtr != NULL) && (dataPtr->data != NULL)) {
sl@0
   642
	    ckfree((char *) dataPtr->data);
sl@0
   643
	    ckfree((char *) dataPtr);
sl@0
   644
	}
sl@0
   645
    }
sl@0
   646
}
sl@0
   647

sl@0
   648
/*
sl@0
   649
 *----------------------------------------------------------------------
sl@0
   650
 *
sl@0
   651
 * TclpFinalizeThreadDataKey --
sl@0
   652
 *
sl@0
   653
 *	This procedure is invoked to clean up one key.  This is a
sl@0
   654
 *	process-wide storage identifier.  The thread finalization code
sl@0
   655
 *	cleans up the thread local storage itself.
sl@0
   656
 *
sl@0
   657
 *      On the Mac, there is really nothing to do here, since the key
sl@0
   658
 *      is just an array index.  But we set the key to 0 just in case
sl@0
   659
 *	someone else is relying on that.
sl@0
   660
 *
sl@0
   661
 * Results:
sl@0
   662
 *	None.
sl@0
   663
 *
sl@0
   664
 * Side effects:
sl@0
   665
 *	The keyPtr value is set to 0.
sl@0
   666
 *
sl@0
   667
 *----------------------------------------------------------------------
sl@0
   668
 */
sl@0
   669
sl@0
   670
void
sl@0
   671
TclpFinalizeThreadDataKey(keyPtr)
sl@0
   672
    Tcl_ThreadDataKey *keyPtr;
sl@0
   673
{
sl@0
   674
    ckfree((char *) tclMacDataKeyArray[(int) *keyPtr - 1]);
sl@0
   675
    tclMacDataKeyArray[(int) *keyPtr - 1] = NULL;
sl@0
   676
    *keyPtr = NULL;
sl@0
   677
}
sl@0
   678
sl@0
   679

sl@0
   680
/*
sl@0
   681
 *----------------------------------------------------------------------
sl@0
   682
 *
sl@0
   683
 * GetThreadDataStruct --
sl@0
   684
 *
sl@0
   685
 *	This procedure gets the data structure corresponding to
sl@0
   686
 *      keyVal for the current process.
sl@0
   687
 *
sl@0
   688
 * Results:
sl@0
   689
 *	The requested key data.
sl@0
   690
 *
sl@0
   691
 * Side effects:
sl@0
   692
 *	None.
sl@0
   693
 *
sl@0
   694
 *----------------------------------------------------------------------
sl@0
   695
 */
sl@0
   696
sl@0
   697
TclMacThrdData *
sl@0
   698
GetThreadDataStruct(keyVal)
sl@0
   699
    Tcl_ThreadDataKey keyVal;
sl@0
   700
{
sl@0
   701
    ThreadID curThread;
sl@0
   702
    TclMacThrdData *dataPtr;
sl@0
   703
    
sl@0
   704
    /*
sl@0
   705
     * The keyPtr will only be greater than keyCounter is someone
sl@0
   706
     * has passed us a key without getting the value from 
sl@0
   707
     * TclpInitDataKey.
sl@0
   708
     */
sl@0
   709
     
sl@0
   710
    if ((int) keyVal <= 0)  {
sl@0
   711
        return NULL;
sl@0
   712
    } else if ((int) keyVal > keyCounter) {
sl@0
   713
        panic("illegal data key value");
sl@0
   714
    }
sl@0
   715
    
sl@0
   716
    GetCurrentThread(&curThread);
sl@0
   717
    
sl@0
   718
    for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1]; dataPtr != NULL;
sl@0
   719
            dataPtr = dataPtr->next) {
sl@0
   720
        if (dataPtr->threadID ==  curThread) {
sl@0
   721
            break;
sl@0
   722
        }
sl@0
   723
    }
sl@0
   724
    
sl@0
   725
    return dataPtr;
sl@0
   726
}
sl@0
   727
sl@0
   728

sl@0
   729
/*
sl@0
   730
 *----------------------------------------------------------------------
sl@0
   731
 *
sl@0
   732
 * RemoveThreadDataStruct --
sl@0
   733
 *
sl@0
   734
 *	This procedure removes the data structure corresponding to
sl@0
   735
 *      keyVal for the current process from the list kept for keyVal.
sl@0
   736
 *
sl@0
   737
 * Results:
sl@0
   738
 *	The requested key data is removed from the list, and a pointer 
sl@0
   739
 *      to it is returned.
sl@0
   740
 *
sl@0
   741
 * Side effects:
sl@0
   742
 *	None.
sl@0
   743
 *
sl@0
   744
 *----------------------------------------------------------------------
sl@0
   745
 */
sl@0
   746
sl@0
   747
TclMacThrdData *
sl@0
   748
RemoveThreadDataStruct(keyVal)
sl@0
   749
    Tcl_ThreadDataKey keyVal;
sl@0
   750
{
sl@0
   751
    ThreadID curThread;
sl@0
   752
    TclMacThrdData *dataPtr, *prevPtr;
sl@0
   753
    
sl@0
   754
     
sl@0
   755
    if ((int) keyVal <= 0)  {
sl@0
   756
        return NULL;
sl@0
   757
    } else if ((int) keyVal > keyCounter) {
sl@0
   758
        panic("illegal data key value");
sl@0
   759
    }
sl@0
   760
    
sl@0
   761
    GetCurrentThread(&curThread);
sl@0
   762
    
sl@0
   763
    for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1], prevPtr = NULL; 
sl@0
   764
            dataPtr != NULL;
sl@0
   765
            prevPtr = dataPtr, dataPtr = dataPtr->next) {
sl@0
   766
        if (dataPtr->threadID == curThread) {
sl@0
   767
            break;
sl@0
   768
        }
sl@0
   769
    }
sl@0
   770
    
sl@0
   771
    if (dataPtr == NULL) {
sl@0
   772
        /* No body */
sl@0
   773
    } else if ( prevPtr == NULL) {
sl@0
   774
        tclMacDataKeyArray[(int) keyVal - 1] = dataPtr->next;
sl@0
   775
    } else {
sl@0
   776
        prevPtr->next = dataPtr->next;
sl@0
   777
    }
sl@0
   778
    
sl@0
   779
    return dataPtr; 
sl@0
   780
}
sl@0
   781

sl@0
   782
/*
sl@0
   783
 *----------------------------------------------------------------------
sl@0
   784
 *
sl@0
   785
 * Tcl_ConditionWait --
sl@0
   786
 *
sl@0
   787
 *	This procedure is invoked to wait on a condition variable.
sl@0
   788
 *	On the Mac, mutexes are no-ops, and we just yield.  After
sl@0
   789
 *	all, it is the application's job to loop till the condition 
sl@0
   790
 *	variable is changed...
sl@0
   791
 *
sl@0
   792
 *
sl@0
   793
 * Results:
sl@0
   794
 *	None.
sl@0
   795
 *
sl@0
   796
 * Side effects:
sl@0
   797
 *	Will block the current thread till someone else yields.
sl@0
   798
 *
sl@0
   799
 *----------------------------------------------------------------------
sl@0
   800
 */
sl@0
   801
sl@0
   802
void
sl@0
   803
Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
sl@0
   804
    Tcl_Condition *condPtr;	/* Really (pthread_cond_t **) */
sl@0
   805
    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */
sl@0
   806
    Tcl_Time *timePtr;		/* Timeout on waiting period */
sl@0
   807
{
sl@0
   808
    if (TclMacHaveThreads()) {
sl@0
   809
        YieldToAnyThread();
sl@0
   810
    }
sl@0
   811
}
sl@0
   812

sl@0
   813
/*
sl@0
   814
 *----------------------------------------------------------------------
sl@0
   815
 *
sl@0
   816
 * Tcl_ConditionNotify --
sl@0
   817
 *
sl@0
   818
 *	This procedure is invoked to signal a condition variable.
sl@0
   819
 *
sl@0
   820
 *	The mutex must be held during this call to avoid races,
sl@0
   821
 *	but this interface does not enforce that.
sl@0
   822
 *
sl@0
   823
 * Results:
sl@0
   824
 *	None.
sl@0
   825
 *
sl@0
   826
 * Side effects:
sl@0
   827
 *	May unblock another thread.
sl@0
   828
 *
sl@0
   829
 *----------------------------------------------------------------------
sl@0
   830
 */
sl@0
   831
sl@0
   832
void
sl@0
   833
Tcl_ConditionNotify(condPtr)
sl@0
   834
    Tcl_Condition *condPtr;
sl@0
   835
{
sl@0
   836
    if (TclMacHaveThreads()) {
sl@0
   837
         YieldToAnyThread();
sl@0
   838
    }
sl@0
   839
}
sl@0
   840
sl@0
   841

sl@0
   842
/*
sl@0
   843
 *----------------------------------------------------------------------
sl@0
   844
 *
sl@0
   845
 * TclpFinalizeCondition --
sl@0
   846
 *
sl@0
   847
 *	This procedure is invoked to clean up a condition variable.
sl@0
   848
 *	This is only safe to call at the end of time.
sl@0
   849
 *
sl@0
   850
 *	This assumes the Master Lock is held.
sl@0
   851
 *
sl@0
   852
 * Results:
sl@0
   853
 *	None.
sl@0
   854
 *
sl@0
   855
 * Side effects:
sl@0
   856
 *	The condition variable is deallocated.
sl@0
   857
 *
sl@0
   858
 *----------------------------------------------------------------------
sl@0
   859
 */
sl@0
   860
sl@0
   861
void
sl@0
   862
TclpFinalizeCondition(condPtr)
sl@0
   863
    Tcl_Condition *condPtr;
sl@0
   864
{
sl@0
   865
    /* Nothing to do on the Mac */
sl@0
   866
}
sl@0
   867
sl@0
   868
sl@0
   869
sl@0
   870
#endif /* TCL_THREADS */
sl@0
   871