Source code of Windows XP (NT5)
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.

689 lines
19 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. *
  79. *******************************************************************************/
  80. #if defined(_MT) || defined(_NTSUBSET_)
  81. # if defined(_NTSUBSET_)
  82. #include <nt.h>
  83. #include <ntrtl.h>
  84. #include <nturtl.h>
  85. #include <ntstatus.h>
  86. #include <ntos.h>
  87. #include <fsrtl.h>
  88. # endif /* _NTSUBSET_ */
  89. #include <sect_attribs.h>
  90. #include <cruntime.h>
  91. #include <oscalls.h>
  92. #include <internal.h>
  93. #include <mtdll.h>
  94. #include <memory.h>
  95. #include <msdos.h>
  96. #include <rterr.h>
  97. #include <stdlib.h>
  98. #include <stddef.h>
  99. #include <dbgint.h>
  100. #ifdef _MT
  101. extern pthreadmbcinfo __ptmbcinfo;
  102. extern threadlocinfo __initiallocinfo;
  103. extern pthreadlocinfo __ptlocinfo;
  104. void __cdecl __freetlocinfo(pthreadlocinfo);
  105. #endif
  106. unsigned long __tlsindex = 0xffffffff;
  107. #if defined(_NTSUBSET_)
  108. #define BEGIN_NONPAGED_CODE code_seg(".text")
  109. #define END_NONPAGED_CODE code_seg("PAGE")
  110. static _ptiddata pTheKernelExceptionContextPool;
  111. static KSPIN_LOCK TheKernelExceptionContextPoolLock;
  112. /****
  113. *_initKernelExceptionContextPool() - creates kernel-mode exception context pool
  114. *
  115. *Purpose:
  116. * (1) Initializes spin-lock used to serialize access to pool
  117. *
  118. *Entry:
  119. * <NONE>
  120. *Exit:
  121. * <NONE>
  122. *
  123. *
  124. *******************************************************************************/
  125. #pragma BEGIN_NONPAGED_CODE
  126. void __cdecl _initKernelExceptionContextPool(void)
  127. {
  128. KeInitializeSpinLock( &TheKernelExceptionContextPoolLock );
  129. }
  130. #pragma END_NONPAGED_CODE
  131. /****
  132. * Tell the linker to insert a call to this function into the CRT runtime
  133. * startup.
  134. *
  135. * The segment .CRT$XCA is the first data segment bounding the array
  136. * of CRT startup functions. We therefore insert our function between
  137. * the first (.CRT$XCA) and the last (.CRT$XCZ).
  138. *
  139. *******************************************************************************/
  140. #pragma data_seg(".CRT$XCAA")
  141. typedef void (__cdecl *PFStartup)(void);
  142. _CRTALLOC(".CRT$XCAA") PFStartup _KernelECPool = _initKernelExceptionContextPool;
  143. #pragma data_seg(".CRT$XCZ")
  144. #pragma data_seg()
  145. /****
  146. *_emptyKernelExceptionContextPool() - empties kernel-mode exception context pool
  147. *
  148. *Purpose:
  149. * (1) Deletes all entries in the pool
  150. *
  151. *Entry:
  152. * <NONE>
  153. *Exit:
  154. * <NONE>
  155. *
  156. *
  157. *******************************************************************************/
  158. #pragma BEGIN_NONPAGED_CODE
  159. void _emptyKernelExceptionContextPool()
  160. {
  161. while ( pTheKernelExceptionContextPool != 0 ) {
  162. _ptiddata ptd = pTheKernelExceptionContextPool;
  163. pTheKernelExceptionContextPool = pTheKernelExceptionContextPool->_next;
  164. ExFreePool( ptd );
  165. }
  166. }
  167. #pragma END_NONPAGED_CODE
  168. /****
  169. *_newKernelTid() - Creates, initializes and sets the current thread's
  170. * OfsChain to _tiddata;
  171. *
  172. *Purpose:
  173. * (1) Creates a new kernel-mode _tiddata
  174. * (2) Initializes fields in new _tiddata
  175. * (3) Sets current thread's OfsChain to new _tiddata
  176. *
  177. * NOTES:
  178. * (1) Can not fail; the memory allocation will cause a fatal system
  179. * trap if memory can not be allocated
  180. *
  181. *Entry:
  182. * <NONE>
  183. *Exit:
  184. * _ptiddata
  185. *
  186. *******************************************************************************/
  187. #pragma BEGIN_NONPAGED_CODE
  188. static _ptiddata _newKernelTid(void)
  189. {
  190. /*
  191. * Pop an entry from the pool of _ptiddata's
  192. */
  193. _ptiddata ptd;
  194. PSINGLE_LIST_ENTRY entry;
  195. entry = ExInterlockedPopEntryList((PSINGLE_LIST_ENTRY) & pTheKernelExceptionContextPool,
  196. & TheKernelExceptionContextPoolLock );
  197. /*
  198. * If none are available, create a new one.
  199. */
  200. if ( 0 == entry ) {
  201. ptd = FsRtlAllocatePoolWithTag( NonPagedPoolMustSucceed,
  202. sizeof(struct _tiddata),
  203. ' dtp' );
  204. } else {
  205. ptd = CONTAINING_RECORD( entry, struct _tiddata, _next );
  206. }
  207. ptd->_tid = (unsigned long) (uintptr_t) PsGetCurrentThread()->Cid.UniqueThread;
  208. ptd->_terminate = 0;
  209. ptd->_unexpected = 0;
  210. ptd->_translator = SystemExceptionTranslator;
  211. ptd->_curexception = 0;
  212. ptd->_curcontext = 0;
  213. PsGetCurrentThread()->OfsChain = ptd;
  214. return ptd;
  215. }
  216. #pragma END_NONPAGED_CODE
  217. /****
  218. *_freeKernelTid() - appends the _tiddata to the pool
  219. *
  220. *Entry:
  221. * _ptiddata
  222. *Exit:
  223. *
  224. *******************************************************************************/
  225. #pragma BEGIN_NONPAGED_CODE
  226. static void _freeKernelTid(_ptiddata ptd)
  227. {
  228. /*
  229. * Return the entry to the kernel pool
  230. */
  231. ExInterlockedPushEntryList( (PSINGLE_LIST_ENTRY) &pTheKernelExceptionContextPool,
  232. (PSINGLE_LIST_ENTRY) &ptd->_next,
  233. &TheKernelExceptionContextPoolLock );
  234. }
  235. #pragma END_NONPAGED_CODE
  236. #endif /* _NTSUBSET_ */
  237. /****
  238. *_mtinit() - Init multi-thread data bases
  239. *
  240. *Purpose:
  241. * (1) Call _mtinitlocks to create/open all lock semaphores.
  242. * (2) Allocate a TLS index to hold pointers to per-thread data
  243. * structure.
  244. *
  245. * NOTES:
  246. * (1) Only to be called ONCE at startup
  247. * (2) Must be called BEFORE any mthread requests are made
  248. *
  249. *Entry:
  250. * <NONE>
  251. *Exit:
  252. * returns FALSE on failure
  253. *
  254. *Uses:
  255. * <any registers may be modified at init time>
  256. *
  257. *Exceptions:
  258. *
  259. *******************************************************************************/
  260. #if defined(_NTSUBSET_)
  261. #pragma BEGIN_NONPAGED_CODE
  262. #endif
  263. int __cdecl _mtinit (
  264. void
  265. )
  266. {
  267. _ptiddata ptd;
  268. #if defined(_NTSUBSET_)
  269. ptd = _newKernelTid();
  270. #else
  271. /*
  272. * Initialize the mthread lock data base
  273. */
  274. if ( !_mtinitlocks() ) {
  275. _mtterm();
  276. return FALSE; /* fail to load DLL */
  277. }
  278. /*
  279. * Allocate a TLS index to maintain pointers to per-thread data
  280. */
  281. if ( (__tlsindex = TlsAlloc()) == 0xffffffff ) {
  282. _mtterm();
  283. return FALSE; /* fail to load DLL */
  284. }
  285. /*
  286. * Create a per-thread data structure for this (i.e., the startup)
  287. * thread.
  288. */
  289. if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL) ||
  290. !TlsSetValue(__tlsindex, (LPVOID)ptd) )
  291. {
  292. _mtterm();
  293. return FALSE; /* fail to load DLL */
  294. }
  295. /*
  296. * Initialize the per-thread data
  297. */
  298. _initptd(ptd);
  299. ptd->_tid = GetCurrentThreadId();
  300. ptd->_thandle = (uintptr_t)(-1);
  301. #endif /* _NTSUBSET_ */
  302. return TRUE;
  303. }
  304. /****
  305. *_mtterm() - Clean-up multi-thread data bases
  306. *
  307. *Purpose:
  308. * (1) Call _mtdeletelocks to free up all lock semaphores.
  309. * (2) Free up the TLS index used to hold pointers to
  310. * per-thread data structure.
  311. *
  312. * NOTES:
  313. * (1) Only to be called ONCE at termination
  314. * (2) Must be called AFTER all mthread requests are made
  315. *
  316. *Entry:
  317. * <NONE>
  318. *Exit:
  319. * returns
  320. *
  321. *Uses:
  322. *
  323. *Exceptions:
  324. *
  325. *******************************************************************************/
  326. void __cdecl _mtterm (
  327. void
  328. )
  329. {
  330. #if defined(_NTSUBSET_)
  331. _freeKernelTid( PsGetCurrentThread()->OfsChain );
  332. PsGetCurrentThread()->OfsChain = 0;
  333. #else /* _NTSUBSET_ */
  334. /*
  335. * Clean up the mthread lock data base
  336. */
  337. _mtdeletelocks();
  338. /*
  339. * Free up the TLS index
  340. *
  341. * (Set the variable __tlsindex back to the unused state (-1L).)
  342. */
  343. if ( __tlsindex != 0xffffffff ) {
  344. TlsFree(__tlsindex);
  345. __tlsindex = 0xffffffff;
  346. }
  347. #endif /* _NTSUBSET_ */
  348. }
  349. #if !defined(_NTSUBSET_)
  350. /***
  351. *void _initptd(_ptiddata ptd) - initialize a per-thread data structure
  352. *
  353. *Purpose:
  354. * This routine handles all of the per-thread initialization
  355. * which is common to _beginthread, _beginthreadex, _mtinit
  356. * and _getptd.
  357. *
  358. *Entry:
  359. * pointer to a per-thread data block
  360. *
  361. *Exit:
  362. * the common fields in that block are initialized
  363. *
  364. *Exceptions:
  365. *
  366. *******************************************************************************/
  367. void __cdecl _initptd (
  368. _ptiddata ptd
  369. )
  370. {
  371. ptd->_pxcptacttab = (void *)_XcptActTab;
  372. ptd->_holdrand = 1L;
  373. #ifdef ANSI_NEW_HANDLER
  374. ptd->_newh = _defnewh;
  375. #endif /* ANSI_NEW_HANDLER */
  376. #ifdef _M_MRX000
  377. /*
  378. * MIPS per-thread data
  379. */
  380. ptd->_MipsPtdDelta =
  381. ptd->_MipsPtdEpsilon = -1L ;
  382. #endif
  383. }
  384. #endif /* _NTSUBSET_ */
  385. /***
  386. *_ptiddata _getptd(void) - get per-thread data structure for the current thread
  387. *
  388. *Purpose:
  389. *
  390. *Entry:
  391. * unsigned long tid
  392. *
  393. *Exit:
  394. * success = pointer to _tiddata structure for the thread
  395. * failure = fatal runtime exit
  396. *
  397. *Exceptions:
  398. *
  399. *******************************************************************************/
  400. _ptiddata __cdecl _getptd (
  401. void
  402. )
  403. {
  404. _ptiddata ptd;
  405. DWORD TL_LastError;
  406. #if defined(_NTSUBSET_)
  407. ptd = PsGetCurrentThread()->OfsChain;
  408. if ( ptd == 0 ) {
  409. ptd = _newKernelTid();
  410. }
  411. #else /* _NTSUBSET_ */
  412. TL_LastError = GetLastError();
  413. if ( (ptd = TlsGetValue(__tlsindex)) == NULL ) {
  414. /*
  415. * no per-thread data structure for this thread. try to create
  416. * one.
  417. */
  418. if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL) &&
  419. TlsSetValue(__tlsindex, (LPVOID)ptd) ) {
  420. /*
  421. * Initialize of per-thread data
  422. */
  423. _initptd(ptd);
  424. ptd->_tid = GetCurrentThreadId();
  425. ptd->_thandle = (uintptr_t)(-1);
  426. }
  427. else
  428. _amsg_exit(_RT_THREAD); /* write message and die */
  429. }
  430. SetLastError(TL_LastError);
  431. #endif /* _NTSUBSET_ */
  432. return(ptd);
  433. }
  434. /***
  435. *void _freeptd(_ptiddata) - free up a per-thread data structure
  436. *
  437. *Purpose:
  438. * Called from _endthread and from a DLL thread detach handler,
  439. * this routine frees up the per-thread buffer associated with a
  440. * thread that is going away. The tiddata structure itself is
  441. * freed, but not until its subordinate buffers are freed.
  442. *
  443. *Entry:
  444. * pointer to a per-thread data block (malloc-ed memory)
  445. * If NULL, the pointer for the current thread is fetched.
  446. *
  447. *Exit:
  448. *
  449. *Exceptions:
  450. *
  451. *******************************************************************************/
  452. void __cdecl _freeptd (
  453. _ptiddata ptd
  454. )
  455. {
  456. #if defined(_NTSUBSET_)
  457. if ( 0 == ptd ) {
  458. ptd = PsGetCurrentThread()->OfsChain;
  459. } else {
  460. ASSERT( ptd == PsGetCurrentThread()->OfsChain );
  461. }
  462. _freeKernelTid( ptd );
  463. PsGetCurrentThread()->OfsChain = 0;
  464. #else /* _NTSUBSET_ */
  465. pthreadmbcinfo ptmbci;
  466. pthreadlocinfo ptloci;
  467. /*
  468. * Do nothing unless per-thread data has been allocated for this module!
  469. */
  470. if ( __tlsindex != 0xFFFFFFFF ) {
  471. /*
  472. * if parameter "ptd" is NULL, get the per-thread data pointer
  473. * Must NOT call _getptd because it will allocate one if none exists!
  474. */
  475. if ( ! ptd )
  476. ptd = TlsGetValue(__tlsindex );
  477. /*
  478. * Free up the _tiddata structure & its malloc-ed buffers.
  479. */
  480. if ( ptd ) {
  481. if(ptd->_errmsg)
  482. _free_crt((void *)ptd->_errmsg);
  483. if(ptd->_namebuf0)
  484. _free_crt((void *)ptd->_namebuf0);
  485. if(ptd->_namebuf1)
  486. _free_crt((void *)ptd->_namebuf1);
  487. if(ptd->_asctimebuf)
  488. _free_crt((void *)ptd->_asctimebuf);
  489. if(ptd->_gmtimebuf)
  490. _free_crt((void *)ptd->_gmtimebuf);
  491. if(ptd->_cvtbuf)
  492. _free_crt((void *)ptd->_cvtbuf);
  493. if (ptd->_pxcptacttab != _XcptActTab)
  494. _free_crt((void *)ptd->_pxcptacttab);
  495. _mlock(_MB_CP_LOCK);
  496. __try {
  497. if ( ((ptmbci = ptd->ptmbcinfo) != NULL) &&
  498. (--(ptmbci->refcount) == 0) &&
  499. (ptmbci != __ptmbcinfo) )
  500. _free_crt(ptmbci);
  501. }
  502. __finally {
  503. _munlock(_MB_CP_LOCK);
  504. }
  505. _mlock(_SETLOCALE_LOCK);
  506. __try {
  507. if ( (ptloci = ptd->ptlocinfo) != NULL )
  508. {
  509. (ptloci->refcount)--;
  510. if ( ptloci->lconv_intl_refcount != NULL )
  511. (*(ptloci->lconv_intl_refcount))--;
  512. if ( ptloci->lconv_mon_refcount != NULL )
  513. (*(ptloci->lconv_mon_refcount))--;
  514. if ( ptloci->lconv_num_refcount != NULL )
  515. (*(ptloci->lconv_num_refcount))--;
  516. if ( ptloci->ctype1_refcount != NULL )
  517. (*(ptloci->ctype1_refcount))--;
  518. (ptloci->lc_time_curr->refcount)--;
  519. if ( (ptloci != __ptlocinfo) &&
  520. (ptloci != &__initiallocinfo) &&
  521. (ptloci->refcount == 0) )
  522. __freetlocinfo(ptloci);
  523. }
  524. }
  525. __finally {
  526. _munlock(_SETLOCALE_LOCK);
  527. }
  528. _free_crt((void *)ptd);
  529. }
  530. /*
  531. * Zero out the one pointer to the per-thread data block
  532. */
  533. TlsSetValue(__tlsindex, (LPVOID)0);
  534. }
  535. #endif /* _NTSUBSET_ */
  536. }
  537. #if defined(_NTSUBSET_)
  538. #pragma END_NONPAGED_CODE
  539. #endif
  540. /***
  541. *__threadid() - Returns current thread ID
  542. *__threadhandle() - Returns "pseudo-handle" for current thread
  543. *
  544. *Purpose:
  545. * The two function are simply do-nothing wrappers for the corresponding
  546. * Win32 APIs (GetCurrentThreadId and GetCurrentThread, respectively).
  547. *
  548. *Entry:
  549. * void
  550. *
  551. *Exit:
  552. * thread ID value
  553. *
  554. *Exceptions:
  555. *
  556. *******************************************************************************/
  557. _CRTIMP unsigned long __cdecl __threadid (
  558. void
  559. )
  560. {
  561. #if defined(_NTSUBSET_)
  562. return( (unsigned long) (uintptr_t) PsGetCurrentThread()->Cid.UniqueThread );
  563. #else
  564. return( GetCurrentThreadId() );
  565. #endif
  566. }
  567. _CRTIMP uintptr_t __cdecl __threadhandle(
  568. void
  569. )
  570. {
  571. #if defined(_NTSUBSET_)
  572. return( (uintptr_t) PsGetCurrentThread()->Cid.UniqueThread );
  573. #else
  574. return( (uintptr_t)GetCurrentThread() );
  575. #endif
  576. }
  577. #endif