void TclpFreeAllocCache( void *ptr) { BOOL success; if (ptr != NULL) { /* * Called by us in TclpFinalizeThreadData when a thread exits and * destroys the tsd key which stores allocator caches. */ TclFreeAllocCache(ptr); success = TlsSetValue(tlsKey, NULL); if (!success) { Tcl_Panic("TlsSetValue failed from TclpFreeAllocCache"); } } else if (once) { /* * Called by us in TclFinalizeThreadAlloc() during the library * finalization initiated from Tcl_Finalize() */ success = TlsFree(tlsKey); if (!success) { Tcl_Panic("TlsFree failed from TclpFreeAllocCache"); } once = 0; /* reset for next time. */ } }
void TclVerifyGlobalLiteralTable( Interp *iPtr) /* Points to interpreter whose global literal * table is to be validated. */ { register LiteralTable *globalTablePtr = &(iPtr->literalTable); register LiteralEntry *globalPtr; char *bytes; register int i; int length, count; count = 0; for (i=0 ; i<globalTablePtr->numBuckets ; i++) { for (globalPtr=globalTablePtr->buckets[i] ; globalPtr!=NULL; globalPtr=globalPtr->nextPtr) { count++; if (globalPtr->refCount < 1) { bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length); Tcl_Panic("TclVerifyGlobalLiteralTable: global literal \"%.*s\" had bad refCount %d", (length>60? 60 : length), bytes, globalPtr->refCount); } if (globalPtr->objPtr->bytes == NULL) { Tcl_Panic("TclVerifyGlobalLiteralTable: literal has NULL string rep"); } } } if (count != globalTablePtr->numEntries) { Tcl_Panic("TclVerifyGlobalLiteralTable: global literal table had %d entries, should be %d", count, globalTablePtr->numEntries); } }
void TclpFreeAllocCache( void *ptr) { BOOL success; if (ptr != NULL) { /* * Called by TclFinalizeThreadAlloc() and * TclFinalizeThreadAllocThread() during Tcl_Finalize() or * Tcl_FinalizeThread(). This function destroys the tsd key which * stores allocator caches in thread local storage. */ TclFreeAllocCache(ptr); success = TlsSetValue(tlsKey, NULL); if (!success) { Tcl_Panic("TlsSetValue failed from TclpFreeAllocCache"); } } else { /* * Called by us in TclFinalizeThreadAlloc() during the library * finalization initiated from Tcl_Finalize() */ success = TlsFree(tlsKey); if (!success) { Tcl_Panic("TlsFree failed from TclpFreeAllocCache"); } } }
void NsThreadFatal(char *func, char *osfunc, int err) { #ifdef _WIN32 Tcl_Panic("nsthreads: %s failed in %s: win32 err: %d", osfunc, func, err); #else Tcl_Panic("nsthreads: %s failed in %s: %s", osfunc, func, strerror(err)); #endif abort(); }
static void EmbWinCheckProc( TkTextSegment *ewPtr, /* Segment to check. */ TkTextLine *linePtr) /* Line containing segment. */ { if (ewPtr->nextPtr == NULL) { Tcl_Panic("EmbWinCheckProc: embedded window is last segment in line"); } if (ewPtr->size != 1) { Tcl_Panic("EmbWinCheckProc: embedded window has size %d", ewPtr->size); } }
void *TclpThreadCreateKey(void) { pthread_key_t *key; key = TclpSysAlloc(sizeof *key, 0); if (NULL == key) { Tcl_Panic("unable to allocate thread key!"); } if (pthread_key_create(key, NULL)) { Tcl_Panic("unable to create pthread key!"); } return key; }
void Tk_MacOSXSetupTkNotifier() { ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (!tsdPtr->initialized) { /* HACK ALERT: There is a bug in Jaguar where when it goes to make * the event queue for the Main Event Loop, it stores the Current * event loop rather than the Main Event Loop in the Queue structure. * So we have to make sure that the Main Event Queue gets set up on * the main thread. Calling GetMainEventQueue will force this to * happen. */ GetMainEventQueue(); tsdPtr->initialized = 1; /* Install Carbon events event source in main event loop thread. */ if (GetCurrentEventLoop() == GetMainEventLoop()) { if (!pthread_main_np()) { /* * Panic if the Carbon main event loop thread (i.e. the * thread where HIToolbox was first loaded) is not the * main application thread, as Carbon does not support * this properly. */ Tcl_Panic("Tk_MacOSXSetupTkNotifier: %s", "first [load] of TkAqua has to occur in the main thread!"); } Tcl_CreateEventSource(CarbonEventsSetupProc, CarbonEventsCheckProc, GetMainEventQueue()); TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL); } } }
void Tcl_Release( ClientData clientData) /* Pointer to malloc'ed block of memory. */ { Reference *refPtr; int i; Tcl_MutexLock(&preserveMutex); for (i=0, refPtr=refArray ; i<inUse ; i++, refPtr++) { int mustFree; Tcl_FreeProc *freeProc; if (refPtr->clientData != clientData) { continue; } if (--refPtr->refCount != 0) { Tcl_MutexUnlock(&preserveMutex); return; } /* * Must remove information from the slot before calling freeProc to * avoid reentrancy problems if the freeProc calls Tcl_Preserve on the * same clientData. Copy down the last reference in the array to * overwrite the current slot. */ freeProc = refPtr->freeProc; mustFree = refPtr->mustFree; inUse--; if (i < inUse) { refArray[i] = refArray[inUse]; } /* * Now committed to disposing the data. But first, we've patched up * all the global data structures so we should release the mutex now. * Only then should we dabble around with potentially-slow memory * managers... */ Tcl_MutexUnlock(&preserveMutex); if (mustFree) { if (freeProc == TCL_DYNAMIC) { ckfree((char *) clientData); } else { freeProc((char *) clientData); } } return; } Tcl_MutexUnlock(&preserveMutex); /* * Reference not found. This is a bug in the caller. */ Tcl_Panic("Tcl_Release couldn't find reference for 0x%x", clientData); }
void TclpThreadSetMasterTSD(void *tsdKeyPtr, void *ptr) { DWORD *key = tsdKeyPtr; if (!TlsSetValue(*key, ptr)) { Tcl_Panic("unable to set master TSD value"); } }
void *TclpThreadCreateKey (void) { DWORD *key; key = TclpSysAlloc(sizeof *key, 0); if (key == NULL) { Tcl_Panic("unable to allocate thread key!"); } *key = TlsAlloc(); if (*key == TLS_OUT_OF_INDEXES) { Tcl_Panic("unable to allocate thread-local storage"); } return key; }
int Tcl_GetBoolean( Tcl_Interp *interp, /* Interpreter used for error reporting. */ const char *src, /* String containing one of the boolean values * 1, 0, true, false, yes, no, on, off. */ int *boolPtr) /* Place to store converted result, which will * be 0 or 1. */ { Tcl_Obj obj; int code; obj.refCount = 1; obj.bytes = (char *) src; obj.length = strlen(src); obj.typePtr = NULL; code = Tcl_ConvertToType(interp, &obj, &tclBooleanType); if (obj.refCount > 1) { Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); } if (code == TCL_OK) { *boolPtr = obj.internalRep.longValue; } return code; }
void TclpThreadSetMasterTSD(void *tsdKeyPtr, void *ptr) { pthread_key_t *key = tsdKeyPtr; if (pthread_setspecific(*key, ptr)) { Tcl_Panic("unable to set master TSD value"); } }
Tcl_Obj * TkDebugColor( Tk_Window tkwin, /* The window in which the color will be used * (not currently used). */ char *name) /* Name of the desired color. */ { Tcl_HashEntry *hashPtr; Tcl_Obj *resultPtr; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; resultPtr = Tcl_NewObj(); hashPtr = Tcl_FindHashEntry(&dispPtr->colorNameTable, name); if (hashPtr != NULL) { TkColor *tkColPtr = Tcl_GetHashValue(hashPtr); if (tkColPtr == NULL) { Tcl_Panic("TkDebugColor found empty hash table entry"); } for ( ; (tkColPtr != NULL); tkColPtr = tkColPtr->nextPtr) { Tcl_Obj *objPtr = Tcl_NewObj(); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewIntObj(tkColPtr->resourceRefCount)); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewIntObj(tkColPtr->objRefCount)); Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); } } return resultPtr; }
extern void TclBNInitBignumFromWideUInt( mp_int *a, /* Bignum to initialize */ Tcl_WideUInt v) /* Initial value */ { int status; mp_digit *p; /* * Allocate enough memory to hold the largest possible Tcl_WideUInt. */ status = mp_init_size(a, (CHAR_BIT * sizeof(Tcl_WideUInt) + DIGIT_BIT - 1) / DIGIT_BIT); if (status != MP_OKAY) { Tcl_Panic("initialization failure in TclBNInitBignumFromWideUInt"); } a->sign = MP_ZPOS; /* * Store the magnitude in the bignum. */ p = a->dp; while (v) { *p++ = (mp_digit) (v & MP_MASK); v >>= MP_DIGIT_BIT; } a->used = p - a->dp; }
static void RegisterTcpServerInterpCleanup( Tcl_Interp *interp, /* Interpreter for which we want to be * informed of deletion. */ AcceptCallback *acceptCallbackPtr) /* The accept callback record whose interp * field we want set to NULL when the * interpreter is deleted. */ { Tcl_HashTable *hTblPtr; /* Hash table for accept callback records to * smash when the interpreter will be * deleted. */ Tcl_HashEntry *hPtr; /* Entry for this record. */ int isNew; /* Is the entry new? */ hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL); if (hTblPtr == NULL) { hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); Tcl_InitHashTable(hTblPtr, TCL_ONE_WORD_KEYS); (void) Tcl_SetAssocData(interp, "tclTCPAcceptCallbacks", TcpAcceptCallbacksDeleteProc, hTblPtr); } hPtr = Tcl_CreateHashEntry(hTblPtr, (char *) acceptCallbackPtr, &isNew); if (!isNew) { Tcl_Panic("RegisterTcpServerCleanup: damaged accept record table"); } Tcl_SetHashValue(hPtr, acceptCallbackPtr); }
void JIT_ResolveType(Proc *procPtr, int pos, int bctype) { int present = procPtr->jitproc.bytecodeTypes[pos].type; if (!present) { procPtr->jitproc.bytecodeTypes[pos].type = bctype; goto resolve; } switch (bctype) { /* XXX Not considering TCL_NUMBER_WIDE and * TCL_NUMBER_NAN yet. */ case TCL_NUMBER_DOUBLE: case TCL_NUMBER_BIG: procPtr->jitproc.bytecodeTypes[pos].type = bctype; break; case TCL_NUMBER_LONG: if (present != TCL_NUMBER_DOUBLE && present != TCL_NUMBER_BIG) procPtr->jitproc.bytecodeTypes[pos].type = bctype; break; default: Tcl_Panic("retry in a later version"); break; } resolve: procPtr->jitproc.bytecodeTypes[pos].resolved = 1; }
GC Tk_GCForColor( XColor *colorPtr, /* Color for which a GC is desired. Must have * been allocated by Tk_GetColor. */ Drawable drawable) /* Drawable in which the color will be used * (must have same screen and depth as the one * for which the color was allocated). */ { TkColor *tkColPtr = (TkColor *) colorPtr; XGCValues gcValues; /* * Do a quick sanity check to make sure this color was really allocated by * Tk_GetColor. */ if (tkColPtr->magic != COLOR_MAGIC) { Tcl_Panic("Tk_GCForColor called with bogus color"); } if (tkColPtr->gc == None) { gcValues.foreground = tkColPtr->color.pixel; tkColPtr->gc = XCreateGC(DisplayOfScreen(tkColPtr->screen), drawable, GCForeground, &gcValues); } return tkColPtr->gc; }
void Tk_FreeColor( XColor *colorPtr) /* Color to be released. Must have been * allocated by Tk_GetColor or * Tk_GetColorByValue. */ { TkColor *tkColPtr = (TkColor *) colorPtr; Screen *screen = tkColPtr->screen; TkColor *prevPtr; /* * Do a quick sanity check to make sure this color was really allocated by * Tk_GetColor. */ if (tkColPtr->magic != COLOR_MAGIC) { Tcl_Panic("Tk_FreeColor called with bogus color"); } tkColPtr->resourceRefCount--; if (tkColPtr->resourceRefCount > 0) { return; } /* * This color is no longer being actively used, so free the color * resources associated with it and remove it from the hash table. No * longer any objects referencing it. */ if (tkColPtr->gc != None) { XFreeGC(DisplayOfScreen(screen), tkColPtr->gc); tkColPtr->gc = None; } TkpFreeColor(tkColPtr); prevPtr = Tcl_GetHashValue(tkColPtr->hashPtr); if (prevPtr == tkColPtr) { if (tkColPtr->nextPtr == NULL) { Tcl_DeleteHashEntry(tkColPtr->hashPtr); } else { Tcl_SetHashValue(tkColPtr->hashPtr, tkColPtr->nextPtr); } } else { while (prevPtr->nextPtr != tkColPtr) { prevPtr = prevPtr->nextPtr; } prevPtr->nextPtr = tkColPtr->nextPtr; } /* * Free the TkColor structure if there are no objects referencing it. * However, if there are objects referencing it then keep the structure * around; it will get freed when the last reference is cleared */ if (tkColPtr->objRefCount == 0) { ckfree((char *) tkColPtr); } }
void * TclpThreadCreateKey(void) { pthread_key_t *ptkeyPtr; ptkeyPtr = TclpSysAlloc(sizeof *ptkeyPtr, 0); if (NULL == ptkeyPtr) { Tcl_Panic("unable to allocate thread key!"); } if (pthread_key_create(ptkeyPtr, NULL)) { Tcl_Panic("unable to create pthread key!"); } return ptkeyPtr; }
long Tk_GetUserInactiveTime( Display *dpy) /* The display for which to query the inactive * time. */ { long inactiveTime = -1; #ifdef HAVE_XSS int eventBase, errorBase, major, minor; /* * Calling XScreenSaverQueryVersion seems to be needed to prevent a crash * on some buggy versions of XFree86. */ if (HaveXSSLibrary() && XScreenSaverQueryExtension(dpy, &eventBase, &errorBase) && XScreenSaverQueryVersion(dpy, &major, &minor)) { XScreenSaverInfo *info = XScreenSaverAllocInfo(); if (info == NULL) { /* * We are out of memory. */ Tcl_Panic("Out of memory: XScreenSaverAllocInfo failed in Tk_GetUserInactiveTime"); } if (XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), info)) { inactiveTime = info->idle; } XFree(info); } #endif /* HAVE_XSS */ return inactiveTime; }
static void UnlinkSlave( Slave *slavePtr) /* Slave structure to be unlinked. */ { register Master *masterPtr; register Slave *prevPtr; masterPtr = slavePtr->masterPtr; if (masterPtr == NULL) { return; } if (masterPtr->slavePtr == slavePtr) { masterPtr->slavePtr = slavePtr->nextPtr; } else { for (prevPtr = masterPtr->slavePtr; ; prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { Tcl_Panic("UnlinkSlave couldn't find slave to unlink"); } if (prevPtr->nextPtr == slavePtr) { prevPtr->nextPtr = slavePtr->nextPtr; break; } } } if (masterPtr->abortPtr != NULL) { *masterPtr->abortPtr = 1; } slavePtr->masterPtr = NULL; }
/* *-------------------------------------------------------------------- * * Tk_3DBorderGC -- * * Given a 3D border, returns one of the graphics contexts used to draw * the border. * * Results: * Returns the graphics context given by the "which" argument. * * Side effects: * None. * *-------------------------------------------------------------------- */ GC Tk_3DBorderGC( Tk_Window tkwin, /* Window for which border was allocated. */ Tk_3DBorder border, /* Border whose GC is wanted. */ int which) /* Selects one of the border's 3 GC's: * TK_3D_FLAT_GC, TK_3D_LIGHT_GC, or * TK_3D_DARK_GC. */ { TkBorder * borderPtr = (TkBorder *) border; if ((borderPtr->lightGC == None) && (which != TK_3D_FLAT_GC)) { TkpGetShadows(borderPtr, tkwin); } if (which == TK_3D_FLAT_GC) { return borderPtr->bgGC; } else if (which == TK_3D_LIGHT_GC) { return borderPtr->lightGC; } else if (which == TK_3D_DARK_GC){ return borderPtr->darkGC; } Tcl_Panic("bogus \"which\" value in Tk_3DBorderGC"); /* * The code below will never be executed, but it's needed to keep * compilers happy. */ return (GC) None; }
void TkTextFreeTag( TkText *textPtr, /* Info about overall widget. */ register TkTextTag *tagPtr) /* Tag being deleted. */ { int i; /* * Let Tk do most of the hard work for us. */ Tk_FreeConfigOptions((char *) tagPtr, tagPtr->optionTable, textPtr->tkwin); /* * This associated information is managed by us. */ if (tagPtr->tabArrayPtr != NULL) { ckfree(tagPtr->tabArrayPtr); } /* * Make sure this tag isn't referenced from the 'current' tag array. */ for (i = 0; i < textPtr->numCurTags; i++) { if (textPtr->curTagArrayPtr[i] == tagPtr) { for (; i < textPtr->numCurTags-1; i++) { textPtr->curTagArrayPtr[i] = textPtr->curTagArrayPtr[i+1]; } textPtr->curTagArrayPtr[textPtr->numCurTags-1] = NULL; textPtr->numCurTags--; break; } } /* * If this tag is widget-specific (peer widgets) then clean up the * refCount it holds. */ if (tagPtr->textPtr != NULL) { if (textPtr != tagPtr->textPtr) { Tcl_Panic("Tag being deleted from wrong widget"); } textPtr->refCount--; if (textPtr->refCount == 0) { ckfree(textPtr); } tagPtr->textPtr = NULL; } /* * Finally free the tag's memory. */ ckfree(tagPtr); }
void Tcl_DeleteHashEntry( Tcl_HashEntry *entryPtr) { register Tcl_HashEntry *prevPtr; const Tcl_HashKeyType *typePtr; Tcl_HashTable *tablePtr; Tcl_HashEntry **bucketPtr; #if TCL_HASH_KEY_STORE_HASH int index; #endif tablePtr = entryPtr->tablePtr; if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #if TCL_HASH_KEY_STORE_HASH if (typePtr->hashKeyProc == NULL || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, entryPtr->hash); } else { index = PTR2UINT(entryPtr->hash) & tablePtr->mask; } bucketPtr = &(tablePtr->buckets[index]); #else bucketPtr = entryPtr->bucketPtr; #endif if (*bucketPtr == entryPtr) { *bucketPtr = entryPtr->nextPtr; } else { for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { Tcl_Panic("malformed bucket chain in Tcl_DeleteHashEntry"); } if (prevPtr->nextPtr == entryPtr) { prevPtr->nextPtr = entryPtr->nextPtr; break; } } } tablePtr->numEntries--; if (typePtr->freeEntryProc) { typePtr->freeEntryProc (entryPtr); } else { ckfree((char *) entryPtr); } }
/* ARGSUSED */ static Tcl_HashEntry * BogusFind( Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */ const char *key) /* Key to use to find matching entry. */ { Tcl_Panic("called %s on deleted table", "Tcl_FindHashEntry"); return NULL; }
int XGetGeometry( Display *display, Drawable d, Window *root_return, int *x_return, int *y_return, unsigned int *width_return, unsigned int *height_return, unsigned int *border_width_return, unsigned int *depth_return) { TkWinDrawable *twdPtr = (TkWinDrawable *)d; if (twdPtr->type == TWD_BITMAP) { HDC dc; BITMAPINFO info; if (twdPtr->bitmap.handle == NULL) { Tcl_Panic("XGetGeometry: invalid pixmap"); } dc = GetDC(NULL); info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biBitCount = 0; if (!GetDIBits(dc, twdPtr->bitmap.handle, 0, 0, NULL, &info, DIB_RGB_COLORS)) { Tcl_Panic("XGetGeometry: unable to get bitmap size"); } ReleaseDC(NULL, dc); *width_return = info.bmiHeader.biWidth; *height_return = info.bmiHeader.biHeight; } else if (twdPtr->type == TWD_WINDOW) { RECT rect; if (twdPtr->window.handle == NULL) { Tcl_Panic("XGetGeometry: invalid window"); } GetClientRect(twdPtr->window.handle, &rect); *width_return = rect.right - rect.left; *height_return = rect.bottom - rect.top; } else { Tcl_Panic("XGetGeometry: invalid window"); } return 1; }
static void SpinLockLockInit(void) { lockLock = OSSpinLockLock != NULL ? OSSpinLockLock : _spin_lock; lockUnlock = OSSpinLockUnlock != NULL ? OSSpinLockUnlock : _spin_unlock; lockTry = OSSpinLockTry != NULL ? OSSpinLockTry : _spin_lock_try; if (lockLock == NULL || lockUnlock == NULL) { Tcl_Panic("SpinLockLockInit: no spinlock API available"); } }
static int TkcCreateBitmap( Tcl_Interp *interp, /* Interpreter for error reporting. */ Tk_Canvas canvas, /* Canvas to hold new item. */ Tk_Item *itemPtr, /* Record to hold new item; header has been * initialized by caller. */ int objc, /* Number of arguments in objv. */ Tcl_Obj *const objv[]) /* Arguments describing rectangle. */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; int i; if (objc == 0) { Tcl_Panic("canvas did not pass any coords"); } /* * Initialize item's record. */ bmapPtr->anchor = TK_ANCHOR_CENTER; bmapPtr->bitmap = None; bmapPtr->activeBitmap = None; bmapPtr->disabledBitmap = None; bmapPtr->fgColor = NULL; bmapPtr->activeFgColor = NULL; bmapPtr->disabledFgColor = NULL; bmapPtr->bgColor = NULL; bmapPtr->activeBgColor = NULL; bmapPtr->disabledBgColor = NULL; bmapPtr->gc = None; /* * Process the arguments to fill in the item record. Only 1 (list) or 2 (x * y) coords are allowed. */ if (objc == 1) { i = 1; } else { const char *arg = Tcl_GetString(objv[1]); i = 2; if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { i = 1; } } if (BitmapCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { goto error; } if (ConfigureBitmap(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { return TCL_OK; } error: DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); return TCL_ERROR; }
void Tcl_AsyncDelete( Tcl_AsyncHandler async) /* Token for handler to delete. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); AsyncHandler *asyncPtr = (AsyncHandler *) async; AsyncHandler *prevPtr, *thisPtr; /* * Assure early handling of the constraint */ if (asyncPtr->originThrdId != Tcl_GetCurrentThread()) { Tcl_Panic("Tcl_AsyncDelete: async handler deleted by the wrong thread"); } /* * If we come to this point when TSD's for the current * thread have already been garbage-collected, we are * in the _serious_ trouble. OTOH, we tolerate calling * with already cleaned-up handler list (should we?). */ Tcl_MutexLock(&tsdPtr->asyncMutex); if (tsdPtr->firstHandler != NULL) { prevPtr = thisPtr = tsdPtr->firstHandler; while (thisPtr != NULL && thisPtr != asyncPtr) { prevPtr = thisPtr; thisPtr = thisPtr->nextPtr; } if (thisPtr == NULL) { Tcl_Panic("Tcl_AsyncDelete: cannot find async handler"); } if (asyncPtr == tsdPtr->firstHandler) { tsdPtr->firstHandler = asyncPtr->nextPtr; } else { prevPtr->nextPtr = asyncPtr->nextPtr; } if (asyncPtr == tsdPtr->lastHandler) { tsdPtr->lastHandler = prevPtr; } } Tcl_MutexUnlock(&tsdPtr->asyncMutex); ckfree((char *) asyncPtr); }
void TclpThreadDeleteKey(void *keyPtr) { pthread_key_t *key = keyPtr; if (pthread_key_delete(*key)) { Tcl_Panic("unable to delete key!"); } TclpSysFree(keyPtr); }