/*** *tidtable.c - Access thread data table * * Copyright (c) 1989-1997, 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 * *******************************************************************************/ #if defined (_MT) # if defined(_NTSUBSET_) #include #include #include #include #include #include # endif /* _NTSUBSET_ */ #include #include #include #include #include #include #include #include #include #include unsigned long __tlsindex = 0xffffffff; /**** *_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: * *Exit: * returns on success * calls _amsg_exit on failure * *Uses: * * *Exceptions: * *******************************************************************************/ int __cdecl _mtinit ( void ) { _ptiddata ptd; /* * Initialize the mthread lock data base */ _mtinitlocks(); /* * Allocate a TLS index to maintain pointers to per-thread data */ if ( (__tlsindex = TlsAlloc()) == 0xffffffff ) 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) || !TlsSetValue(__tlsindex, (LPVOID)ptd) ) return FALSE; /* fail to load DLL */ /* * Initialize the per-thread data */ _initptd(ptd); ptd->_tid = GetCurrentThreadId(); ptd->_thandle = (unsigned long)(-1L); 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: * *Exit: * returns * *Uses: * *Exceptions: * *******************************************************************************/ void __cdecl _mtterm ( void ) { /* * Clean up the mthread lock data base */ _mtdeletelocks(); /* * Free up the TLS index * * (Set the variable __tlsindex back to the unused state (-1L).) */ if ( __tlsindex != 0xffffffff ) { TlsFree(__tlsindex); __tlsindex = 0xffffffff; } } /*** *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 _M_MRX000 /* * MIPS per-thread data */ ptd->_MipsPtdDelta = ptd->_MipsPtdEpsilon = -1L ; #endif /* _M_MRX000 */ } /*** *_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; DWORD TL_LastError; TL_LastError = GetLastError(); if ( (ptd = TlsGetValue(__tlsindex)) == NULL ) { /* * no per-thread data structure for this thread. try to create * one. */ if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL) && TlsSetValue(__tlsindex, (LPVOID)ptd) ) { /* * Initialize of per-thread data */ _initptd(ptd); ptd->_tid = GetCurrentThreadId(); ptd->_thandle = (unsigned long)(-1L); } else _amsg_exit(_RT_THREAD); /* write message and die */ } SetLastError(TL_LastError); return(ptd); } /*** *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 = TlsGetValue(__tlsindex ); /* * Free up the _tiddata structure & its malloc-ed buffers. */ if ( ptd ) { 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); _free_crt((void *)ptd); } /* * Zero out the one pointer to the per-thread data block */ TlsSetValue(__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 unsigned long __cdecl __threadhandle( void ) { return( (unsigned long)GetCurrentThread() ); } #endif /* defined (_MT) */