windows-nt/Source/XPSP1/NT/sdktools/unicows/godot/threads.c
2020-09-26 16:20:57 +08:00

216 lines
5.7 KiB
C

/*++
Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
Module Name:
threads.c
Abstract:
This file contains functions that support our threading efforts
Functions found in this file:
GetThreadInfoSafe
UninitThread
Revision History:
01 Mar 2001 v-michka Created.
--*/
#include "precomp.h"
//
// The MEM structure. We store a linked list of these. In our
// most optimal case, this is a list with just one MEM in it.
//
struct MEM
{
LPGODOTTLSINFO alloc; // the allocation to store
struct MEM* next; // Pointer to the next MEM to chain to
};
struct MEM* m_memHead;
/*-------------------------------
GetThreadInfoSafe
Returns our TLS info, and if it has never been gotten,
allocates it (if the caller specifies) and returns the
newly allocated info.
-------------------------------*/
LPGODOTTLSINFO GetThreadInfoSafe(BOOL fAllocate)
{
LPGODOTTLSINFO lpgti = NULL;
DWORD dwLastError = ERROR_SUCCESS;
// Use SEH around our critical section since low memory
// situations can cause a STATUS_INVALID_HANDLE exception
// to be raise. We will simply set the last error for this
// case so the client can always know why we failed
// CONSIDER: Use ERROR_LOCK_FAILED or ERROR_LOCKED here?
__try
{
EnterCriticalSection(&g_csThreads);
lpgti = TlsGetValue(g_tls);
dwLastError = GetLastError();
if(!lpgti)
{
if(fAllocate)
{
struct MEM* newThreadMem;
lpgti = GodotHeapAlloc(sizeof(GODOTTLSINFO));
if(!lpgti)
dwLastError = ERROR_OUTOFMEMORY;
else
{
// First lets add the block to our
// handy linked list of allocations.
if(newThreadMem = GodotHeapAlloc(sizeof(struct MEM)))
{
newThreadMem->alloc = lpgti;
newThreadMem->next = m_memHead;
m_memHead = newThreadMem;
// Now lets store it in the TLS slot.
dwLastError = GetLastError();
TlsSetValue(g_tls, lpgti);
}
else
dwLastError = ERROR_OUTOFMEMORY;
if(dwLastError != ERROR_SUCCESS)
{
// we failed somehow, so clean it all up
GodotHeapFree(lpgti);
m_memHead = m_memHead->next;
GodotHeapFree(newThreadMem);
lpgti = NULL;
}
}
}
else
dwLastError=ERROR_OUTOFMEMORY;
}
}
__finally
{
LeaveCriticalSection(&g_csThreads);
}
if(lpgti == NULL)
{
SetLastError(dwLastError);
return(NULL);
}
return(lpgti);
}
/*-------------------------------
UninitThread
-------------------------------*/
void UninitThread(void)
{
LPGODOTTLSINFO lpgti;
if(g_tls)
{
// don't alloc if its not there!
lpgti = GetThreadInfoSafe(FALSE);
// Use SEH around our critical section since low memory
// situations can cause a STATUS_INVALID_HANDLE exception
// to be raise. Note that if we fail to enter our CS that
// missing out on this alloc is the least of our problems.
// We will get a second chance at process close to free
// it up, if we ever get there.
__try
{
EnterCriticalSection(&g_csThreads);
if(lpgti)
{
struct MEM* current = m_memHead;
// Clean up that ol' heap allocated memory
GodotHeapFree(lpgti);
while(current != NULL)
{
if(current->alloc == lpgti)
{
// Must handle the head case separately
m_memHead = current->next;
current->alloc = NULL;
GodotHeapFree(current);
break;
}
if((current->next != NULL) && (current->next->alloc == lpgti))
{
// The next one in line is the
// one we want to free up
current->next = current->next->next;
current->next->alloc = NULL;
GodotHeapFree(current->next);
break;
}
current = current->next;
}
TlsSetValue(g_tls, NULL);
}
}
__finally
{
LeaveCriticalSection(&g_csThreads);
}
}
return;
}
/*-------------------------------
UninitAllThreads
Deletes our entire linked list of allocations. Note that we
can only call TlsSetValue on the current thread, not others.
However, this function will invalidate any pointers in other
threads so this function should NEVER be called until process
close.
-------------------------------*/
void UninitAllThreads(void)
{
struct MEM* current;
struct MEM* next;
__try
{
EnterCriticalSection(&g_csThreads);
current = m_memHead;
while (current != NULL)
{
next = current->next;
GodotHeapFree(current->alloc);
GodotHeapFree(current);
current = next;
}
m_memHead = NULL;
}
__finally
{
LeaveCriticalSection(&g_csThreads);
}
}