os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacThrd.c
Update contrib.
4 * This file implements the Mac-specific thread support.
6 * Copyright (c) 1991-1994 The Regents of the University of California.
7 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * SCCS: @(#) tclMacThrd.c 1.2 98/02/23 16:48:07
17 #include "tclMacInt.h"
21 #define TCL_MAC_THRD_DEFAULT_STACK (256*1024)
24 typedef struct TclMacThrdData {
27 struct TclMacThrdData *next;
31 * This is an array of the Thread Data Keys. It is a process-wide table.
32 * Its size is originally set to 32, but it can grow if needed.
35 static TclMacThrdData **tclMacDataKeyArray;
36 #define TCL_MAC_INITIAL_KEYSIZE 32
39 * These two bits of data store the current maximum number of keys
40 * and the keyCounter (which is the number of occupied slots in the
45 static int maxNumKeys = 0;
46 static int keyCounter = 0;
49 * Prototypes for functions used only in this file
52 TclMacThrdData *GetThreadDataStruct(Tcl_ThreadDataKey keyVal);
53 TclMacThrdData *RemoveThreadDataStruct(Tcl_ThreadDataKey keyVal);
56 * Note: The race evoked by the emulation layer for joinable threads
57 * (see ../win/tclWinThrd.c) cannot occur on this platform due to
58 * the cooperative implementation of multithreading.
62 *----------------------------------------------------------------------
64 * TclMacHaveThreads --
66 * Do we have the Thread Manager?
69 * 1 if the ThreadManager is present, 0 otherwise.
72 * If this is the first time this is called, the return is cached.
74 *----------------------------------------------------------------------
78 TclMacHaveThreads(void)
80 static initialized = false;
81 static int tclMacHaveThreads = false;
86 err = Gestalt(gestaltThreadMgrAttr, &response);
88 tclMacHaveThreads = response | (1 << gestaltThreadMgrPresent);
92 return tclMacHaveThreads;
96 *----------------------------------------------------------------------
100 * This procedure creates a new thread.
103 * TCL_OK if the thread could be created. The thread ID is
104 * returned in a parameter.
107 * A new thread is created.
109 *----------------------------------------------------------------------
113 Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
114 Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
115 Tcl_ThreadCreateProc proc; /* Main() function of the thread */
116 ClientData clientData; /* The one argument to Main() */
117 int stackSize; /* Size of stack for the new thread */
118 int flags; /* Flags controlling behaviour of
121 if (!TclMacHaveThreads()) {
125 if (stackSize == TCL_THREAD_STACK_DEFAULT) {
126 stackSize = TCL_MAC_THRD_DEFAULT_STACK;
129 #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
131 ThreadEntryProcPtr entryProc;
132 entryProc = NewThreadEntryUPP(proc);
134 NewThread(kCooperativeThread, entryProc, (void *) clientData,
135 stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
138 NewThread(kCooperativeThread, proc, (void *) clientData,
139 stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
141 if ((ThreadID) *idPtr == kNoThreadID) {
144 if (flags & TCL_THREAD_JOINABLE) {
145 TclRememberJoinableThread (*idPtr);
154 *----------------------------------------------------------------------
158 * This procedure waits upon the exit of the specified thread.
161 * TCL_OK if the wait was successful, TCL_ERROR else.
164 * The result area is set to the exit code of the thread we
167 *----------------------------------------------------------------------
171 Tcl_JoinThread(threadId, result)
172 Tcl_ThreadId threadId; /* Id of the thread to wait upon */
173 int* result; /* Reference to the storage the result
174 * of the thread we wait upon will be
177 if (!TclMacHaveThreads()) {
181 return TclJoinThread (threadId, result);
185 *----------------------------------------------------------------------
189 * This procedure terminates the current thread.
195 * This procedure terminates the current thread.
197 *----------------------------------------------------------------------
201 TclpThreadExit(status)
206 if (!TclMacHaveThreads()) {
210 GetCurrentThread(&curThread);
211 TclSignalExitThread ((Tcl_ThreadId) curThread, status);
213 DisposeThread(curThread, NULL, false);
218 *----------------------------------------------------------------------
220 * Tcl_GetCurrentThread --
222 * This procedure returns the ID of the currently running thread.
230 *----------------------------------------------------------------------
234 Tcl_GetCurrentThread()
239 if (!TclMacHaveThreads()) {
240 return (Tcl_ThreadId) 0;
242 GetCurrentThread(&curThread);
243 return (Tcl_ThreadId) curThread;
246 return (Tcl_ThreadId) 0;
252 *----------------------------------------------------------------------
256 * This procedure is used to grab a lock that serializes initialization
257 * and finalization of Tcl. On some platforms this may also initialize
258 * the mutex used to serialize creation of more mutexes and thread
259 * local storage keys.
265 * Acquire the initialization mutex.
267 *----------------------------------------------------------------------
274 /* There is nothing to do on the Mac. */;
280 *----------------------------------------------------------------------
284 * This procedure is used to release a lock that serializes initialization
285 * and finalization of Tcl.
291 * Release the initialization mutex.
293 *----------------------------------------------------------------------
300 /* There is nothing to do on the Mac */;
305 *----------------------------------------------------------------------
309 * This procedure is used to grab a lock that serializes creation
310 * and finalization of serialization objects. This interface is
311 * only needed in finalization; it is hidden during
312 * creation of the objects.
314 * This lock must be different than the initLock because the
315 * initLock is held during creation of syncronization objects.
321 * Acquire the master mutex.
323 *----------------------------------------------------------------------
330 /* There is nothing to do on the Mac */;
336 *----------------------------------------------------------------------
340 * This procedure is used to release a lock that serializes creation
341 * and finalization of synchronization objects.
347 * Release the master mutex.
349 *----------------------------------------------------------------------
356 /* There is nothing to do on the Mac */
362 *----------------------------------------------------------------------
366 * This procedure returns a pointer to a statically initialized
367 * mutex for use by the memory allocator. The alloctor must
368 * use this lock, because all other locks are allocated...
371 * A pointer to a mutex that is suitable for passing to
372 * Tcl_MutexLock and Tcl_MutexUnlock.
377 *----------------------------------------------------------------------
383 /* There is nothing to do on the Mac */
390 *----------------------------------------------------------------------
394 * This procedure is invoked to lock a mutex. This procedure
395 * handles initializing the mutex, if necessary. The caller
396 * can rely on the fact that Tcl_Mutex is an opaque pointer.
397 * This routine will change that pointer from NULL after first use.
403 * May block the current thread. The mutex is aquired when
404 * this returns. Will allocate memory for a pthread_mutex_t
405 * and initialize this the first time this Tcl_Mutex is used.
407 *----------------------------------------------------------------------
411 Tcl_MutexLock(mutexPtr)
412 Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
414 /* There is nothing to do on the Mac */
419 *----------------------------------------------------------------------
423 * This procedure is invoked to unlock a mutex. The mutex must
424 * have been locked by Tcl_MutexLock.
430 * The mutex is released when this returns.
432 *----------------------------------------------------------------------
436 Tcl_MutexUnlock(mutexPtr)
437 Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
439 /* There is nothing to do on the Mac */
444 *----------------------------------------------------------------------
446 * TclpFinalizeMutex --
448 * This procedure is invoked to clean up one mutex. This is only
449 * safe to call at the end of time.
451 * This assumes the Master Lock is held.
457 * The mutex list is deallocated.
459 *----------------------------------------------------------------------
463 TclpFinalizeMutex(mutexPtr)
466 /* There is nothing to do on the Mac */
471 *----------------------------------------------------------------------
473 * TclpThreadDataKeyInit --
475 * This procedure initializes a thread specific data block key.
476 * Each thread has table of pointers to thread specific data.
477 * all threads agree on which table entry is used by each module.
478 * this is remembered in a "data key", that is just an index into
479 * this table. To allow self initialization, the interface
480 * passes a pointer to this key and the first thread to use
481 * the key fills in the pointer to the key. The key should be
482 * a process-wide static.
484 * There is no system-wide support for thread specific data on the
485 * Mac. So we implement this as an array of pointers. The keys are
486 * allocated sequentially, and each key maps to a slot in the table.
487 * The table element points to a linked list of the instances of
488 * the data for each thread.
494 * Will bump the key counter if this is the first time this key
495 * has been initialized. May grow the DataKeyArray if that is
498 *----------------------------------------------------------------------
502 TclpThreadDataKeyInit(keyPtr)
503 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
504 * really (pthread_key_t **) */
507 if (*keyPtr == NULL) {
509 *keyPtr = (Tcl_ThreadDataKey) keyCounter;
510 if (keyCounter > maxNumKeys) {
511 TclMacThrdData **newArray;
512 int i, oldMax = maxNumKeys;
514 maxNumKeys = maxNumKeys + TCL_MAC_INITIAL_KEYSIZE;
516 newArray = (TclMacThrdData **)
517 ckalloc(maxNumKeys * sizeof(TclMacThrdData *));
519 for (i = 0; i < oldMax; i++) {
520 newArray[i] = tclMacDataKeyArray[i];
522 for (i = oldMax; i < maxNumKeys; i++) {
526 if (tclMacDataKeyArray != NULL) {
527 ckfree((char *) tclMacDataKeyArray);
529 tclMacDataKeyArray = newArray;
532 /* TclRememberDataKey(keyPtr); */
537 *----------------------------------------------------------------------
539 * TclpThreadDataKeyGet --
541 * This procedure returns a pointer to a block of thread local storage.
544 * A thread-specific pointer to the data structure, or NULL
545 * if the memory has not been assigned to this key for this thread.
550 *----------------------------------------------------------------------
554 TclpThreadDataKeyGet(keyPtr)
555 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
556 * really (pthread_key_t **) */
558 TclMacThrdData *dataPtr;
560 dataPtr = GetThreadDataStruct(*keyPtr);
562 if (dataPtr == NULL) {
565 return dataPtr->data;
571 *----------------------------------------------------------------------
573 * TclpThreadDataKeySet --
575 * This procedure sets the pointer to a block of thread local storage.
581 * Sets up the thread so future calls to TclpThreadDataKeyGet with
582 * this key will return the data pointer.
584 *----------------------------------------------------------------------
588 TclpThreadDataKeySet(keyPtr, data)
589 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
590 * really (pthread_key_t **) */
591 VOID *data; /* Thread local storage */
593 TclMacThrdData *dataPtr;
596 dataPtr = GetThreadDataStruct(*keyPtr);
599 * Is it legal to reset the thread data like this?
600 * And if so, who owns the memory?
603 if (dataPtr != NULL) {
604 dataPtr->data = data;
606 dataPtr = (TclMacThrdData *) ckalloc(sizeof(TclMacThrdData));
607 GetCurrentThread(&curThread);
608 dataPtr->threadID = curThread;
609 dataPtr->data = data;
610 dataPtr->next = tclMacDataKeyArray[(int) *keyPtr - 1];
611 tclMacDataKeyArray[(int) *keyPtr - 1] = dataPtr;
616 *----------------------------------------------------------------------
618 * TclpFinalizeThreadData --
620 * This procedure cleans up the thread-local storage. This is
621 * called once for each thread.
627 * Frees up all thread local storage.
629 *----------------------------------------------------------------------
633 TclpFinalizeThreadData(keyPtr)
634 Tcl_ThreadDataKey *keyPtr;
636 TclMacThrdData *dataPtr;
638 if (*keyPtr != NULL) {
639 dataPtr = RemoveThreadDataStruct(*keyPtr);
641 if ((dataPtr != NULL) && (dataPtr->data != NULL)) {
642 ckfree((char *) dataPtr->data);
643 ckfree((char *) dataPtr);
649 *----------------------------------------------------------------------
651 * TclpFinalizeThreadDataKey --
653 * This procedure is invoked to clean up one key. This is a
654 * process-wide storage identifier. The thread finalization code
655 * cleans up the thread local storage itself.
657 * On the Mac, there is really nothing to do here, since the key
658 * is just an array index. But we set the key to 0 just in case
659 * someone else is relying on that.
665 * The keyPtr value is set to 0.
667 *----------------------------------------------------------------------
671 TclpFinalizeThreadDataKey(keyPtr)
672 Tcl_ThreadDataKey *keyPtr;
674 ckfree((char *) tclMacDataKeyArray[(int) *keyPtr - 1]);
675 tclMacDataKeyArray[(int) *keyPtr - 1] = NULL;
681 *----------------------------------------------------------------------
683 * GetThreadDataStruct --
685 * This procedure gets the data structure corresponding to
686 * keyVal for the current process.
689 * The requested key data.
694 *----------------------------------------------------------------------
698 GetThreadDataStruct(keyVal)
699 Tcl_ThreadDataKey keyVal;
702 TclMacThrdData *dataPtr;
705 * The keyPtr will only be greater than keyCounter is someone
706 * has passed us a key without getting the value from
710 if ((int) keyVal <= 0) {
712 } else if ((int) keyVal > keyCounter) {
713 panic("illegal data key value");
716 GetCurrentThread(&curThread);
718 for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1]; dataPtr != NULL;
719 dataPtr = dataPtr->next) {
720 if (dataPtr->threadID == curThread) {
730 *----------------------------------------------------------------------
732 * RemoveThreadDataStruct --
734 * This procedure removes the data structure corresponding to
735 * keyVal for the current process from the list kept for keyVal.
738 * The requested key data is removed from the list, and a pointer
744 *----------------------------------------------------------------------
748 RemoveThreadDataStruct(keyVal)
749 Tcl_ThreadDataKey keyVal;
752 TclMacThrdData *dataPtr, *prevPtr;
755 if ((int) keyVal <= 0) {
757 } else if ((int) keyVal > keyCounter) {
758 panic("illegal data key value");
761 GetCurrentThread(&curThread);
763 for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1], prevPtr = NULL;
765 prevPtr = dataPtr, dataPtr = dataPtr->next) {
766 if (dataPtr->threadID == curThread) {
771 if (dataPtr == NULL) {
773 } else if ( prevPtr == NULL) {
774 tclMacDataKeyArray[(int) keyVal - 1] = dataPtr->next;
776 prevPtr->next = dataPtr->next;
783 *----------------------------------------------------------------------
785 * Tcl_ConditionWait --
787 * This procedure is invoked to wait on a condition variable.
788 * On the Mac, mutexes are no-ops, and we just yield. After
789 * all, it is the application's job to loop till the condition
790 * variable is changed...
797 * Will block the current thread till someone else yields.
799 *----------------------------------------------------------------------
803 Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
804 Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
805 Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
806 Tcl_Time *timePtr; /* Timeout on waiting period */
808 if (TclMacHaveThreads()) {
814 *----------------------------------------------------------------------
816 * Tcl_ConditionNotify --
818 * This procedure is invoked to signal a condition variable.
820 * The mutex must be held during this call to avoid races,
821 * but this interface does not enforce that.
827 * May unblock another thread.
829 *----------------------------------------------------------------------
833 Tcl_ConditionNotify(condPtr)
834 Tcl_Condition *condPtr;
836 if (TclMacHaveThreads()) {
843 *----------------------------------------------------------------------
845 * TclpFinalizeCondition --
847 * This procedure is invoked to clean up a condition variable.
848 * This is only safe to call at the end of time.
850 * This assumes the Master Lock is held.
856 * The condition variable is deallocated.
858 *----------------------------------------------------------------------
862 TclpFinalizeCondition(condPtr)
863 Tcl_Condition *condPtr;
865 /* Nothing to do on the Mac */
870 #endif /* TCL_THREADS */