Esempio n. 1
0
/*! Set the error message of the current thread to the given string.

    Always returns -1.
*/
int hpgs_set_verror(const char *fmt, va_list ap)
{
  char *x;
#ifdef WIN32
  x = (char *)TlsGetValue(tls_handle);
  if (x) HeapFree(hHeap,0,x);
  x = vsprintf_hHeap(fmt,ap);
  TlsSetValue(tls_handle,x);
#else
  x = (char *)pthread_getspecific (key);
  if (x) free(x);

  va_list aq;
  va_copy(aq, ap);      
  x = hpgs_vsprintf_malloc(fmt,aq);
  va_end(aq);

  pthread_setspecific (key,x);
#endif
  return -1;
}
Esempio n. 2
0
static void set_error_from_last(void) {
    DWORD slot = get_tl_error_slot();
    char * s = NULL;
    char * old_s;

    if (slot == TLS_OUT_OF_INDEXES)
        return;

    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
		  0, GetLastError(), 0,
		  (LPTSTR) &s, 0,
		  NULL);
    if (s == NULL)
        return;

    old_s = (char *) TlsGetValue(slot);
    TlsSetValue(slot, (LPVOID) s);

    if (old_s != NULL)
        LocalFree(old_s);
}
Esempio n. 3
0
SilcThread silc_thread_self(void)
{
#ifdef SILC_THREADS
  SilcWin32Thread self = TlsGetValue(silc_thread_tls);

  if (!self) {
    /* This should only happen for the main thread. */
    HANDLE handle = GetCurrentThread ();
    HANDLE process = GetCurrentProcess ();
    self = silc_calloc(1, sizeof(*self));
    DuplicateHandle(process, handle, process,
		    &self->thread, 0, FALSE,
		    DUPLICATE_SAME_ACCESS);
    TlsSetValue(silc_thread_tls, self);
  }

  return (SilcThread)self;
#else
  return NULL;
#endif
}
Esempio n. 4
0
int callback_uri(http_parser *parser, const char *pos, size_t len)

{

	http_message *message = (http_message *) TlsGetValue(dwTlsIndex);

	char uri_buf[MAX_URI_SIZE];

	DWORD uri_buflen = MAX_URI_SIZE;

	

	strncpy_s(uri_buf, MAX_URI_SIZE, pos, len);

	InternetCanonicalizeUrlA(uri_buf, message->request_uri, &uri_buflen, ICU_DECODE | ICU_NO_ENCODE);



	return 0;

}
    int ConnectorInterface::GetBufferIndex(bool bReserve)
    {
#if BEHAVIAC_COMPILER_MSVC
        BEHAVIAC_ASSERT(t_packetBufferIndex != TLS_OUT_OF_INDEXES);
        int bufferIndex = (int)TlsGetValue(t_packetBufferIndex);
#else
        BEHAVIAC_ASSERT(t_packetBufferIndex != (unsigned int) - 1);
        int bufferIndex = (int)t_packetBufferIndex;
#endif
        //WHEN bReserve is false, it is unsafe to allocate memory as other threads might be allocating
        //you can avoid the following assert to malloc a block of memory in your thread at the very beginning
        BEHAVIAC_ASSERT(bufferIndex > 0 || bReserve);

        //bufferIndex initially is 0
        if (bufferIndex <= 0 && bReserve)
        {
            bufferIndex = ReserveThreadPacketBuffer();
        }

        return bufferIndex;
    }
Esempio n. 6
0
	ThreadLocalStorage::~ThreadLocalStorage()
	{
		if (!instance)
			return;
#ifdef WIN32
		if (instance->cl_tls_index == TLS_OUT_OF_INDEXES)
			return;
		ThreadLocalStorage_Impl *tls_impl = (ThreadLocalStorage_Impl *)TlsGetValue(instance->cl_tls_index);
		if (tls_impl)
			tls_impl->release_reference();
#elif !defined(HAVE_TLS)
		if (!instance->cl_tls_index_created)
			return;
		ThreadLocalStorage_Impl *tls_impl = (ThreadLocalStorage_Impl *) pthread_getspecific(instance->cl_tls_index);
		if (tls_impl)
			tls_impl->release_reference();
#else
		if (instance->cl_tls_impl)
			instance->cl_tls_impl->release_reference();
#endif
	}
Esempio n. 7
0
pthread_t pthread_self(void)
{
  pthread_t t;
	
  _pthread_once_raw(&_pthread_tls_once, pthread_tls_init);
	
  t = (pthread_t)TlsGetValue(_pthread_tls);
	
  /* Main thread? */
  if (!t)
    {
      t = (pthread_t)malloc(sizeof(struct _pthread_v));
		
      /* If cannot initialize main thread, then the only thing we can do is abort */
      if (!t) abort();
	
      t->ret_arg = NULL;
      t->func = NULL;
      t->clean = NULL;
      t->cancelled = 0;
      t->p_state = PTHREAD_DEFAULT_ATTR;
      t->keymax = 0;
      t->keyval = NULL;
      t->h = GetCurrentThread();
		
      /* Save for later */
      TlsSetValue(_pthread_tls, t);
		
      if (setjmp(t->jb))
	{
	  /* Make sure we free ourselves if we are detached */
	  if (!t->h) free(t);
			
	  /* Time to die */
	  _endthreadex(0);
	}
    }
	
  return t;
}
Esempio n. 8
0
boolean aboutsetmiscstring (bigstring bsmisc) {
	
	#ifdef WIN95VERSION
	extern 	DWORD ixthreadglobalsgrabcount;			// Tls index of counter for nest globals grabbing

	long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
	#endif

//	register hdlcancoonrecord hc = cancoonglobals;
//	hdlwindowinfo hinfo;

	copystring (bsmisc, bsmiscinfo);

//	if (!findaboutwindow (&hinfo) || !shellpushglobals ((**hinfo).macwindow))
//		return (false);
	
	#ifdef WIN95VERSION
	if (grabcount > 0)
	#endif
	if (aboutport != nil && flhavemiscrect) {
		
		pushport (aboutport);
		
			pushclip (miscinforect);
			
			eraserect (miscinforect);
			
			movepento (miscinforect.left, miscinforect.top + globalfontinfo.ascent);
			
			pendrawstring (bsmisc);
			
			popclip ();

		popport ();
		}
	
//	shellpopglobals ();

	return (true);
	} /*aboutsetmiscstring*/
Esempio n. 9
0
static HDC getBitmapDC(void *imageData) {
    HDC hdc;
    HANDLE  *mutex = (HANDLE*) TlsGetValue(tlsId);

    if(mutex == NULL) {
        mutex = (HANDLE*)malloc(sizeof(HANDLE));
        if(mutex == NULL) {
            return NULL;
        }
        TlsSetValue(tlsId, mutex);
        *mutex = CreateMutex(0, JAVACALL_FALSE, "hPhoneBitmapMutex");
    }

    if(lastImage != imageData) {
        if(hMemDC != NULL) {
            DeleteDC(hMemDC);
        }

        hdc = GetDC(hMainWindow);
        hMemDC = CreateCompatibleDC(hdc);
        ReleaseDC(hMainWindow, hdc);
        lastImage = imageData;
    }

    WaitForSingleObject(*mutex, INFINITE);

    if(imageData == NULL) {
        CHECK_RETURN(getBitmapDCtmp = SelectObject(hMemDC, hPhoneBitmap));
        SetWindowOrgEx(hMemDC, -x_offset, -(Y_SCREEN_OFFSET), NULL);
    } else if(imageData == UNTRANSLATED_SCREEN_BITMAP) {
        CHECK_RETURN(getBitmapDCtmp = SelectObject(hMemDC, hPhoneBitmap));
    } else {
        myBitmapStruct *bmp = (myBitmapStruct *)imageData;
        if(bmp->mutable) {
            getBitmapDCtmp = SelectObject(hMemDC, bmp->bitmap);
        }
    }

    return hMemDC;
}
Esempio n. 10
0
// ================================================================================================
// FUNCTION  : wiProcess_ThreadIndex()
// ------------------------------------------------------------------------------------------------
// ================================================================================================
unsigned int wiProcess_ThreadIndex(void)
{
    #ifdef WISE_BUILD_MULTITHREADED

        #if defined WISE_USE_PTHREADS
        {
            void *lpvData = pthread_getspecific(wiProcessKey);
            return lpvData ? *((unsigned int *)lpvData) : 0;
        }
        #elif defined WIN32
        {
            LPVOID lpvData = TlsGetValue(dwTlsIndex); 
            return *((unsigned int *)lpvData);
        }
        #else
            return STATUS(WI_ERROR_NO_MULTITHREAD_SUPPORT);
        #endif

    #else
        return 0;
    #endif
}
Esempio n. 11
0
int async_fibre_init_dispatcher(async_fibre *fibre)
{
    LPVOID dispatcher;

    dispatcher = (LPVOID)TlsGetValue(asyncwindispatch);
    if (dispatcher == NULL) {
        fibre->fibre = ConvertThreadToFiber(NULL);
        if (fibre->fibre == NULL) {
            fibre->converted = 0;
            fibre->fibre = GetCurrentFiber();
            if (fibre->fibre == NULL)
                return 0;
        } else {
            fibre->converted = 1;
        }
        if (TlsSetValue(asyncwindispatch, (LPVOID)fibre->fibre) == 0)
            return 0;
    } else {
        fibre->fibre = dispatcher;
    }
    return 1;
}
Esempio n. 12
0
int dc_get_device_status(wchar_t *device, dc_status *status)
{
	dc_ioctl dctl;
	u32      bytes;
	int      succs;

	wcscpy(dctl.device, device);

	succs = DeviceIoControl(
		TlsGetValue(h_tls_idx), DC_CTL_STATUS,
		&dctl, sizeof(dc_ioctl), status, sizeof(dc_status), &bytes, NULL);

	if (succs == 0) {
		return ST_ERROR;
	} else
	{
		if (status->mnt_point[0] == 0) {
			wcscpy(status->mnt_point, device); /* -- */
		}
		return dctl.status;
	}
}
Esempio n. 13
0
int dc_get_boot_device(wchar_t *device)
{
	dc_ioctl dctl;
	u32      bytes;
	int      succs;

	wcscpy(dctl.device, L"\\ArcName\\multi(0)disk(0)rdisk(0)partition(1)");

	succs = DeviceIoControl(
		TlsGetValue(h_tls_idx), DC_CTL_RESOLVE, 
		&dctl, sizeof(dctl), &dctl, sizeof(dctl), &bytes, NULL);

	if (succs != 0) 
	{
		if (dctl.status == ST_OK) {
			wcscpy(device, dctl.device);			
		}
		return dctl.status;
	} else {		
		return ST_ERROR;
	}
}
Esempio n. 14
0
/**
 * Pop and call the top cleanup routine.
 * The pthread_cleanup_pop() function pops the top cleanup routine off
 * of the current threads cleanup routine stack, and, if execute is
 * non-zero, it will execute the function. If there is no cleanup
 * routine then pthread_cleanup_pop() does nothing.
 *
 * @param  execute If execute is non-zero, the top-most clean-up handler
 * is popped and executed.
 * @bug The main thread do not support cleanup routines.
 */
void pthread_cleanup_pop(int execute)
{
    arch_thread_info *pv = TlsGetValue(libpthread_tls_index);
    if (pv != NULL) {
        arch_thread_cleanup_list *node = pv->cleanup_list, *prev;

        if (node == NULL) return;
        while(node->next != NULL)
            node = node->next;

        if (execute) {
            node->cleaner(node->arg);
        }

        prev = node->prev;
        free(node);
        if(prev == NULL)
            pv->cleanup_list = NULL;
        else
            prev->next = NULL;
    }
}
Esempio n. 15
0
/* Deinitialize libgpg-error.  This function is only used in special
   circumstances.  No gpg-error function should be used after this
   function has been called.  A value of 0 passed for MODE
   deinitializes the entire libgpg-error, a value of 1 releases
   resources allocated for the current thread and only that thread may
   not anymore access libgpg-error after such a call.  Under Windows
   this function may be called from the DllMain function of a DLL
   which statically links to libgpg-error.  */
void
_gpg_err_deinit (int mode)
{
#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
  struct tls_space_s *tls;

  tls = TlsGetValue (tls_index);
  if (tls)
    {
      TlsSetValue (tls_index, NULL);
      LocalFree (tls);
    }

  if (mode == 0)
    {
      TlsFree (tls_index);
      tls_index = TLS_OUT_OF_INDEXES;
    }
#else
  (void)mode;
#endif
}
Esempio n. 16
0
/* static */
bool JsrtContext::TrySetCurrent(JsrtContext * context)
{
    Assert(s_tlsSlot != TLS_OUT_OF_INDEXES);

    ThreadContext * threadContext;

    //We are not pinning the context after SetCurrentContext, so if the context is not pinned
    //it might be reclaimed half way during execution. In jsrtshell the runtime was optimized out
    //at time of JsrtContext::Run by the compiler.
    //The change is to pin the context at setconcurrentcontext, and unpin the previous one. In
    //JsDisposeRuntime we'll reject if current context is active, so that will make sure all
    //contexts are unpinned at time of JsDisposeRuntime.
    if (context != nullptr)
    {
        threadContext = context->GetScriptContext()->GetThreadContext();

        if (!ThreadContextTLSEntry::TrySetThreadContext(threadContext))
        {
            return false;
        }
        threadContext->GetRecycler()->RootAddRef((LPVOID)context);
    }
    else
    {
        if (!ThreadContextTLSEntry::ClearThreadContext(true))
        {
            return false;
        }
    }

    JsrtContext* originalContext = (JsrtContext*) TlsGetValue(s_tlsSlot);
    if (originalContext != nullptr)
    {
        originalContext->GetScriptContext()->GetRecycler()->RootRelease((LPVOID) originalContext);
    }

    TlsSetValue(s_tlsSlot, context);
    return true;
}
Esempio n. 17
0
static void set_error(const char * e)
{
    char * s;
    char * old_s;
    size_t len;

    DWORD slot = get_tl_error_slot();

    if (slot == TLS_OUT_OF_INDEXES)
        return;

    len = strlen(e) * sizeof(char) + sizeof(char);
    s = LocalAlloc(LMEM_FIXED, len);
    if (s == NULL)
        return;

    old_s = (char *) TlsGetValue(slot);
    TlsSetValue(slot, (LPVOID) s);

    if (old_s != NULL)
        LocalFree(old_s);
}
Esempio n. 18
0
BOOL WINAPI TLS_SetThread(fdcore::UpdateSystemThread* dw)
{
   LPVOID lpvData; 
   fdcore::UpdateSystemThread** pData;  // The stored memory pointer 

   lpvData = TlsGetValue(dwTlsIndex); 
   if (lpvData == NULL)
   {
      lpvData = (LPVOID) LocalAlloc(LPTR, 256); 
      if (lpvData == NULL) 
         return FALSE;
      if (!TlsSetValue(dwTlsIndex, lpvData))
         return FALSE;
   }

   pData = (fdcore::UpdateSystemThread**) lpvData; // Cast to my data type.
   // In this example, it is only a pointer to a DWORD
   // but it can be a structure pointer to contain more complicated data.

   (*pData) = dw;
   return TRUE;
}
Esempio n. 19
0
static void detach_thread(void)
{
    tls_data_t *data;

    if(urlmon_tls == TLS_OUT_OF_INDEXES)
        return;

    data = TlsGetValue(urlmon_tls);
    if(!data)
        return;

    EnterCriticalSection(&tls_cs);
    list_remove(&data->entry);
    LeaveCriticalSection(&tls_cs);

    if(data->notif_hwnd) {
        WARN("notif_hwnd not destroyed\n");
        DestroyWindow(data->notif_hwnd);
    }

    heap_free(data);
}
Esempio n. 20
0
File: threads.c Progetto: WeiY/krb5
void krb5int_thread_detach_hook (void)
{
    /* XXX Memory leak here!
       Need to destroy all TLS objects we know about for this thread.  */
    struct tsd_block *t;
    int i, err;

    err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
    if (err)
        return;

    t = TlsGetValue(tls_idx);
    if (t == NULL)
        return;
    for (i = 0; i < K5_KEY_MAX; i++) {
        if (destructors_set[i] && destructors[i] && t->values[i]) {
            void *v = t->values[i];
            t->values[i] = 0;
            (*destructors[i])(v);
        }
    }
}
Esempio n. 21
0
// ================================================================================================
// FUNCTION  : wiProcess_Close()
// ------------------------------------------------------------------------------------------------
// ================================================================================================
wiStatus wiProcess_Close(void)
{
    if (!ModuleIsInitialized) return STATUS(WI_ERROR_MODULE_NOT_INITIALIZED);

    #ifdef WISE_BUILD_MULTITHREADED

        #if defined WISE_USE_PTHREADS

            // nothing to do

        #elif defined WIN32 
        {
            LPVOID lpvData = TlsGetValue(dwTlsIndex); 
            LocalFree((HLOCAL)lpvData);
            TlsFree(dwTlsIndex);
        }
        #endif
    #endif

    ModuleIsInitialized = WI_FALSE;
    return WI_SUCCESS;
}
Esempio n. 22
0
STDMETHODIMP_(VOID) DHContext::Release(SIZE_T cookie)
{
#if LOCK_TRACE
    // If we're tracing, enter a record into the list of currently held locks.
    vector<SIZE_T> *pCurrentLocks = reinterpret_cast<vector<SIZE_T>*>(TlsGetValue(m_dwTlsCurrentLocks));
    if (pCurrentLocks)
    {
        _ASSERTE(!pCurrentLocks->empty() && "Expected a non-empty list");

        if (pCurrentLocks->back() == cookie)
        {
            // This is the fast case (vector is constant time deletion from front/back).
            pCurrentLocks->pop_back();
        }
        else
        {
            // Slow case, we must manually iterate through the list.
            for (vector<SIZE_T>::iterator currentWalker = pCurrentLocks->end();
                currentWalker != pCurrentLocks->begin();
                currentWalker--)
            {
                if (*currentWalker == cookie)
                {
                    pCurrentLocks->erase(currentWalker);
                    break;
                }
            }
        }

        // If the current list is empty, remove it from TLS and delete it. We will lazily
        // re-create it if necessary.
        if (pCurrentLocks->empty())
        {
            TlsSetValue(m_dwTlsCurrentLocks, NULL);
            delete pCurrentLocks;
        }
    }
#endif
}
Esempio n. 23
0
File: hal.c Progetto: callcc/tekui
EXPORT TUINT
hal_setsignal(struct THALBase *hal, TUINT newsig, TUINT sigmask)
{
	struct HALSpecific *hws = hal->hmb_Specific;
	struct HALThread *wth = TlsGetValue(hws->hsp_TLSIndex);
#ifndef HAL_USE_ATOMICS 
	TUINT oldsig;
	EnterCriticalSection(&wth->hth_SigLock);
	oldsig = wth->hth_SigState;
	wth->hth_SigState &= ~sigmask;
	wth->hth_SigState |= newsig;
	LeaveCriticalSection(&wth->hth_SigLock);
	return oldsig;
#else
	TUINT cmask = ~sigmask | newsig;
	TUINT before_consume = InterlockedAnd(&wth->hth_SigState, cmask);
	if (! newsig)
		return before_consume;
	TUINT before_publish = InterlockedOr(&wth->hth_SigState, newsig);
	return (before_consume & ~cmask) | (before_publish & cmask);
#endif
}
Esempio n. 24
0
static void
__mingwthr_run_key_dtors (void)
{
  __mingwthr_key_t volatile *keyp;

  if (__mingwthr_cs_init == 0)
    return;
  EnterCriticalSection (&__mingwthr_cs);

  for (keyp = key_dtor_list; keyp; )
    {
      LPVOID value = TlsGetValue (keyp->key);
      if (GetLastError () == ERROR_SUCCESS)
        {
          if (value)
            (*keyp->dtor) (value);
        }
      keyp = keyp->next;
    }

  LeaveCriticalSection (&__mingwthr_cs);
}
Esempio n. 25
0
void *pa_tls_set(pa_tls *t, void *userdata) {
    void *r;

    assert(t);

    r = TlsGetValue(t->index);

    TlsSetValue(t->index, userdata);

    if (t->free_func) {
        struct pa_tls_monitor *m;

        PA_ONCE_BEGIN {
            monitor_tls = pa_tls_new(NULL);
            assert(monitor_tls);
            pa_tls_set(monitor_tls, NULL);
        } PA_ONCE_END;

        m = pa_tls_get(monitor_tls);
        if (!m) {
            HANDLE thread;

            m = pa_xnew(struct pa_tls_monitor, 1);

            DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
                GetCurrentProcess(), &m->thread, 0, FALSE,
                DUPLICATE_SAME_ACCESS);

            m->free_func = t->free_func;

            pa_tls_set(monitor_tls, m);

            thread = CreateThread(NULL, 0, monitor_thread_func, m, 0, NULL);
            assert(thread);
            CloseHandle(thread);
        }

        m->data = userdata;
    }
Esempio n. 26
0
DWORD Distributor::getframes(LPVOID param){
	Thread* current_thread=(Thread*)param;
	Distributor* _this=current_thread->distributor;
	IScriptEnvironment** penv=&_this->_env;
	TlsSetValue(TlsIndex,new ScriptEnvironmentTLS());
	while(true)
	{
		WaitForSingleObject(current_thread->begin,INFINITE);
		_RPT2(0,"Thread %d generating frame %d\n",GetCurrentThreadId(),current_thread->n);
		if(current_thread->endthread)
			break;

		current_thread->result=_this->child->GetFrame(current_thread->n,*penv);

		_RPT2(0,"Thread %d finished generating frame %d\n",GetCurrentThreadId(),current_thread->n);
		current_thread->status=Distributor::Thread::idle;
		SetEvent(current_thread->done);
	}
	delete((ScriptEnvironmentTLS*) TlsGetValue(TlsIndex));
	ExitThread(0);
  return 0;
}
Esempio n. 27
0
/* Return the tls object.  This function is guaranteed to return a
   valid non-NULL object.  */
struct tls_space_s *
get_tls (void)
{
  struct tls_space_s *tls;

  tls = TlsGetValue (tls_index);
  if (!tls)
    {
      /* Called by a thread which existed before this DLL was loaded.
         Allocate the space.  */
      tls = LocalAlloc (LPTR, sizeof *tls);
      if (!tls)
        {
          /* No way to continue - commit suicide.  */
          abort ();
        }
      tls->gt_use_utf8 = 0;
      TlsSetValue (tls_index, tls);
    }
        
  return tls;
}
Esempio n. 28
0
static inline void msvcrt_free_tls_mem(void)
{
  thread_data_t *tls = TlsGetValue(msvcrt_tls_index);

  if (tls)
  {
    CloseHandle(tls->handle);
    MSVCRT_free(tls->efcvt_buffer);
    MSVCRT_free(tls->asctime_buffer);
    MSVCRT_free(tls->wasctime_buffer);
    MSVCRT_free(tls->strerror_buffer);
    MSVCRT_free(tls->wcserror_buffer);
    MSVCRT_free(tls->time_buffer);
    MSVCRT_free(tls->tmpnam_buffer);
    MSVCRT_free(tls->wtmpnam_buffer);
    if(tls->have_locale) {
        free_locinfo(tls->locinfo);
        free_mbcinfo(tls->mbcinfo);
    }
  }
  HeapFree(GetProcessHeap(), 0, tls);
}
Esempio n. 29
0
CxContext* icxGetContext()
{
#ifdef CX_DLL
#ifdef WIN32
    CxContext* pContext = (CxContext*)TlsGetValue( g_TlsIndex );
    if( !pContext )
    {
    pContext = icxCreateContext();

    if( !pContext )
    {
        FatalAppExit( 0, "OpenCX. Problem to allocate memory for TLS OpenCX context." );
    }
    TlsSetValue( g_TlsIndex, pContext );
    }
    return pContext;
#else
    CxContext* pContext = (CxContext*)pthread_getspecific( g_TlsIndex );
    if( !pContext )
    {
    pContext = icxCreateContext();
    if( !pContext )
    {
            fprintf(stderr,"OpenCX. Problem to allocate memory for OpenCX context.");
        exit(1);
    }
    pthread_setspecific( g_TlsIndex, pContext );
    }
    return pContext;
#endif
#else /* CX_DLL */
    static CxContext* pContext = 0;

    if( !pContext )
    pContext = icxCreateContext();

    return pContext;
#endif
}
Esempio n. 30
0
File: mthr.c Progetto: WndSks/msys
void
__mingwthr_run_key_dtors (void)
{
    __mingwthr_key_t *keyp;

#ifdef DEBUG
    printf ("%s: Entering Thread id %ld\n", __FUNCTION__, GetCurrentThreadId() );
#endif

    EnterCriticalSection (&__mingwthr_cs);

    for (keyp = key_dtor_list; keyp; )
    {
        LPVOID value = TlsGetValue (keyp->key);
        if (GetLastError () == ERROR_SUCCESS)
        {
#ifdef DEBUG
            printf ("   (%ld, %x)\n", keyp->key, keyp->dtor);
#endif
            if (value)
                (*keyp->dtor) (value);
        }
#ifdef DEBUG
        else
        {
            printf ("   TlsGetValue FAILED  (%ld, %x)\n",
                    keyp->key, keyp->dtor);
        }
#endif
        keyp = keyp->next;
    }

    LeaveCriticalSection (&__mingwthr_cs);

#ifdef DEBUG
    printf ("%s: Exiting Thread id %ld\n", __FUNCTION__, GetCurrentThreadId() );
#endif
}