Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

571 lines
16 KiB

/***
*tidtable.c - Access thread data table
*
* Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
*
*Purpose:
* This module contains the following routines for multi-thread
* data support:
*
* _mtinit = Initialize the mthread data
* _getptd = get the pointer to the per-thread data structure for
* the current thread
* _freeptd = free up a per-thread data structure and its
* subordinate structures
* __threadid = return thread ID for the current thread
* __threadhandle = return pseudo-handle for the current thread
*
*Revision History:
* 05-04-90 JCR Translated from ASM to C for portable 32-bit OS/2
* 06-04-90 GJF Changed error message interface.
* 07-02-90 GJF Changed __threadid() for DCR 1024/2012.
* 08-08-90 GJF Removed 32 from API names.
* 10-08-90 GJF New-style function declarators.
* 10-09-90 GJF Thread ids are of type unsigned long! Also, fixed a
* bug in __threadid().
* 10-22-90 GJF Another bug in __threadid().
* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
* 05-31-91 GJF Win32 version [_WIN32_].
* 07-18-91 GJF Fixed many silly errors [_WIN32_].
* 09-29-91 GJF Conditionally added _getptd_lk/_getptd1_lk so that
* DEBUG version of mlock doesn't infinitely recurse
* the first time _THREADDATA_LOCK is asserted [_WIN32_].
* 01-30-92 GJF Must init. _pxcptacttab field to _XcptActTab.
* 02-25-92 GJF Initialize _holdrand field to 1.
* 02-13-93 GJF Revised to use TLS API. Also, purged Cruiser support.
* 03-26-93 GJF Initialize ptd->_holdrand to 1L (see thread.c).
* 04-06-93 SKS Replace _CRTAPI* with __cdecl
* 04-13-93 SKS Add _mtterm to do multi-thread termination
* Set freed __tlsindex to -1 again to prevent mis-use
* 04-26-93 SKS _mtinit now returns 0 or 1, no longer calls _amsg_exit
* 12-13-93 SKS Add _freeptd(), which frees up the per-thread data
* maintained by the C run-time library.
* 04-12-94 GJF Made definition of __tlsindex conditional on ndef
* DLL_FOR_WIN32S. Also, replaced MTHREAD with _MT.
* 01-10-95 CFW Debug CRT allocs.
* 04-12-95 DAK Added NT kernel support for C++ exceptions
* 04-18-95 SKS Add 5 MIPS per-thread variables.
* 04-25-95 DAK More Kernel EH support
* 05-02-95 SKS add _initptd() to do initialization of per-thread data
* 05-24-95 CFW Add _defnewh.
* 06-12-95 JWM _getptd() now preserves LastError.
* 01-17-97 GJF _freeptd() must free the thread's copy of the
* exception-action table.
* 09-26-97 BWT Fix NTSUBSET
* 02-03-98 GJF Changes for Win64: use uintptr_t type for anything with
* a HANDLE value.
* 04-27-98 GJF Added support for per-thread mbc information.
* 07-28-98 JWM Initialize __pceh (new per-thread data for comerr support).
* 09-03-98 GJF Added support for per-thread locale information.
* 12-04-98 JWM Pulled all comerr support.
* 12-08-98 GJF In _freeptd, fixed several errors in cleaning up the
* threadlocinfo.
* 12-18-98 GJF Fixed one more error in _freeptd.
* 01-18-99 GJF Take care not to free up __ptlocinfo when a thread
* exits.
* 03-16-99 GJF threadlocinfo incorporates more reference counters
* 04-24-99 PML Added __lconv_intl_refcount
* 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
* 11-03-99 RDL Win64 _NTSUBSET_ warning fix.
* 06-08-00 PML No need to keep per-thread mbcinfo in circular linked
* list. Also, don't free mbcinfo if it's also the global
* info (vs7#118174).
* 02-20-01 PML vs7#172586 Avoid _RT_LOCK by preallocating all locks
* that will be required, and returning failure back on
* inability to allocate a lock.
* 06-12-01 BWT ntbug: 414059 - cleanup from mtinit failure
* 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
* 10-16-01 GB Added fiber support
* 12-07-01 BWT NUKE NTSUBSET support and add _getptd_noexit for cases
* when the caller has the ability to return ENOMEM failures.
* 04-02-02 GB VS7#508599 - FLS and TLS routines will always be redirected
* by function pointers.
*
*******************************************************************************/
#if defined(_MT)
#include <sect_attribs.h>
#include <cruntime.h>
#include <oscalls.h>
#include <internal.h>
#include <mtdll.h>
#include <memory.h>
#include <msdos.h>
#include <rterr.h>
#include <stdlib.h>
#include <stddef.h>
#include <dbgint.h>
extern pthreadmbcinfo __ptmbcinfo;
extern threadlocinfo __initiallocinfo;
extern pthreadlocinfo __ptlocinfo;
void __cdecl __freetlocinfo(pthreadlocinfo);
//
// Define Fiber Local Storage function pointers.
//
PFLS_ALLOC_FUNCTION gpFlsAlloc = NULL;
PFLS_GETVALUE_FUNCTION gpFlsGetValue = NULL;
PFLS_SETVALUE_FUNCTION gpFlsSetValue = NULL;
PFLS_FREE_FUNCTION gpFlsFree = NULL;
unsigned long __tlsindex = 0xffffffff;
/***
* __crtTlsAlloc - crt wrapper around TlsAlloc
*
* Purpose:
* (1) Call to __crtTlsAlloc should look like call to FlsAlloc, this will
* Help in redirecting the call to TlsAlloc and FlsAlloc using same
* redirection variable.
*******************************************************************************/
DWORD WINAPI __crtTlsAlloc( PFLS_CALLBACK_FUNCTION lpCallBack)
{
return TlsAlloc( );
}
/****
*_mtinit() - Init multi-thread data bases
*
*Purpose:
* (1) Call _mtinitlocks to create/open all lock semaphores.
* (2) Allocate a TLS index to hold pointers to per-thread data
* structure.
*
* NOTES:
* (1) Only to be called ONCE at startup
* (2) Must be called BEFORE any mthread requests are made
*
*Entry:
* <NONE>
*Exit:
* returns FALSE on failure
*
*Uses:
* <any registers may be modified at init time>
*
*Exceptions:
*
*******************************************************************************/
int __cdecl _mtinit (
void
)
{
_ptiddata ptd;
HINSTANCE hKernel32;
/*
* Initialize the mthread lock data base
*/
if ( !_mtinitlocks() ) {
_mtterm();
return FALSE; /* fail to load DLL */
}
/*
* Initialize fiber local storage function pointers.
*/
hKernel32 = GetModuleHandle("kernel32.dll");
if (hKernel32 != NULL) {
gpFlsAlloc = (PFLS_ALLOC_FUNCTION)GetProcAddress(hKernel32,
"FlsAlloc");
gpFlsGetValue = (PFLS_GETVALUE_FUNCTION)GetProcAddress(hKernel32,
"FlsGetValue");
gpFlsSetValue = (PFLS_SETVALUE_FUNCTION)GetProcAddress(hKernel32,
"FlsSetValue");
gpFlsFree = (PFLS_FREE_FUNCTION)GetProcAddress(hKernel32,
"FlsFree");
if (!gpFlsAlloc || !gpFlsGetValue || !gpFlsSetValue || !gpFlsFree) {
gpFlsAlloc = (PFLS_ALLOC_FUNCTION)__crtTlsAlloc;
gpFlsGetValue = (PFLS_GETVALUE_FUNCTION)TlsGetValue;
gpFlsSetValue = (PFLS_SETVALUE_FUNCTION)TlsSetValue;
gpFlsFree = (PFLS_FREE_FUNCTION)TlsFree;
}
}
/*
* Allocate a TLS index to maintain pointers to per-thread data
*/
if ( (__tlsindex = FLS_ALLOC(&_freefls)) == 0xffffffff ) {
_mtterm();
return FALSE; /* fail to load DLL */
}
/*
* Create a per-thread data structure for this (i.e., the startup)
* thread.
*/
if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL) ||
!FLS_SETVALUE(__tlsindex, (LPVOID)ptd) )
{
_mtterm();
return FALSE; /* fail to load DLL */
}
/*
* Initialize the per-thread data
*/
_initptd(ptd);
ptd->_tid = GetCurrentThreadId();
ptd->_thandle = (uintptr_t)(-1);
return TRUE;
}
/****
*_mtterm() - Clean-up multi-thread data bases
*
*Purpose:
* (1) Call _mtdeletelocks to free up all lock semaphores.
* (2) Free up the TLS index used to hold pointers to
* per-thread data structure.
*
* NOTES:
* (1) Only to be called ONCE at termination
* (2) Must be called AFTER all mthread requests are made
*
*Entry:
* <NONE>
*Exit:
* returns
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _mtterm (
void
)
{
/*
* Free up the TLS index
*
* (Set the variable __tlsindex back to the unused state (-1L).)
*/
if ( __tlsindex != 0xffffffff ) {
FLS_FREE(__tlsindex);
__tlsindex = 0xffffffff;
}
/*
* Clean up the mthread lock data base
*/
_mtdeletelocks();
}
/***
*void _initptd(_ptiddata ptd) - initialize a per-thread data structure
*
*Purpose:
* This routine handles all of the per-thread initialization
* which is common to _beginthread, _beginthreadex, _mtinit
* and _getptd.
*
*Entry:
* pointer to a per-thread data block
*
*Exit:
* the common fields in that block are initialized
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _initptd (
_ptiddata ptd
)
{
ptd->_pxcptacttab = (void *)_XcptActTab;
ptd->_holdrand = 1L;
#ifdef ANSI_NEW_HANDLER
ptd->_newh = _defnewh;
#endif /* ANSI_NEW_HANDLER */
}
/***
*_ptiddata _getptd_noexit(void) - get per-thread data structure for the current thread
*
*Purpose:
*
*Entry:
*
*Exit:
* success = pointer to _tiddata structure for the thread
* failure = NULL
*
*Exceptions:
*
*******************************************************************************/
_ptiddata __cdecl _getptd_noexit (
void
)
{
_ptiddata ptd;
DWORD TL_LastError;
TL_LastError = GetLastError();
if ( (ptd = FLS_GETVALUE(__tlsindex)) == NULL ) {
/*
* no per-thread data structure for this thread. try to create
* one.
*/
if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL) &&
FLS_SETVALUE(__tlsindex, (LPVOID)ptd) ) {
/*
* Initialize of per-thread data
*/
_initptd(ptd);
ptd->_tid = GetCurrentThreadId();
ptd->_thandle = (uintptr_t)(-1);
}
}
SetLastError(TL_LastError);
return(ptd);
}
/***
*_ptiddata _getptd(void) - get per-thread data structure for the current thread
*
*Purpose:
*
*Entry:
* unsigned long tid
*
*Exit:
* success = pointer to _tiddata structure for the thread
* failure = fatal runtime exit
*
*Exceptions:
*
*******************************************************************************/
_ptiddata __cdecl _getptd (
void
)
{
_ptiddata ptd = _getptd_noexit();
if (!ptd) {
_amsg_exit(_RT_THREAD); /* write message and die */
}
return ptd;
}
/***
*void WINAPI _freefls(void *) - free up a per-fiber data structure
*
*Purpose:
* Called from _freeptd, as a callback from deleting a fiber, and
* from deleting an FLS index. This routine frees up the per-fiber
* buffer associated with a fiber that is going away. The tiddata
* structure itself is freed, but not until its subordinate buffers
* are freed.
*
*Entry:
* pointer to a per-fiber data block (malloc-ed memory)
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void
WINAPI
_freefls (
void *data
)
{
_ptiddata ptd;
pthreadlocinfo ptloci;
pthreadmbcinfo ptmbci;
/*
* Free up the _tiddata structure & its malloc-ed buffers.
*/
ptd = data;
if (ptd != NULL) {
if(ptd->_errmsg)
_free_crt((void *)ptd->_errmsg);
if(ptd->_namebuf0)
_free_crt((void *)ptd->_namebuf0);
if(ptd->_namebuf1)
_free_crt((void *)ptd->_namebuf1);
if(ptd->_asctimebuf)
_free_crt((void *)ptd->_asctimebuf);
if(ptd->_gmtimebuf)
_free_crt((void *)ptd->_gmtimebuf);
if(ptd->_cvtbuf)
_free_crt((void *)ptd->_cvtbuf);
if (ptd->_pxcptacttab != _XcptActTab)
_free_crt((void *)ptd->_pxcptacttab);
_mlock(_MB_CP_LOCK);
__try {
if ( ((ptmbci = ptd->ptmbcinfo) != NULL) &&
(--(ptmbci->refcount) == 0) &&
(ptmbci != __ptmbcinfo) )
_free_crt(ptmbci);
}
__finally {
_munlock(_MB_CP_LOCK);
}
_mlock(_SETLOCALE_LOCK);
__try {
if ( (ptloci = ptd->ptlocinfo) != NULL )
{
(ptloci->refcount)--;
if ( ptloci->lconv_intl_refcount != NULL )
(*(ptloci->lconv_intl_refcount))--;
if ( ptloci->lconv_mon_refcount != NULL )
(*(ptloci->lconv_mon_refcount))--;
if ( ptloci->lconv_num_refcount != NULL )
(*(ptloci->lconv_num_refcount))--;
if ( ptloci->ctype1_refcount != NULL )
(*(ptloci->ctype1_refcount))--;
(ptloci->lc_time_curr->refcount)--;
if ( (ptloci != __ptlocinfo) &&
(ptloci != &__initiallocinfo) &&
(ptloci->refcount == 0) )
__freetlocinfo(ptloci);
}
}
__finally {
_munlock(_SETLOCALE_LOCK);
}
_free_crt((void *)ptd);
}
return;
}
/***
*void _freeptd(_ptiddata) - free up a per-thread data structure
*
*Purpose:
* Called from _endthread and from a DLL thread detach handler,
* this routine frees up the per-thread buffer associated with a
* thread that is going away. The tiddata structure itself is
* freed, but not until its subordinate buffers are freed.
*
*Entry:
* pointer to a per-thread data block (malloc-ed memory)
* If NULL, the pointer for the current thread is fetched.
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _freeptd (
_ptiddata ptd
)
{
/*
* Do nothing unless per-thread data has been allocated for this module!
*/
if ( __tlsindex != 0xFFFFFFFF ) {
/*
* if parameter "ptd" is NULL, get the per-thread data pointer
* Must NOT call _getptd because it will allocate one if none exists!
*/
if ( ! ptd )
ptd = FLS_GETVALUE(__tlsindex );
_freefls(ptd);
/*
* Zero out the one pointer to the per-thread data block
*/
FLS_SETVALUE(__tlsindex, (LPVOID)0);
}
}
/***
*__threadid() - Returns current thread ID
*__threadhandle() - Returns "pseudo-handle" for current thread
*
*Purpose:
* The two function are simply do-nothing wrappers for the corresponding
* Win32 APIs (GetCurrentThreadId and GetCurrentThread, respectively).
*
*Entry:
* void
*
*Exit:
* thread ID value
*
*Exceptions:
*
*******************************************************************************/
_CRTIMP unsigned long __cdecl __threadid (
void
)
{
return( GetCurrentThreadId() );
}
_CRTIMP uintptr_t __cdecl __threadhandle(
void
)
{
return( (uintptr_t)GetCurrentThread() );
}
#endif