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

  1. /***
  2. *tidtable.c - Access thread data table
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This module contains the following routines for multi-thread
  8. * data support:
  9. *
  10. * _mtinit = Initialize the mthread data
  11. * _getptd = get the pointer to the per-thread data structure for
  12. * the current thread
  13. * _freeptd = free up a per-thread data structure and its
  14. * subordinate structures
  15. * __threadid = return thread ID for the current thread
  16. * __threadhandle = return pseudo-handle for the current thread
  17. *
  18. *Revision History:
  19. * 05-04-90 JCR Translated from ASM to C for portable 32-bit OS/2
  20. * 06-04-90 GJF Changed error message interface.
  21. * 07-02-90 GJF Changed __threadid() for DCR 1024/2012.
  22. * 08-08-90 GJF Removed 32 from API names.
  23. * 10-08-90 GJF New-style function declarators.
  24. * 10-09-90 GJF Thread ids are of type unsigned long! Also, fixed a
  25. * bug in __threadid().
  26. * 10-22-90 GJF Another bug in __threadid().
  27. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  28. * 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
  29. * 05-31-91 GJF Win32 version [_WIN32_].
  30. * 07-18-91 GJF Fixed many silly errors [_WIN32_].
  31. * 09-29-91 GJF Conditionally added _getptd_lk/_getptd1_lk so that
  32. * DEBUG version of mlock doesn't infinitely recurse
  33. * the first time _THREADDATA_LOCK is asserted [_WIN32_].
  34. * 01-30-92 GJF Must init. _pxcptacttab field to _XcptActTab.
  35. * 02-25-92 GJF Initialize _holdrand field to 1.
  36. * 02-13-93 GJF Revised to use TLS API. Also, purged Cruiser support.
  37. * 03-26-93 GJF Initialize ptd->_holdrand to 1L (see thread.c).
  38. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  39. * 04-13-93 SKS Add _mtterm to do multi-thread termination
  40. * Set freed __tlsindex to -1 again to prevent mis-use
  41. * 04-26-93 SKS _mtinit now returns 0 or 1, no longer calls _amsg_exit
  42. * 12-13-93 SKS Add _freeptd(), which frees up the per-thread data
  43. * maintained by the C run-time library.
  44. * 04-12-94 GJF Made definition of __tlsindex conditional on ndef
  45. * DLL_FOR_WIN32S. Also, replaced MTHREAD with _MT.
  46. * 01-10-95 CFW Debug CRT allocs.
  47. * 04-12-95 DAK Added NT kernel support for C++ exceptions
  48. * 04-18-95 SKS Add 5 MIPS per-thread variables.
  49. * 04-25-95 DAK More Kernel EH support
  50. * 05-02-95 SKS add _initptd() to do initialization of per-thread data
  51. * 05-24-95 CFW Add _defnewh.
  52. * 06-12-95 JWM _getptd() now preserves LastError.
  53. * 01-17-97 GJF _freeptd() must free the thread's copy of the
  54. * exception-action table.
  55. * 09-26-97 BWT Fix NTSUBSET
  56. * 02-03-98 GJF Changes for Win64: use uintptr_t type for anything with
  57. * a HANDLE value.
  58. * 04-27-98 GJF Added support for per-thread mbc information.
  59. * 07-28-98 JWM Initialize __pceh (new per-thread data for comerr support).
  60. * 09-03-98 GJF Added support for per-thread locale information.
  61. * 12-04-98 JWM Pulled all comerr support.
  62. * 12-08-98 GJF In _freeptd, fixed several errors in cleaning up the
  63. * threadlocinfo.
  64. * 12-18-98 GJF Fixed one more error in _freeptd.
  65. * 01-18-99 GJF Take care not to free up __ptlocinfo when a thread
  66. * exits.
  67. * 03-16-99 GJF threadlocinfo incorporates more reference counters
  68. * 04-24-99 PML Added __lconv_intl_refcount
  69. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  70. * 11-03-99 RDL Win64 _NTSUBSET_ warning fix.
  71. * 06-08-00 PML No need to keep per-thread mbcinfo in circular linked
  72. * list. Also, don't free mbcinfo if it's also the global
  73. * info (vs7#118174).
  74. * 02-20-01 PML vs7#172586 Avoid _RT_LOCK by preallocating all locks
  75. * that will be required, and returning failure back on
  76. * inability to allocate a lock.
  77. * 06-12-01 BWT ntbug: 414059 - cleanup from mtinit failure
  78. * 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
  79. * 10-16-01 GB Added fiber support
  80. * 12-07-01 BWT NUKE NTSUBSET support and add _getptd_noexit for cases
  81. * when the caller has the ability to return ENOMEM failures.
  82. * 04-02-02 GB VS7#508599 - FLS and TLS routines will always be redirected
  83. * by function pointers.
  84. *
  85. *******************************************************************************/
  86. #if defined(_MT)
  87. #include <sect_attribs.h>
  88. #include <cruntime.h>
  89. #include <oscalls.h>
  90. #include <internal.h>
  91. #include <mtdll.h>
  92. #include <memory.h>
  93. #include <msdos.h>
  94. #include <rterr.h>
  95. #include <stdlib.h>
  96. #include <stddef.h>
  97. #include <dbgint.h>
  98. extern pthreadmbcinfo __ptmbcinfo;
  99. extern threadlocinfo __initiallocinfo;
  100. extern pthreadlocinfo __ptlocinfo;
  101. void __cdecl __freetlocinfo(pthreadlocinfo);
  102. //
  103. // Define Fiber Local Storage function pointers.
  104. //
  105. PFLS_ALLOC_FUNCTION gpFlsAlloc = NULL;
  106. PFLS_GETVALUE_FUNCTION gpFlsGetValue = NULL;
  107. PFLS_SETVALUE_FUNCTION gpFlsSetValue = NULL;
  108. PFLS_FREE_FUNCTION gpFlsFree = NULL;
  109. unsigned long __tlsindex = 0xffffffff;
  110. /***
  111. * __crtTlsAlloc - crt wrapper around TlsAlloc
  112. *
  113. * Purpose:
  114. * (1) Call to __crtTlsAlloc should look like call to FlsAlloc, this will
  115. * Help in redirecting the call to TlsAlloc and FlsAlloc using same
  116. * redirection variable.
  117. *******************************************************************************/
  118. DWORD WINAPI __crtTlsAlloc( PFLS_CALLBACK_FUNCTION lpCallBack)
  119. {
  120. return TlsAlloc( );
  121. }
  122. /****
  123. *_mtinit() - Init multi-thread data bases
  124. *
  125. *Purpose:
  126. * (1) Call _mtinitlocks to create/open all lock semaphores.
  127. * (2) Allocate a TLS index to hold pointers to per-thread data
  128. * structure.
  129. *
  130. * NOTES:
  131. * (1) Only to be called ONCE at startup
  132. * (2) Must be called BEFORE any mthread requests are made
  133. *
  134. *Entry:
  135. * <NONE>
  136. *Exit:
  137. * returns FALSE on failure
  138. *
  139. *Uses:
  140. * <any registers may be modified at init time>
  141. *
  142. *Exceptions:
  143. *
  144. *******************************************************************************/
  145. int __cdecl _mtinit (
  146. void
  147. )
  148. {
  149. _ptiddata ptd;
  150. HINSTANCE hKernel32;
  151. /*
  152. * Initialize the mthread lock data base
  153. */
  154. if ( !_mtinitlocks() ) {
  155. _mtterm();
  156. return FALSE; /* fail to load DLL */
  157. }
  158. /*
  159. * Initialize fiber local storage function pointers.
  160. */
  161. hKernel32 = GetModuleHandle("kernel32.dll");
  162. if (hKernel32 != NULL) {
  163. gpFlsAlloc = (PFLS_ALLOC_FUNCTION)GetProcAddress(hKernel32,
  164. "FlsAlloc");
  165. gpFlsGetValue = (PFLS_GETVALUE_FUNCTION)GetProcAddress(hKernel32,
  166. "FlsGetValue");
  167. gpFlsSetValue = (PFLS_SETVALUE_FUNCTION)GetProcAddress(hKernel32,
  168. "FlsSetValue");
  169. gpFlsFree = (PFLS_FREE_FUNCTION)GetProcAddress(hKernel32,
  170. "FlsFree");
  171. if (!gpFlsAlloc || !gpFlsGetValue || !gpFlsSetValue || !gpFlsFree) {
  172. gpFlsAlloc = (PFLS_ALLOC_FUNCTION)__crtTlsAlloc;
  173. gpFlsGetValue = (PFLS_GETVALUE_FUNCTION)TlsGetValue;
  174. gpFlsSetValue = (PFLS_SETVALUE_FUNCTION)TlsSetValue;
  175. gpFlsFree = (PFLS_FREE_FUNCTION)TlsFree;
  176. }
  177. }
  178. /*
  179. * Allocate a TLS index to maintain pointers to per-thread data
  180. */
  181. if ( (__tlsindex = FLS_ALLOC(&_freefls)) == 0xffffffff ) {
  182. _mtterm();
  183. return FALSE; /* fail to load DLL */
  184. }
  185. /*
  186. * Create a per-thread data structure for this (i.e., the startup)
  187. * thread.
  188. */
  189. if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL) ||
  190. !FLS_SETVALUE(__tlsindex, (LPVOID)ptd) )
  191. {
  192. _mtterm();
  193. return FALSE; /* fail to load DLL */
  194. }
  195. /*
  196. * Initialize the per-thread data
  197. */
  198. _initptd(ptd);
  199. ptd->_tid = GetCurrentThreadId();
  200. ptd->_thandle = (uintptr_t)(-1);
  201. return TRUE;
  202. }
  203. /****
  204. *_mtterm() - Clean-up multi-thread data bases
  205. *
  206. *Purpose:
  207. * (1) Call _mtdeletelocks to free up all lock semaphores.
  208. * (2) Free up the TLS index used to hold pointers to
  209. * per-thread data structure.
  210. *
  211. * NOTES:
  212. * (1) Only to be called ONCE at termination
  213. * (2) Must be called AFTER all mthread requests are made
  214. *
  215. *Entry:
  216. * <NONE>
  217. *Exit:
  218. * returns
  219. *
  220. *Uses:
  221. *
  222. *Exceptions:
  223. *
  224. *******************************************************************************/
  225. void __cdecl _mtterm (
  226. void
  227. )
  228. {
  229. /*
  230. * Free up the TLS index
  231. *
  232. * (Set the variable __tlsindex back to the unused state (-1L).)
  233. */
  234. if ( __tlsindex != 0xffffffff ) {
  235. FLS_FREE(__tlsindex);
  236. __tlsindex = 0xffffffff;
  237. }
  238. /*
  239. * Clean up the mthread lock data base
  240. */
  241. _mtdeletelocks();
  242. }
  243. /***
  244. *void _initptd(_ptiddata ptd) - initialize a per-thread data structure
  245. *
  246. *Purpose:
  247. * This routine handles all of the per-thread initialization
  248. * which is common to _beginthread, _beginthreadex, _mtinit
  249. * and _getptd.
  250. *
  251. *Entry:
  252. * pointer to a per-thread data block
  253. *
  254. *Exit:
  255. * the common fields in that block are initialized
  256. *
  257. *Exceptions:
  258. *
  259. *******************************************************************************/
  260. void __cdecl _initptd (
  261. _ptiddata ptd
  262. )
  263. {
  264. ptd->_pxcptacttab = (void *)_XcptActTab;
  265. ptd->_holdrand = 1L;
  266. #ifdef ANSI_NEW_HANDLER
  267. ptd->_newh = _defnewh;
  268. #endif /* ANSI_NEW_HANDLER */
  269. }
  270. /***
  271. *_ptiddata _getptd_noexit(void) - get per-thread data structure for the current thread
  272. *
  273. *Purpose:
  274. *
  275. *Entry:
  276. *
  277. *Exit:
  278. * success = pointer to _tiddata structure for the thread
  279. * failure = NULL
  280. *
  281. *Exceptions:
  282. *
  283. *******************************************************************************/
  284. _ptiddata __cdecl _getptd_noexit (
  285. void
  286. )
  287. {
  288. _ptiddata ptd;
  289. DWORD TL_LastError;
  290. TL_LastError = GetLastError();
  291. if ( (ptd = FLS_GETVALUE(__tlsindex)) == NULL ) {
  292. /*
  293. * no per-thread data structure for this thread. try to create
  294. * one.
  295. */
  296. if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL) &&
  297. FLS_SETVALUE(__tlsindex, (LPVOID)ptd) ) {
  298. /*
  299. * Initialize of per-thread data
  300. */
  301. _initptd(ptd);
  302. ptd->_tid = GetCurrentThreadId();
  303. ptd->_thandle = (uintptr_t)(-1);
  304. }
  305. }
  306. SetLastError(TL_LastError);
  307. return(ptd);
  308. }
  309. /***
  310. *_ptiddata _getptd(void) - get per-thread data structure for the current thread
  311. *
  312. *Purpose:
  313. *
  314. *Entry:
  315. * unsigned long tid
  316. *
  317. *Exit:
  318. * success = pointer to _tiddata structure for the thread
  319. * failure = fatal runtime exit
  320. *
  321. *Exceptions:
  322. *
  323. *******************************************************************************/
  324. _ptiddata __cdecl _getptd (
  325. void
  326. )
  327. {
  328. _ptiddata ptd = _getptd_noexit();
  329. if (!ptd) {
  330. _amsg_exit(_RT_THREAD); /* write message and die */
  331. }
  332. return ptd;
  333. }
  334. /***
  335. *void WINAPI _freefls(void *) - free up a per-fiber data structure
  336. *
  337. *Purpose:
  338. * Called from _freeptd, as a callback from deleting a fiber, and
  339. * from deleting an FLS index. This routine frees up the per-fiber
  340. * buffer associated with a fiber that is going away. The tiddata
  341. * structure itself is freed, but not until its subordinate buffers
  342. * are freed.
  343. *
  344. *Entry:
  345. * pointer to a per-fiber data block (malloc-ed memory)
  346. *
  347. *Exit:
  348. *
  349. *Exceptions:
  350. *
  351. *******************************************************************************/
  352. void
  353. WINAPI
  354. _freefls (
  355. void *data
  356. )
  357. {
  358. _ptiddata ptd;
  359. pthreadlocinfo ptloci;
  360. pthreadmbcinfo ptmbci;
  361. /*
  362. * Free up the _tiddata structure & its malloc-ed buffers.
  363. */
  364. ptd = data;
  365. if (ptd != NULL) {
  366. if(ptd->_errmsg)
  367. _free_crt((void *)ptd->_errmsg);
  368. if(ptd->_namebuf0)
  369. _free_crt((void *)ptd->_namebuf0);
  370. if(ptd->_namebuf1)
  371. _free_crt((void *)ptd->_namebuf1);
  372. if(ptd->_asctimebuf)
  373. _free_crt((void *)ptd->_asctimebuf);
  374. if(ptd->_gmtimebuf)
  375. _free_crt((void *)ptd->_gmtimebuf);
  376. if(ptd->_cvtbuf)
  377. _free_crt((void *)ptd->_cvtbuf);
  378. if (ptd->_pxcptacttab != _XcptActTab)
  379. _free_crt((void *)ptd->_pxcptacttab);
  380. _mlock(_MB_CP_LOCK);
  381. __try {
  382. if ( ((ptmbci = ptd->ptmbcinfo) != NULL) &&
  383. (--(ptmbci->refcount) == 0) &&
  384. (ptmbci != __ptmbcinfo) )
  385. _free_crt(ptmbci);
  386. }
  387. __finally {
  388. _munlock(_MB_CP_LOCK);
  389. }
  390. _mlock(_SETLOCALE_LOCK);
  391. __try {
  392. if ( (ptloci = ptd->ptlocinfo) != NULL )
  393. {
  394. (ptloci->refcount)--;
  395. if ( ptloci->lconv_intl_refcount != NULL )
  396. (*(ptloci->lconv_intl_refcount))--;
  397. if ( ptloci->lconv_mon_refcount != NULL )
  398. (*(ptloci->lconv_mon_refcount))--;
  399. if ( ptloci->lconv_num_refcount != NULL )
  400. (*(ptloci->lconv_num_refcount))--;
  401. if ( ptloci->ctype1_refcount != NULL )
  402. (*(ptloci->ctype1_refcount))--;
  403. (ptloci->lc_time_curr->refcount)--;
  404. if ( (ptloci != __ptlocinfo) &&
  405. (ptloci != &__initiallocinfo) &&
  406. (ptloci->refcount == 0) )
  407. __freetlocinfo(ptloci);
  408. }
  409. }
  410. __finally {
  411. _munlock(_SETLOCALE_LOCK);
  412. }
  413. _free_crt((void *)ptd);
  414. }
  415. return;
  416. }
  417. /***
  418. *void _freeptd(_ptiddata) - free up a per-thread data structure
  419. *
  420. *Purpose:
  421. * Called from _endthread and from a DLL thread detach handler,
  422. * this routine frees up the per-thread buffer associated with a
  423. * thread that is going away. The tiddata structure itself is
  424. * freed, but not until its subordinate buffers are freed.
  425. *
  426. *Entry:
  427. * pointer to a per-thread data block (malloc-ed memory)
  428. * If NULL, the pointer for the current thread is fetched.
  429. *
  430. *Exit:
  431. *
  432. *Exceptions:
  433. *
  434. *******************************************************************************/
  435. void __cdecl _freeptd (
  436. _ptiddata ptd
  437. )
  438. {
  439. /*
  440. * Do nothing unless per-thread data has been allocated for this module!
  441. */
  442. if ( __tlsindex != 0xFFFFFFFF ) {
  443. /*
  444. * if parameter "ptd" is NULL, get the per-thread data pointer
  445. * Must NOT call _getptd because it will allocate one if none exists!
  446. */
  447. if ( ! ptd )
  448. ptd = FLS_GETVALUE(__tlsindex );
  449. _freefls(ptd);
  450. /*
  451. * Zero out the one pointer to the per-thread data block
  452. */
  453. FLS_SETVALUE(__tlsindex, (LPVOID)0);
  454. }
  455. }
  456. /***
  457. *__threadid() - Returns current thread ID
  458. *__threadhandle() - Returns "pseudo-handle" for current thread
  459. *
  460. *Purpose:
  461. * The two function are simply do-nothing wrappers for the corresponding
  462. * Win32 APIs (GetCurrentThreadId and GetCurrentThread, respectively).
  463. *
  464. *Entry:
  465. * void
  466. *
  467. *Exit:
  468. * thread ID value
  469. *
  470. *Exceptions:
  471. *
  472. *******************************************************************************/
  473. _CRTIMP unsigned long __cdecl __threadid (
  474. void
  475. )
  476. {
  477. return( GetCurrentThreadId() );
  478. }
  479. _CRTIMP uintptr_t __cdecl __threadhandle(
  480. void
  481. )
  482. {
  483. return( (uintptr_t)GetCurrentThread() );
  484. }
  485. #endif