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.

4656 lines
130 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. thread.c
  5. Abstract:
  6. This module implements Win32 Thread Object APIs
  7. Author:
  8. Mark Lucovsky (markl) 21-Sep-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "faultrep.h"
  13. #define STRSAFE_NO_DEPRECATE
  14. #include <strsafe.h>
  15. //
  16. // Define the fiber local storage data structure.
  17. //
  18. typedef struct _FLS_DATA {
  19. LIST_ENTRY Entry;
  20. PVOID Slots[FLS_MAXIMUM_AVAILABLE];
  21. } FLS_DATA, *PFLS_DATA;
  22. HANDLE BasepDefaultTimerQueue ;
  23. ULONG BasepTimerQueueInitFlag ;
  24. ULONG BasepTimerQueueDoneFlag ;
  25. HANDLE
  26. APIENTRY
  27. CreateThread(
  28. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  29. SIZE_T dwStackSize,
  30. LPTHREAD_START_ROUTINE lpStartAddress,
  31. LPVOID lpParameter,
  32. DWORD dwCreationFlags,
  33. LPDWORD lpThreadId
  34. )
  35. /*++
  36. Routine Description:
  37. A thread object can be created to execute within the address space of the
  38. calling process using CreateThread.
  39. See CreateRemoteThread for a description of the arguments and return value.
  40. --*/
  41. {
  42. return CreateRemoteThread( NtCurrentProcess(),
  43. lpThreadAttributes,
  44. dwStackSize,
  45. lpStartAddress,
  46. lpParameter,
  47. dwCreationFlags,
  48. lpThreadId
  49. );
  50. }
  51. HANDLE
  52. APIENTRY
  53. CreateRemoteThread(
  54. HANDLE hProcess,
  55. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  56. SIZE_T dwStackSize,
  57. LPTHREAD_START_ROUTINE lpStartAddress,
  58. LPVOID lpParameter,
  59. DWORD dwCreationFlags,
  60. LPDWORD lpThreadId
  61. )
  62. /*++
  63. Routine Description:
  64. A thread object can be created to execute within the address space of the
  65. another process using CreateRemoteThread.
  66. Creating a thread causes a new thread of execution to begin in the address
  67. space of the current process. The thread has access to all objects opened
  68. by the process.
  69. The thread begins executing at the address specified by the StartAddress
  70. parameter. If the thread returns from this procedure, the results are
  71. un-specified.
  72. The thread remains in the system until it has terminated and
  73. all handles to the thread
  74. have been closed through a call to CloseHandle.
  75. When a thread terminates, it attains a state of signaled satisfying all
  76. waits on the object.
  77. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
  78. object type specific access flags are valid for thread objects:
  79. - THREAD_QUERY_INFORMATION - This access is required to read
  80. certain information from the thread object.
  81. - SYNCHRONIZE - This access is required to wait on a thread
  82. object.
  83. - THREAD_GET_CONTEXT - This access is required to read the
  84. context of a thread using GetThreadContext.
  85. - THREAD_SET_CONTEXT - This access is required to write the
  86. context of a thread using SetThreadContext.
  87. - THREAD_SUSPEND_RESUME - This access is required to suspend or
  88. resume a thread using SuspendThread or ResumeThread.
  89. - THREAD_ALL_ACCESS - This set of access flags specifies all of
  90. the possible access flags for a thread object.
  91. Arguments:
  92. hProcess - Supplies the handle to the process in which the thread is
  93. to be create in.
  94. lpThreadAttributes - An optional parameter that may be used to specify
  95. the attributes of the new thread. If the parameter is not
  96. specified, then the thread is created without a security
  97. descriptor, and the resulting handle is not inherited on process
  98. creation.
  99. dwStackSize - Supplies the size in bytes of the stack for the new thread.
  100. A value of zero specifies that the thread's stack size should be
  101. the same size as the stack size of the first thread in the process.
  102. This size is specified in the application's executable file.
  103. lpStartAddress - Supplies the starting address of the new thread. The
  104. address is logically a procedure that never returns and that
  105. accepts a single 32-bit pointer argument.
  106. lpParameter - Supplies a single parameter value passed to the thread.
  107. dwCreationFlags - Supplies additional flags that control the creation
  108. of the thread.
  109. dwCreationFlags Flags:
  110. CREATE_SUSPENDED - The thread is created in a suspended state.
  111. The creator can resume this thread using ResumeThread.
  112. Until this is done, the thread will not begin execution.
  113. STACK_SIZE_PARAM_IS_A_RESERVATION - Use stack size as a reservation rather than commit
  114. lpThreadId - Returns the thread identifier of the thread. The
  115. thread ID is valid until the thread terminates.
  116. Return Value:
  117. NON-NULL - Returns a handle to the new thread. The handle has full
  118. access to the new thread and may be used in any API that
  119. requires a handle to a thread object.
  120. NULL - The operation failed. Extended error status is available
  121. using GetLastError.
  122. --*/
  123. {
  124. NTSTATUS Status;
  125. OBJECT_ATTRIBUTES Obja;
  126. POBJECT_ATTRIBUTES pObja;
  127. HANDLE Handle;
  128. CONTEXT ThreadContext={0};
  129. INITIAL_TEB InitialTeb;
  130. CLIENT_ID ClientId;
  131. ULONG i;
  132. ACTIVATION_CONTEXT_BASIC_INFORMATION ActivationContextInfo = {0};
  133. const ACTIVATION_CONTEXT_INFO_CLASS ActivationContextInfoClass = ActivationContextBasicInformation;
  134. #if !defined(BUILD_WOW6432)
  135. BASE_API_MSG m;
  136. PBASE_CREATETHREAD_MSG a = &m.u.CreateThread;
  137. #endif
  138. #if defined(WX86) || defined(_AXP64_)
  139. BOOL bWx86 = FALSE;
  140. HANDLE Wx86Info;
  141. PWX86TIB Wx86Tib;
  142. #endif
  143. //
  144. // Allocate a stack for this thread in the address space of the target
  145. // process.
  146. //
  147. if (dwCreationFlags&STACK_SIZE_PARAM_IS_A_RESERVATION) {
  148. Status = BaseCreateStack (hProcess,
  149. 0L,
  150. dwStackSize,
  151. &InitialTeb);
  152. } else {
  153. Status = BaseCreateStack (hProcess,
  154. dwStackSize,
  155. 0L,
  156. &InitialTeb);
  157. }
  158. if ( !NT_SUCCESS(Status) ) {
  159. BaseSetLastNTError(Status);
  160. return NULL;
  161. }
  162. //
  163. // Create an initial context for the new thread.
  164. //
  165. BaseInitializeContext(
  166. &ThreadContext,
  167. lpParameter,
  168. (PVOID)lpStartAddress,
  169. InitialTeb.StackBase,
  170. BaseContextTypeThread
  171. );
  172. pObja = BaseFormatObjectAttributes(&Obja,lpThreadAttributes,NULL);
  173. Status = NtCreateThread(
  174. &Handle,
  175. THREAD_ALL_ACCESS,
  176. pObja,
  177. hProcess,
  178. &ClientId,
  179. &ThreadContext,
  180. &InitialTeb,
  181. TRUE // CreateSuspended
  182. );
  183. if (!NT_SUCCESS(Status)) {
  184. BaseFreeThreadStack(hProcess,NULL, &InitialTeb);
  185. BaseSetLastNTError(Status);
  186. return NULL;
  187. }
  188. __try {
  189. // If the current thread has a non-default, inheriting activation context active, send it
  190. // on over to the new thread.
  191. if (hProcess == NtCurrentProcess()) {
  192. THREAD_BASIC_INFORMATION tbi;
  193. ULONG_PTR Cookie; // not really used but non-optional parameter
  194. // We need the TEB pointer for the new thread...
  195. Status = NtQueryInformationThread(
  196. Handle,
  197. ThreadBasicInformation,
  198. &tbi,
  199. sizeof(tbi),
  200. NULL);
  201. if (!NT_SUCCESS(Status)) {
  202. DbgPrint("SXS: %s - Failing thread create becuase NtQueryInformationThread() failed with status %08lx\n", __FUNCTION__, Status);
  203. __leave;
  204. }
  205. // There might be some per-context activation going on in the current thread;
  206. // we need to propogate it to the new thread.
  207. Status =
  208. RtlQueryInformationActivationContext(
  209. RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
  210. NULL,
  211. 0,
  212. ActivationContextInfoClass,
  213. &ActivationContextInfo,
  214. sizeof(ActivationContextInfo),
  215. NULL
  216. );
  217. if (!NT_SUCCESS(Status)) {
  218. DbgPrint("SXS: %s - Failing thread create because RtlQueryInformationActivationContext() failed with status %08lx\n", __FUNCTION__, Status);
  219. __leave;
  220. }
  221. // Only do the propogation if an activation context other than the process default is active and the NO_INHERIT flag isn't set.
  222. if ((ActivationContextInfo.ActivationContext != NULL) &&
  223. (!(ActivationContextInfo.Flags & ACTIVATION_CONTEXT_FLAG_NO_INHERIT))) {
  224. Status = RtlActivateActivationContextEx(
  225. RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION,
  226. tbi.TebBaseAddress,
  227. ActivationContextInfo.ActivationContext,
  228. &Cookie);
  229. if (!NT_SUCCESS(Status)) {
  230. DbgPrint("SXS: %s - Failing thread create because RtlActivateActivationContextEx() failed with status %08lx\n", __FUNCTION__, Status);
  231. __leave;
  232. }
  233. }
  234. }
  235. //
  236. // Call the Windows server to let it know about the
  237. // thread.
  238. //
  239. if ( !BaseRunningInServerProcess ) {
  240. #if defined(BUILD_WOW6432)
  241. Status = CsrBasepCreateThread(Handle,
  242. ClientId
  243. );
  244. #else
  245. a->ThreadHandle = Handle;
  246. a->ClientId = ClientId;
  247. CsrClientCallServer( (PCSR_API_MSG)&m,
  248. NULL,
  249. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  250. BasepCreateThread
  251. ),
  252. sizeof( *a )
  253. );
  254. Status = m.ReturnValue;
  255. #endif
  256. } else {
  257. if (hProcess != NtCurrentProcess()) {
  258. CSRREMOTEPROCPROC ProcAddress;
  259. ProcAddress = (CSRREMOTEPROCPROC)GetProcAddress(
  260. GetModuleHandleA("csrsrv"),
  261. "CsrCreateRemoteThread"
  262. );
  263. if (ProcAddress) {
  264. Status = (ProcAddress)(Handle, &ClientId);
  265. }
  266. }
  267. }
  268. if (!NT_SUCCESS(Status)) {
  269. Status = (NTSTATUS)STATUS_NO_MEMORY;
  270. } else {
  271. if ( ARGUMENT_PRESENT(lpThreadId) ) {
  272. *lpThreadId = HandleToUlong(ClientId.UniqueThread);
  273. }
  274. if (!( dwCreationFlags & CREATE_SUSPENDED) ) {
  275. NtResumeThread(Handle,&i);
  276. }
  277. }
  278. } __finally {
  279. if (ActivationContextInfo.ActivationContext != NULL) {
  280. RtlReleaseActivationContext(ActivationContextInfo.ActivationContext);
  281. }
  282. if (!NT_SUCCESS(Status)) {
  283. //
  284. // A second release is needed because we activated the activation context
  285. // on the new thread but we did not succeed in completing creation of the
  286. // thread. Had the thread been created, it would have deactivated the
  287. // activation context upon exit (RtlFreeThreadActivationContextStack).
  288. // This extra addref/releasing is triggered
  289. // by the flags ACTIVATE_ACTIVATION_CONTEXT_FLAG_RELEASE_ON_STACK_DEALLOCATION
  290. // and ACTIVATION_CONTEXT_STACK_FRAME_RELEASE_ON_DEACTIVATION.
  291. //
  292. if (ActivationContextInfo.ActivationContext != NULL) {
  293. RtlReleaseActivationContext (ActivationContextInfo.ActivationContext);
  294. }
  295. NtTerminateThread (Handle, Status);
  296. //
  297. // Wait for the thread before deleting its stack. the kernel might be in the
  298. // process of writing to it until we exit (say in user APC dispatch).
  299. //
  300. WaitForSingleObject (Handle, INFINITE);
  301. BaseFreeThreadStack (hProcess,
  302. Handle,
  303. &InitialTeb);
  304. NtClose (Handle);
  305. BaseSetLastNTError (Status);
  306. Handle = NULL;
  307. }
  308. }
  309. return Handle;
  310. }
  311. NTSTATUS
  312. NTAPI
  313. BaseCreateThreadPoolThread(
  314. PUSER_THREAD_START_ROUTINE Function,
  315. PVOID Parameter,
  316. HANDLE * ThreadHandleReturn
  317. )
  318. {
  319. NTSTATUS Status;
  320. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  321. RtlActivateActivationContextUnsafeFast(&Frame, NULL);
  322. __try {
  323. *ThreadHandleReturn
  324. = CreateRemoteThread(
  325. NtCurrentProcess(),
  326. NULL,
  327. 0,
  328. (LPTHREAD_START_ROUTINE) Function,
  329. Parameter,
  330. CREATE_SUSPENDED,
  331. NULL);
  332. if (*ThreadHandleReturn) {
  333. Status = STATUS_SUCCESS;
  334. } else {
  335. Status = NtCurrentTeb()->LastStatusValue;
  336. if (NT_SUCCESS(Status)) {
  337. Status = STATUS_UNSUCCESSFUL;
  338. }
  339. }
  340. } __finally {
  341. RtlDeactivateActivationContextUnsafeFast(&Frame);
  342. }
  343. return Status;
  344. }
  345. NTSTATUS
  346. NTAPI
  347. BaseExitThreadPoolThread(
  348. NTSTATUS Status
  349. )
  350. {
  351. ExitThread( (DWORD) Status );
  352. return STATUS_SUCCESS ;
  353. }
  354. HANDLE
  355. WINAPI
  356. OpenThread(
  357. DWORD dwDesiredAccess,
  358. BOOL bInheritHandle,
  359. DWORD dwThreadId
  360. )
  361. /*++
  362. Routine Description:
  363. A handle to a thread object may be created using OpenThread.
  364. Opening a thread creates a handle to the specified thread.
  365. Associated with the thread handle is a set of access rights that
  366. may be performed using the thread handle. The caller specifies the
  367. desired access to the thread using the DesiredAccess parameter.
  368. Arguments:
  369. mDesiredAccess - Supplies the desired access to the thread object.
  370. For NT/Win32, this access is checked against any security
  371. descriptor on the target thread. The following object type
  372. specific access flags can be specified in addition to the
  373. STANDARD_RIGHTS_REQUIRED access flags.
  374. DesiredAccess Flags:
  375. THREAD_TERMINATE - This access is required to terminate the
  376. thread using TerminateThread.
  377. THREAD_SUSPEND_RESUME - This access is required to suspend and
  378. resume the thread using SuspendThread and ResumeThread.
  379. THREAD_GET_CONTEXT - This access is required to use the
  380. GetThreadContext API on a thread object.
  381. THREAD_SET_CONTEXT - This access is required to use the
  382. SetThreadContext API on a thread object.
  383. THREAD_SET_INFORMATION - This access is required to set certain
  384. information in the thread object.
  385. THREAD_SET_THREAD_TOKEN - This access is required to set the
  386. thread token using SetTokenInformation.
  387. THREAD_QUERY_INFORMATION - This access is required to read
  388. certain information from the thread object.
  389. SYNCHRONIZE - This access is required to wait on a thread object.
  390. THREAD_ALL_ACCESS - This set of access flags specifies all of the
  391. possible access flags for a thread object.
  392. bInheritHandle - Supplies a flag that indicates whether or not the
  393. returned handle is to be inherited by a new process during
  394. process creation. A value of TRUE indicates that the new
  395. process will inherit the handle.
  396. dwThreadId - Supplies the thread id of the thread to open.
  397. Return Value:
  398. NON-NULL - Returns an open handle to the specified thread. The
  399. handle may be used by the calling process in any API that
  400. requires a handle to a thread. If the open is successful, the
  401. handle is granted access to the thread object only to the
  402. extent that it requested access through the DesiredAccess
  403. parameter.
  404. NULL - The operation failed. Extended error status is available
  405. using GetLastError.
  406. --*/
  407. {
  408. NTSTATUS Status;
  409. OBJECT_ATTRIBUTES Obja;
  410. HANDLE Handle;
  411. CLIENT_ID ClientId;
  412. ClientId.UniqueThread = (HANDLE)LongToHandle(dwThreadId);
  413. ClientId.UniqueProcess = (HANDLE)NULL;
  414. InitializeObjectAttributes(
  415. &Obja,
  416. NULL,
  417. (bInheritHandle ? OBJ_INHERIT : 0),
  418. NULL,
  419. NULL
  420. );
  421. Status = NtOpenThread(
  422. &Handle,
  423. (ACCESS_MASK)dwDesiredAccess,
  424. &Obja,
  425. &ClientId
  426. );
  427. if ( NT_SUCCESS(Status) ) {
  428. return Handle;
  429. }
  430. else {
  431. BaseSetLastNTError(Status);
  432. return NULL;
  433. }
  434. }
  435. BOOL
  436. APIENTRY
  437. SetThreadPriority(
  438. HANDLE hThread,
  439. int nPriority
  440. )
  441. /*++
  442. Routine Description:
  443. The specified thread's priority can be set using SetThreadPriority.
  444. A thread's priority may be set using SetThreadPriority. This call
  445. allows the thread's relative execution importance to be communicated
  446. to the system. The system normally schedules threads according to
  447. their priority. The system is free to temporarily boost the
  448. priority of a thread when signifigant events occur (e.g. keyboard
  449. or mouse input...). Similarly, as a thread runs without blocking,
  450. the system will decay its priority. The system will never decay the
  451. priority below the value set by this call.
  452. In the absence of system originated priority boosts, threads will be
  453. scheduled in a round-robin fashion at each priority level from
  454. THREAD_PRIORITY_TIME_CRITICAL to THREAD_PRIORITY_IDLE. Only when there
  455. are no runnable threads at a higher level, will scheduling of
  456. threads at a lower level take place.
  457. All threads initially start at THREAD_PRIORITY_NORMAL.
  458. If for some reason the thread needs more priority, it can be
  459. switched to THREAD_PRIORITY_ABOVE_NORMAL or THREAD_PRIORITY_HIGHEST.
  460. Switching to THREAD_PRIORITY_TIME_CRITICAL should only be done in extreme
  461. situations. Since these threads are given the highes priority, they
  462. should only run in short bursts. Running for long durations will
  463. soak up the systems processing bandwidth starving threads at lower
  464. levels.
  465. If a thread needs to do low priority work, or should only run there
  466. is nothing else to do, its priority should be set to
  467. THREAD_PRIORITY_BELOW_NORMAL or THREAD_PRIORITY_LOWEST. For extreme
  468. cases, THREAD_PRIORITY_IDLE can be used.
  469. Care must be taken when manipulating priorites. If priorities are
  470. used carelessly (every thread is set to THREAD_PRIORITY_TIME_CRITICAL),
  471. the effects of priority modifications can produce undesireable
  472. effects (e.g. starvation, no effect...).
  473. Arguments:
  474. hThread - Supplies a handle to the thread whose priority is to be
  475. set. The handle must have been created with
  476. THREAD_SET_INFORMATION access.
  477. nPriority - Supplies the priority value for the thread. The
  478. following five priority values (ordered from lowest priority to
  479. highest priority) are allowed.
  480. nPriority Values:
  481. THREAD_PRIORITY_IDLE - The thread's priority should be set to
  482. the lowest possible settable priority.
  483. THREAD_PRIORITY_LOWEST - The thread's priority should be set to
  484. the next lowest possible settable priority.
  485. THREAD_PRIORITY_BELOW_NORMAL - The thread's priority should be
  486. set to just below normal.
  487. THREAD_PRIORITY_NORMAL - The thread's priority should be set to
  488. the normal priority value. This is the value that all
  489. threads begin execution at.
  490. THREAD_PRIORITY_ABOVE_NORMAL - The thread's priority should be
  491. set to just above normal priority.
  492. THREAD_PRIORITY_HIGHEST - The thread's priority should be set to
  493. the next highest possible settable priority.
  494. THREAD_PRIORITY_TIME_CRITICAL - The thread's priority should be set
  495. to the highest possible settable priority. This priority is
  496. very likely to interfere with normal operation of the
  497. system.
  498. Return Value:
  499. TRUE - The operation was successful
  500. FALSE/NULL - The operation failed. Extended error status is available
  501. using GetLastError.
  502. --*/
  503. {
  504. NTSTATUS Status;
  505. LONG BasePriority;
  506. BasePriority = (LONG)nPriority;
  507. //
  508. // saturation is indicated by calling with a value of 16 or -16
  509. //
  510. if ( BasePriority == THREAD_PRIORITY_TIME_CRITICAL ) {
  511. BasePriority = ((HIGH_PRIORITY + 1) / 2);
  512. }
  513. else if ( BasePriority == THREAD_PRIORITY_IDLE ) {
  514. BasePriority = -((HIGH_PRIORITY + 1) / 2);
  515. }
  516. Status = NtSetInformationThread(
  517. hThread,
  518. ThreadBasePriority,
  519. &BasePriority,
  520. sizeof(BasePriority)
  521. );
  522. if ( !NT_SUCCESS(Status) ) {
  523. BaseSetLastNTError(Status);
  524. return FALSE;
  525. }
  526. return TRUE;
  527. }
  528. int
  529. APIENTRY
  530. GetThreadPriority(
  531. HANDLE hThread
  532. )
  533. /*++
  534. Routine Description:
  535. The specified thread's priority can be read using GetThreadPriority.
  536. Arguments:
  537. hThread - Supplies a handle to the thread whose priority is to be
  538. set. The handle must have been created with
  539. THREAD_QUERY_INFORMATION access.
  540. Return Value:
  541. The value of the thread's current priority is returned. If an error
  542. occured, the value THREAD_PRIORITY_ERROR_RETURN is returned.
  543. Extended error status is available using GetLastError.
  544. --*/
  545. {
  546. NTSTATUS Status;
  547. THREAD_BASIC_INFORMATION BasicInfo;
  548. int returnvalue;
  549. Status = NtQueryInformationThread(
  550. hThread,
  551. ThreadBasicInformation,
  552. &BasicInfo,
  553. sizeof(BasicInfo),
  554. NULL
  555. );
  556. if ( !NT_SUCCESS(Status) ) {
  557. BaseSetLastNTError(Status);
  558. return (int)THREAD_PRIORITY_ERROR_RETURN;
  559. }
  560. returnvalue = (int)BasicInfo.BasePriority;
  561. if ( returnvalue == ((HIGH_PRIORITY + 1) / 2) ) {
  562. returnvalue = THREAD_PRIORITY_TIME_CRITICAL;
  563. }
  564. else if ( returnvalue == -((HIGH_PRIORITY + 1) / 2) ) {
  565. returnvalue = THREAD_PRIORITY_IDLE;
  566. }
  567. return returnvalue;
  568. }
  569. BOOL
  570. WINAPI
  571. SetThreadPriorityBoost(
  572. HANDLE hThread,
  573. BOOL bDisablePriorityBoost
  574. )
  575. {
  576. NTSTATUS Status;
  577. ULONG DisableBoost;
  578. DisableBoost = bDisablePriorityBoost ? 1 : 0;
  579. Status = NtSetInformationThread(
  580. hThread,
  581. ThreadPriorityBoost,
  582. &DisableBoost,
  583. sizeof(DisableBoost)
  584. );
  585. if ( !NT_SUCCESS(Status) ) {
  586. BaseSetLastNTError(Status);
  587. return FALSE;
  588. }
  589. return TRUE;
  590. }
  591. BOOL
  592. WINAPI
  593. GetThreadPriorityBoost(
  594. HANDLE hThread,
  595. PBOOL pDisablePriorityBoost
  596. )
  597. {
  598. NTSTATUS Status;
  599. DWORD DisableBoost;
  600. Status = NtQueryInformationThread(
  601. hThread,
  602. ThreadPriorityBoost,
  603. &DisableBoost,
  604. sizeof(DisableBoost),
  605. NULL
  606. );
  607. if ( !NT_SUCCESS(Status) ) {
  608. BaseSetLastNTError(Status);
  609. return FALSE;
  610. }
  611. *pDisablePriorityBoost = DisableBoost;
  612. return TRUE;
  613. }
  614. VOID
  615. BaseRundownFls (
  616. IN PFLS_DATA FlsData
  617. )
  618. /*++
  619. Routine Description:
  620. This routine removes the specified fiber local storage data structure
  621. from the process list and runs down data entries by invoking callback
  622. routines as necessary.
  623. Arguments:
  624. FlsData - Supplies a pointer to fiber local storage data structure.
  625. Return Value:
  626. None.
  627. --*/
  628. {
  629. PFLS_CALLBACK_FUNCTION Callback;
  630. DWORD HighIndex;
  631. DWORD Index;
  632. PPEB Peb;
  633. //
  634. // Remove the fiber local storage data structure from the process list.
  635. //
  636. Peb = NtCurrentPeb();
  637. RtlAcquirePebLock();
  638. try {
  639. HighIndex = Peb->FlsHighIndex;
  640. RemoveEntryList(&FlsData->Entry);
  641. } finally {
  642. RtlReleasePebLock();
  643. }
  644. //
  645. // Scan the process fiber local storage callback array and invoke callback
  646. // routines as necessary.
  647. //
  648. // N.B. If the callback pointers are corrupted or a DLL has leaked memory
  649. // and been freed, then an exception can occur during the processing
  650. // of callbacks. This exception will be ignored and will stop callback
  651. // processing.
  652. try {
  653. for (Index = 1; Index <= HighIndex; Index += 1) {
  654. Callback = Peb->FlsCallback[Index];
  655. if ((Callback != NULL) && (FlsData->Slots[Index] != NULL)) {
  656. (Callback)(FlsData->Slots[Index]);
  657. }
  658. }
  659. } except (EXCEPTION_EXECUTE_HANDLER) {
  660. NOTHING;
  661. }
  662. //
  663. // Deallocate fiber local storage data structure.
  664. //
  665. RtlFreeHeap(Peb->ProcessHeap, 0, FlsData);
  666. return;
  667. }
  668. VOID
  669. APIENTRY
  670. ExitThread(
  671. DWORD dwExitCode
  672. )
  673. /*++
  674. Routine Description:
  675. The current thread can exit using ExitThread.
  676. ExitThread is the prefered method of exiting a thread. When this
  677. API is called (either explicitly or by returning from a thread
  678. procedure), The current thread's stack is deallocated and the thread
  679. terminates. If the thread is the last thread in the process when
  680. this API is called, the behavior of this API does not change. DLLs
  681. are not notified as a result of a call to ExitThread.
  682. Arguments:
  683. dwExitCode - Supplies the termination status for the thread.
  684. Return Value:
  685. None.
  686. --*/
  687. {
  688. PFIBER Fiber;
  689. MEMORY_BASIC_INFORMATION MemInfo;
  690. NTSTATUS st;
  691. ULONG LastThread;
  692. PTEB Teb = NtCurrentTeb();
  693. #if DBG
  694. {
  695. //
  696. // Assert on exiting while holding loader lock.
  697. //
  698. PRTL_CRITICAL_SECTION LoaderLock;
  699. LoaderLock = NtCurrentPeb()->LoaderLock;
  700. if (LoaderLock != NULL) {
  701. ASSERT(Teb->ClientId.UniqueThread != LoaderLock->OwningThread);
  702. }
  703. }
  704. #endif
  705. //
  706. // Check if this is the last thread in the process.
  707. //
  708. st = NtQueryInformationThread(NtCurrentThread(),
  709. ThreadAmILastThread,
  710. &LastThread,
  711. sizeof(LastThread),
  712. NULL);
  713. //
  714. // If this is the last thread in the process, then exit the process.
  715. // Otherwise, exit the thread.
  716. //
  717. if ((st == STATUS_SUCCESS) && LastThread) {
  718. ExitProcess(dwExitCode);
  719. } else {
  720. RtlFreeThreadActivationContextStack();
  721. LdrShutdownThread();
  722. //
  723. // If expansion slots have been allocated, then free the memory.
  724. //
  725. // N.B. The following code needs to hold the PEB lock to prevent
  726. // heap corruption.
  727. //
  728. if (Teb->TlsExpansionSlots != NULL) {
  729. RtlAcquirePebLock();
  730. try {
  731. RtlFreeHeap(RtlProcessHeap(), 0, Teb->TlsExpansionSlots);
  732. Teb->TlsExpansionSlots = NULL;
  733. } finally {
  734. RtlReleasePebLock();
  735. }
  736. }
  737. //
  738. // If a fiber local storage data structure has been allocated, then
  739. // rundown the structure.
  740. //
  741. if (Teb->FlsData != NULL) {
  742. BaseRundownFls((PFLS_DATA)Teb->FlsData);
  743. Teb->FlsData = NULL;
  744. }
  745. //
  746. // If the thread is associated with a fiber, then free the fiber
  747. // storage.
  748. //
  749. if (Teb->HasFiberData == TRUE) {
  750. Fiber = Teb->NtTib.FiberData;
  751. Teb->NtTib.FiberData = NULL;
  752. ASSERT(Fiber != NULL);
  753. RtlFreeHeap(RtlProcessHeap(), 0, Fiber);
  754. }
  755. Teb->FreeStackOnTermination = TRUE;
  756. NtTerminateThread(NULL, (NTSTATUS)dwExitCode);
  757. ExitProcess(dwExitCode);
  758. }
  759. }
  760. BOOL
  761. APIENTRY
  762. TerminateThread(
  763. HANDLE hThread,
  764. DWORD dwExitCode
  765. )
  766. /*++
  767. Routine Description:
  768. A thread may be terminated using TerminateThread.
  769. TerminateThread is used to cause a thread to terminate user-mode
  770. execution. There is nothing a thread can to to predict or prevent
  771. when this occurs. If a process has a handle with appropriate
  772. termination access to the thread or to the threads process, then the
  773. thread can be unconditionally terminated without notice. When this
  774. occurs, the target thread has no chance to execute any user-mode
  775. code and its initial stack is not deallocated. The thread attains a
  776. state of signaled satisfying any waits on the thread. The thread's
  777. termination status is updated from its initial value of
  778. STATUS_PENDING to the value of the TerminationStatus parameter.
  779. Terminating a thread does not remove a thread from the system. The
  780. thread is not removed from the system until the last handle to the
  781. thread is closed.
  782. Arguments:
  783. hThread - Supplies a handle to the thread to terminate. The handle
  784. must have been created with THREAD_TERMINATE access.
  785. dwExitCode - Supplies the termination status for the thread.
  786. Return Value:
  787. TRUE - The operation was successful
  788. FALSE/NULL - The operation failed. Extended error status is available
  789. using GetLastError.
  790. --*/
  791. {
  792. NTSTATUS Status;
  793. #if DBG
  794. PRTL_CRITICAL_SECTION LoaderLock;
  795. HANDLE ThreadId;
  796. THREAD_BASIC_INFORMATION ThreadInfo;
  797. #endif
  798. if ( hThread == NULL ) {
  799. SetLastError(ERROR_INVALID_HANDLE);
  800. return FALSE;
  801. }
  802. //
  803. // Assert on suicide while holding loader lock
  804. //
  805. #if DBG
  806. LoaderLock = NtCurrentPeb()->LoaderLock;
  807. if (LoaderLock) {
  808. Status = NtQueryInformationThread(
  809. hThread,
  810. ThreadBasicInformation,
  811. &ThreadInfo,
  812. sizeof(ThreadInfo),
  813. NULL
  814. );
  815. if (NT_SUCCESS(Status)) {
  816. ASSERT( NtCurrentTeb()->ClientId.UniqueThread != ThreadInfo.ClientId.UniqueThread ||
  817. NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread);
  818. }
  819. }
  820. #endif
  821. Status = NtTerminateThread(hThread,(NTSTATUS)dwExitCode);
  822. if ( NT_SUCCESS(Status) ) {
  823. return TRUE;
  824. }
  825. else {
  826. BaseSetLastNTError(Status);
  827. return FALSE;
  828. }
  829. }
  830. BOOL
  831. APIENTRY
  832. GetExitCodeThread(
  833. HANDLE hThread,
  834. LPDWORD lpExitCode
  835. )
  836. /*++
  837. Routine Description:
  838. The termination status of a thread can be read using
  839. GetExitCodeThread.
  840. If a Thread is in the signaled state, calling this function returns
  841. the termination status of the thread. If the thread is not yet
  842. signaled, the termination status returned is STILL_ACTIVE.
  843. Arguments:
  844. hThread - Supplies a handle to the thread whose termination status is
  845. to be read. The handle must have been created with
  846. THREAD_QUERY_INFORMATION access.
  847. lpExitCode - Returns the current termination status of the
  848. thread.
  849. Return Value:
  850. TRUE - The operation was successful
  851. FALSE/NULL - The operation failed. Extended error status is available
  852. using GetLastError.
  853. --*/
  854. {
  855. NTSTATUS Status;
  856. THREAD_BASIC_INFORMATION BasicInformation;
  857. Status = NtQueryInformationThread(
  858. hThread,
  859. ThreadBasicInformation,
  860. &BasicInformation,
  861. sizeof(BasicInformation),
  862. NULL
  863. );
  864. if ( NT_SUCCESS(Status) ) {
  865. *lpExitCode = BasicInformation.ExitStatus;
  866. return TRUE;
  867. }
  868. else {
  869. BaseSetLastNTError(Status);
  870. return FALSE;
  871. }
  872. }
  873. HANDLE
  874. APIENTRY
  875. GetCurrentThread(
  876. VOID
  877. )
  878. /*++
  879. Routine Description:
  880. A pseudo handle to the current thread may be retrieved using
  881. GetCurrentThread.
  882. A special constant is exported by Win32 that is interpreted as a
  883. handle to the current thread. This handle may be used to specify
  884. the current thread whenever a thread handle is required. On Win32,
  885. this handle has THREAD_ALL_ACCESS to the current thread. On
  886. NT/Win32, this handle has the maximum access allowed by any security
  887. descriptor placed on the current thread.
  888. Arguments:
  889. None.
  890. Return Value:
  891. Returns the pseudo handle of the current thread.
  892. --*/
  893. {
  894. return NtCurrentThread();
  895. }
  896. DWORD
  897. APIENTRY
  898. GetCurrentThreadId(
  899. VOID
  900. )
  901. /*++
  902. Routine Description:
  903. The thread ID of the current thread may be retrieved using
  904. GetCurrentThreadId.
  905. Arguments:
  906. None.
  907. Return Value:
  908. Returns a unique value representing the thread ID of the currently
  909. executing thread. The return value may be used to identify a thread
  910. in the system.
  911. --*/
  912. {
  913. return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
  914. }
  915. DWORD
  916. APIENTRY
  917. GetThreadId(
  918. HANDLE Thread
  919. )
  920. /*++
  921. Routine Description:
  922. Gets the thread ID of the thread open via the specified handle
  923. Arguments:
  924. Thread - Handle of thread to do the query on
  925. Return Value:
  926. Returns a unique value representing the thread ID of the
  927. executing thread. The return value may be used to identify a thread
  928. in the system. If the function fails the return value is zero.
  929. --*/
  930. {
  931. NTSTATUS Status;
  932. THREAD_BASIC_INFORMATION tbi;
  933. Status = NtQueryInformationThread (Thread,
  934. ThreadBasicInformation,
  935. &tbi,
  936. sizeof (tbi),
  937. NULL);
  938. if (!NT_SUCCESS (Status)) {
  939. BaseSetLastNTError (Status);
  940. return 0;
  941. }
  942. return HandleToUlong (tbi.ClientId.UniqueThread);
  943. }
  944. DWORD
  945. APIENTRY
  946. GetProcessIdOfThread(
  947. HANDLE Thread
  948. )
  949. /*++
  950. Routine Description:
  951. Gets the process ID of the thread opened via the specified handle
  952. Arguments:
  953. Thread - Handle of thread to do the query on
  954. Return Value:
  955. Returns a unique value representing the process ID of the
  956. executing thread. The return value may be used to identify a process
  957. in the system. If the function fails the return value is zero.
  958. --*/
  959. {
  960. NTSTATUS Status;
  961. THREAD_BASIC_INFORMATION tbi;
  962. Status = NtQueryInformationThread (Thread,
  963. ThreadBasicInformation,
  964. &tbi,
  965. sizeof (tbi),
  966. NULL);
  967. if (!NT_SUCCESS (Status)) {
  968. BaseSetLastNTError (Status);
  969. return 0;
  970. }
  971. return HandleToUlong (tbi.ClientId.UniqueProcess);
  972. }
  973. BOOL
  974. APIENTRY
  975. GetThreadContext(
  976. HANDLE hThread,
  977. LPCONTEXT lpContext
  978. )
  979. /*++
  980. Routine Description:
  981. The context of a specified thread can be retreived using
  982. GetThreadContext.
  983. This function is used to retreive the context of the specified
  984. thread. The API allows selective context to be retrieved based on
  985. the value of the ContextFlags field of the context structure. The
  986. specified thread does not have to be being debugged in order for
  987. this API to operate. The caller must simply have a handle to the
  988. thread that was created with THREAD_GET_CONTEXT access.
  989. Arguments:
  990. hThread - Supplies an open handle to a thread whose context is to be
  991. retreived. The handle must have been created with
  992. THREAD_GET_CONTEXT access to the thread.
  993. lpContext - Supplies the address of a context structure that
  994. receives the appropriate context of the specified thread. The
  995. value of the ContextFlags field of this structure specifies
  996. which portions of a threads context are to be retreived. The
  997. context structure is highly machine specific. There are
  998. currently two versions of the context structure. One version
  999. exists for x86 processors, and another exists for MIPS
  1000. processors.
  1001. Return Value:
  1002. TRUE - The operation was successful.
  1003. FALSE/NULL - The operation failed. Extended error status is available
  1004. using GetLastError.
  1005. --*/
  1006. {
  1007. NTSTATUS Status;
  1008. Status = NtGetContextThread (hThread, lpContext);
  1009. if (!NT_SUCCESS (Status)) {
  1010. BaseSetLastNTError (Status);
  1011. return FALSE;
  1012. } else {
  1013. return TRUE;
  1014. }
  1015. }
  1016. BOOL
  1017. APIENTRY
  1018. SetThreadContext(
  1019. HANDLE hThread,
  1020. CONST CONTEXT *lpContext
  1021. )
  1022. /*++
  1023. Routine Description:
  1024. This function is used to set the context in the specified thread.
  1025. The API allows selective context to be set based on the value of the
  1026. ContextFlags field of the context structure. The specified thread
  1027. does not have to be being debugged in order for this API to operate.
  1028. The caller must simply have a handle to the thread that was created
  1029. with THREAD_SET_CONTEXT access.
  1030. Arguments:
  1031. hThread - Supplies an open handle to a thread whose context is to be
  1032. written. The handle must have been created with
  1033. THREAD_SET_CONTEXT access to the thread.
  1034. lpContext - Supplies the address of a context structure that
  1035. contains the context that is to be set in the specified thread.
  1036. The value of the ContextFlags field of this structure specifies
  1037. which portions of a threads context are to be set. Some values
  1038. in the context structure are not settable and are silently set
  1039. to the correct value. This includes cpu status register bits
  1040. that specify the priviledged processor mode, debug register
  1041. global enabling bits, and other state that must be completely
  1042. controlled by the operating system.
  1043. Return Value:
  1044. TRUE - The operation was successful.
  1045. FALSE/NULL - The operation failed. Extended error status is available
  1046. using GetLastError.
  1047. --*/
  1048. {
  1049. NTSTATUS Status;
  1050. Status = NtSetContextThread(hThread,(PCONTEXT)lpContext);
  1051. if ( !NT_SUCCESS(Status) ) {
  1052. BaseSetLastNTError(Status);
  1053. return FALSE;
  1054. }
  1055. else {
  1056. return TRUE;
  1057. }
  1058. }
  1059. DWORD
  1060. APIENTRY
  1061. SuspendThread(
  1062. HANDLE hThread
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. A thread can be suspended using SuspendThread.
  1067. Suspending a thread causes the thread to stop executing user-mode
  1068. (or application) code. Each thread has a suspend count (with a
  1069. maximum value of MAXIMUM_SUSPEND_COUNT). If the suspend count is
  1070. greater than zero, the thread is suspended; otherwise, the thread is
  1071. not suspended and is eligible for execution.
  1072. Calling SuspendThread causes the target thread's suspend count to
  1073. increment. Attempting to increment past the maximum suspend count
  1074. causes an error without incrementing the count.
  1075. Arguments:
  1076. hThread - Supplies a handle to the thread that is to be suspended.
  1077. The handle must have been created with THREAD_SUSPEND_RESUME
  1078. access to the thread.
  1079. Return Value:
  1080. -1 - The operation failed. Extended error status is available using
  1081. GetLastError.
  1082. Other - The target thread was suspended. The return value is the thread's
  1083. previous suspend count.
  1084. --*/
  1085. {
  1086. NTSTATUS Status;
  1087. DWORD PreviousSuspendCount;
  1088. Status = NtSuspendThread(hThread,&PreviousSuspendCount);
  1089. if ( !NT_SUCCESS(Status) ) {
  1090. BaseSetLastNTError(Status);
  1091. return (DWORD)-1;
  1092. }
  1093. else {
  1094. return PreviousSuspendCount;
  1095. }
  1096. }
  1097. DWORD
  1098. APIENTRY
  1099. ResumeThread(
  1100. IN HANDLE hThread
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. A thread can be resumed using ResumeThread.
  1105. Resuming a thread object checks the suspend count of the subject
  1106. thread. If the suspend count is zero, then the thread is not
  1107. currently suspended and no operation is performed. Otherwise, the
  1108. subject thread's suspend count is decremented. If the resultant
  1109. value is zero , then the execution of the subject thread is resumed.
  1110. The previous suspend count is returned as the function value. If
  1111. the return value is zero, then the subject thread was not previously
  1112. suspended. If the return value is one, then the subject thread's
  1113. the subject thread is still suspended and must be resumed the number
  1114. of times specified by the return value minus one before it will
  1115. actually resume execution.
  1116. Note that while reporting debug events, all threads withing the
  1117. reporting process are frozen. This has nothing to do with
  1118. SuspendThread or ResumeThread. Debuggers are expected to use
  1119. SuspendThread and ResumeThread to limit the set of threads that can
  1120. execute within a process. By suspending all threads in a process
  1121. except for the one reporting a debug event, it is possible to
  1122. "single step" a single thread. The other threads will not be
  1123. released by a continue if they are suspended.
  1124. Arguments:
  1125. hThread - Supplies a handle to the thread that is to be resumed.
  1126. The handle must have been created with THREAD_SUSPEND_RESUME
  1127. access to the thread.
  1128. Return Value:
  1129. -1 - The operation failed. Extended error status is available using
  1130. GetLastError.
  1131. Other - The target thread was resumed (or was not previously
  1132. suspended). The return value is the thread's previous suspend
  1133. count.
  1134. --*/
  1135. {
  1136. NTSTATUS Status;
  1137. DWORD PreviousSuspendCount;
  1138. Status = NtResumeThread(hThread,&PreviousSuspendCount);
  1139. if ( !NT_SUCCESS(Status) ) {
  1140. BaseSetLastNTError(Status);
  1141. return (DWORD)-1;
  1142. }
  1143. else {
  1144. return PreviousSuspendCount;
  1145. }
  1146. }
  1147. VOID
  1148. APIENTRY
  1149. RaiseException(
  1150. DWORD dwExceptionCode,
  1151. DWORD dwExceptionFlags,
  1152. DWORD nNumberOfArguments,
  1153. CONST ULONG_PTR *lpArguments
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Raising an exception causes the exception dispatcher to go through
  1158. its search for an exception handler. This includes debugger
  1159. notification, frame based handler searching, and system default
  1160. actions.
  1161. Arguments:
  1162. dwExceptionCode - Supplies the exception code of the exception being
  1163. raised. This value may be obtained in exception filters and in
  1164. exception handlers by calling GetExceptionCode.
  1165. dwExceptionFlags - Supplies a set of flags associated with the exception.
  1166. dwExceptionFlags Flags:
  1167. EXCEPTION_NONCONTINUABLE - The exception is non-continuable.
  1168. Returning EXCEPTION_CONTINUE_EXECUTION from an exception
  1169. marked in this way causes the
  1170. STATUS_NONCONTINUABLE_EXCEPTION exception.
  1171. nNumberOfArguments - Supplies the number of arguments associated
  1172. with the exception. This value may not exceed
  1173. EXCEPTION_MAXIMUM_PARAMETERS. This parameter is ignored if
  1174. lpArguments is NULL.
  1175. lpArguments - An optional parameter, that if present supplies the
  1176. arguments for the exception.
  1177. Return Value:
  1178. None.
  1179. --*/
  1180. {
  1181. EXCEPTION_RECORD ExceptionRecord;
  1182. ULONG n;
  1183. PULONG_PTR s,d;
  1184. ExceptionRecord.ExceptionCode = (DWORD)dwExceptionCode;
  1185. ExceptionRecord.ExceptionFlags = dwExceptionFlags & EXCEPTION_NONCONTINUABLE;
  1186. ExceptionRecord.ExceptionRecord = NULL;
  1187. ExceptionRecord.ExceptionAddress = (PVOID)RaiseException;
  1188. if ( ARGUMENT_PRESENT(lpArguments) ) {
  1189. n = nNumberOfArguments;
  1190. if ( n > EXCEPTION_MAXIMUM_PARAMETERS ) {
  1191. n = EXCEPTION_MAXIMUM_PARAMETERS;
  1192. }
  1193. ExceptionRecord.NumberParameters = n;
  1194. s = (PULONG_PTR)lpArguments;
  1195. d = ExceptionRecord.ExceptionInformation;
  1196. while(n--){
  1197. *d++ = *s++;
  1198. }
  1199. }
  1200. else {
  1201. ExceptionRecord.NumberParameters = 0;
  1202. }
  1203. RtlRaiseException(&ExceptionRecord);
  1204. }
  1205. BOOLEAN BasepAlreadyHadHardError = FALSE;
  1206. LPTOP_LEVEL_EXCEPTION_FILTER BasepCurrentTopLevelFilter;
  1207. LPTOP_LEVEL_EXCEPTION_FILTER
  1208. WINAPI
  1209. SetUnhandledExceptionFilter(
  1210. LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. This function allows an application to supersede the top level
  1215. exception handler that Win32 places at the top of each thread and
  1216. process.
  1217. If an exception occurs, and it makes it to the Win32 unhandled
  1218. exception filter, and the process is not being debugged, the Win32
  1219. filter will call the unhandled exception filter specified by
  1220. lpTopLevelExceptionFilter.
  1221. This filter may return:
  1222. EXCEPTION_EXECUTE_HANDLER - Return from the Win32
  1223. UnhandledExceptionFilter and execute the associated
  1224. exception handler. This will usually result in process
  1225. termination
  1226. EXCEPTION_CONTINUE_EXECUTION - Return from the Win32
  1227. UnhandledExceptionFilter and continue execution from the
  1228. point of the exception. The filter is of course free to
  1229. modify the continuation state my modifying the passed
  1230. exception information.
  1231. EXCEPTION_CONTINUE_SEARCH - Proceed with normal execution of the
  1232. Win32 UnhandledExceptionFilter. e.g. obey the SetErrorMode
  1233. flags, or invoke the Application Error popup.
  1234. This function is not a general vectored exception handling
  1235. mechanism. It is intended to be used to establish a per-process
  1236. exception filter that can monitor unhandled exceptions at the
  1237. process level and respond to these exceptions appropriately.
  1238. Arguments:
  1239. lpTopLevelExceptionFilter - Supplies the address of a top level
  1240. filter function that will be called whenever the Win32
  1241. UnhandledExceptionFilter gets control, and the process is NOT
  1242. being debugged. A value of NULL specifies default handling
  1243. within the Win32 UnhandledExceptionFilter.
  1244. Return Value:
  1245. This function returns the address of the previous exception filter
  1246. established with this API. A value of NULL means that there is no
  1247. current top level handler.
  1248. --*/
  1249. {
  1250. LPTOP_LEVEL_EXCEPTION_FILTER PreviousTopLevelFilter;
  1251. PreviousTopLevelFilter = BasepCurrentTopLevelFilter;
  1252. BasepCurrentTopLevelFilter = lpTopLevelExceptionFilter;
  1253. return PreviousTopLevelFilter;
  1254. }
  1255. LONG
  1256. BasepCheckForReadOnlyResource(
  1257. PVOID Va
  1258. )
  1259. {
  1260. SIZE_T RegionSize;
  1261. ULONG OldProtect;
  1262. NTSTATUS Status;
  1263. MEMORY_BASIC_INFORMATION MemInfo;
  1264. PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
  1265. ULONG ResourceSize;
  1266. char *rbase, *va;
  1267. LONG ReturnValue;
  1268. //
  1269. // Locate the base address that continas this va
  1270. //
  1271. Status = NtQueryVirtualMemory(
  1272. NtCurrentProcess(),
  1273. Va,
  1274. MemoryBasicInformation,
  1275. (PVOID)&MemInfo,
  1276. sizeof(MemInfo),
  1277. NULL
  1278. );
  1279. if ( !NT_SUCCESS(Status) ) {
  1280. return EXCEPTION_CONTINUE_SEARCH;
  1281. }
  1282. //
  1283. // if the va is readonly and in an image then continue
  1284. //
  1285. if ( !((MemInfo.Protect == PAGE_READONLY) && (MemInfo.Type == MEM_IMAGE)) ){
  1286. return EXCEPTION_CONTINUE_SEARCH;
  1287. }
  1288. ReturnValue = EXCEPTION_CONTINUE_SEARCH;
  1289. try {
  1290. ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
  1291. RtlImageDirectoryEntryToData(MemInfo.AllocationBase,
  1292. TRUE,
  1293. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  1294. &ResourceSize
  1295. );
  1296. rbase = (char *)ResourceDirectory;
  1297. va = (char *)Va;
  1298. if ( rbase && va >= rbase && va < rbase+ResourceSize ) {
  1299. RegionSize = 1;
  1300. Status = NtProtectVirtualMemory(
  1301. NtCurrentProcess(),
  1302. &va,
  1303. &RegionSize,
  1304. PAGE_READWRITE,
  1305. &OldProtect
  1306. );
  1307. if ( NT_SUCCESS(Status) ) {
  1308. ReturnValue = EXCEPTION_CONTINUE_EXECUTION;
  1309. }
  1310. }
  1311. }
  1312. except (EXCEPTION_EXECUTE_HANDLER) {
  1313. ;
  1314. }
  1315. return ReturnValue;
  1316. }
  1317. //
  1318. // Used for fault reporting in UnhandledExceptionFilter
  1319. //
  1320. static WCHAR *WStrStrIA(const WCHAR *cs1, const WCHAR *cs2)
  1321. {
  1322. WCHAR *cp = (WCHAR *)cs1;
  1323. WCHAR *s1, *s2;
  1324. while (*cp != L'\0')
  1325. {
  1326. s1 = cp;
  1327. s2 = (WCHAR *)cs2;
  1328. while (*s1 != L'\0' && *s2 !=L'\0' && (towlower(*s1) - towlower(*s2)) == 0)
  1329. s1++, s2++;
  1330. if (*s2 == L'\0')
  1331. return(cp);
  1332. cp++;
  1333. }
  1334. return(NULL);
  1335. }
  1336. LONG
  1337. UnhandledExceptionFilter(
  1338. struct _EXCEPTION_POINTERS *ExceptionInfo
  1339. )
  1340. {
  1341. EFaultRepRetVal frrv = frrvErrNoDW;
  1342. NTSTATUS Status;
  1343. ULONG_PTR Parameters[ 4 ];
  1344. ULONG Response;
  1345. HANDLE DebugPort;
  1346. WCHAR AeDebuggerCmdLine[256];
  1347. CHAR AeAutoDebugString[8];
  1348. BOOLEAN AeAutoDebug;
  1349. ULONG ResponseFlag;
  1350. LONG FilterReturn;
  1351. PRTL_CRITICAL_SECTION PebLockPointer;
  1352. JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimit;
  1353. //
  1354. // If we take a write fault, then attempt to make the memory writable. If this
  1355. // succeeds, then silently proceed.
  1356. //
  1357. if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION
  1358. && ExceptionInfo->ExceptionRecord->ExceptionInformation[0] ) {
  1359. FilterReturn = BasepCheckForReadOnlyResource((PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
  1360. if ( FilterReturn == EXCEPTION_CONTINUE_EXECUTION ) {
  1361. return FilterReturn;
  1362. }
  1363. }
  1364. //
  1365. // If the process is being debugged, just let the exception happen
  1366. // so that the debugger can see it. This way the debugger can ignore
  1367. // all first chance exceptions.
  1368. //
  1369. DebugPort = (HANDLE)NULL;
  1370. Status = NtQueryInformationProcess(
  1371. GetCurrentProcess(),
  1372. ProcessDebugPort,
  1373. (PVOID)&DebugPort,
  1374. sizeof(DebugPort),
  1375. NULL
  1376. );
  1377. if ( NT_SUCCESS(Status) && DebugPort ) {
  1378. //
  1379. // Process is being debugged.
  1380. // Return a code that specifies that the exception
  1381. // processing is to continue
  1382. //
  1383. return EXCEPTION_CONTINUE_SEARCH;
  1384. }
  1385. if ( BasepCurrentTopLevelFilter ) {
  1386. FilterReturn = (BasepCurrentTopLevelFilter)(ExceptionInfo);
  1387. if ( FilterReturn == EXCEPTION_EXECUTE_HANDLER ||
  1388. FilterReturn == EXCEPTION_CONTINUE_EXECUTION ) {
  1389. return FilterReturn;
  1390. }
  1391. }
  1392. if ( (GetErrorMode() & SEM_NOGPFAULTERRORBOX)
  1393. || (RtlGetThreadErrorMode() & RTL_ERRORMODE_NOGPFAULTERRORBOX)) {
  1394. return EXCEPTION_EXECUTE_HANDLER;
  1395. }
  1396. //
  1397. // See if the process's job has been programmed to NOGPFAULTERRORBOX
  1398. //
  1399. Status = NtQueryInformationJobObject(
  1400. NULL,
  1401. JobObjectBasicLimitInformation,
  1402. &BasicLimit,
  1403. sizeof(BasicLimit),
  1404. NULL
  1405. );
  1406. if ( NT_SUCCESS(Status) && (BasicLimit.LimitFlags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION) ) {
  1407. return EXCEPTION_EXECUTE_HANDLER;
  1408. }
  1409. //
  1410. // The process is not being debugged, so do the hard error
  1411. // popup.
  1412. //
  1413. Parameters[ 0 ] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionCode;
  1414. Parameters[ 1 ] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
  1415. //
  1416. // For inpage i/o errors, juggle the real status code to overwrite the
  1417. // read/write field
  1418. //
  1419. if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR ) {
  1420. Parameters[ 2 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 2 ];
  1421. }
  1422. else {
  1423. Parameters[ 2 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 0 ];
  1424. }
  1425. Parameters[ 3 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ];
  1426. //
  1427. // See if a debugger has been programmed in. If so, use the
  1428. // debugger specified. If not then there is no AE Cancel support
  1429. // DEVL systems will default the debugger command line. Retail
  1430. // systems will not.
  1431. // Also, check to see if we need to report the exception up to anyone
  1432. //
  1433. ResponseFlag = OptionOk;
  1434. AeAutoDebug = FALSE;
  1435. //
  1436. // If we are holding the PebLock, then the createprocess will fail
  1437. // because a new thread will also need this lock. Avoid this by peeking
  1438. // inside the PebLock and looking to see if we own it. If we do, then just allow
  1439. // a regular popup.
  1440. //
  1441. PebLockPointer = NtCurrentPeb()->FastPebLock;
  1442. if ( PebLockPointer->OwningThread != NtCurrentTeb()->ClientId.UniqueThread ) {
  1443. HMODULE hmodFaultRep = NULL;
  1444. if (GetProfileStringW(L"AeDebug",
  1445. L"Debugger",
  1446. NULL,
  1447. AeDebuggerCmdLine,
  1448. RTL_NUMBER_OF(AeDebuggerCmdLine)-1)) {
  1449. ResponseFlag = OptionOkCancel;
  1450. }
  1451. if (GetProfileString ("AeDebug",
  1452. "Auto",
  1453. "0",
  1454. AeAutoDebugString,
  1455. sizeof(AeAutoDebugString)-1)) {
  1456. if (!strcmp (AeAutoDebugString, "1")) {
  1457. if (ResponseFlag == OptionOkCancel) {
  1458. AeAutoDebug = TRUE;
  1459. }
  1460. }
  1461. }
  1462. //
  1463. // Attempt to report the fault back to Microsoft. ReportFault
  1464. // will return the following:
  1465. // frrvErrNoDW: Always show our own fault notification.
  1466. //
  1467. // frrvErrTimeout: see frrvOkHeadless
  1468. // frrvOkQueued: see frrvOkHeadless
  1469. // frrvOkHeadless: If we need to ask whether to launch a debugger,
  1470. // then we ask. Otherwise, show nothing else.
  1471. //
  1472. // frrvOk: see frrvOkManifest
  1473. // frrvOkManifest: We're done. Show nothing else.
  1474. //
  1475. // frrvLaunchDebugger: Launch the configured debugger.
  1476. //
  1477. frrv = frrvErrNoDW;
  1478. if ( BasepAlreadyHadHardError == FALSE &&
  1479. (AeAutoDebug == FALSE ||
  1480. WStrStrIA(AeDebuggerCmdLine, L"drwtsn32") != NULL)) {
  1481. WCHAR wszDll[MAX_PATH];
  1482. PVOID pvLdrLockCookie = NULL;
  1483. ULONG ulLockState = 0;
  1484. /*
  1485. * Insure that we get the full %sys32%\faultrep.dll" correctly formed path,
  1486. * or else we can fail in a well mannered way.
  1487. */
  1488. if (GetSystemDirectoryW(wszDll, (sizeof(wszDll) / sizeof(WCHAR)) - 1 - wcslen (L"\\faultrep.dll")))
  1489. {
  1490. wcscat(wszDll, L"\\faultrep.dll");
  1491. }
  1492. else
  1493. wszDll[0] = 0;
  1494. // make sure that no one else owns the loader lock because we
  1495. // could otherwise deadlock
  1496. LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY, &ulLockState,
  1497. &pvLdrLockCookie);
  1498. if (ulLockState == LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED) {
  1499. hmodFaultRep = LoadLibraryExW(wszDll, NULL, 0);
  1500. LdrUnlockLoaderLock(0, pvLdrLockCookie);
  1501. }
  1502. if (hmodFaultRep != NULL) {
  1503. pfn_REPORTFAULT pfn;
  1504. DWORD dwDebug;
  1505. // parameter 2 to ReportFault should be:
  1506. // froNoDebugWait: don't display a debug button but wait
  1507. // for DW to finish- this is a special
  1508. // case to make sure DW is done before
  1509. // Dr. Watson starts
  1510. // froNoDebugWait : don't display a debug button
  1511. // froDebug : display a debug button and wait for DW to
  1512. // finish
  1513. if (ResponseFlag == OptionOkCancel) {
  1514. dwDebug = (AeAutoDebug) ? froNoDebugWait : froDebug;
  1515. } else {
  1516. dwDebug = froNoDebug;
  1517. }
  1518. pfn = (pfn_REPORTFAULT)GetProcAddress(hmodFaultRep,
  1519. "ReportFault");
  1520. if (pfn != NULL)
  1521. frrv = (*pfn)(ExceptionInfo, dwDebug);
  1522. FreeLibrary(hmodFaultRep);
  1523. hmodFaultRep = NULL;
  1524. }
  1525. }
  1526. //
  1527. // Since we're supposed to launch the debugger anyway, just set the
  1528. // AeAutoDebug flag to true to minimize code munging below
  1529. //
  1530. if ( frrv == frrvLaunchDebugger ) {
  1531. AeAutoDebug = TRUE;
  1532. }
  1533. }
  1534. //
  1535. // only display this dialog if we couldn't show DW & we're not set to
  1536. // automatically launch a debugger. The conditions here are:
  1537. // 1. cannot be directly launching a debugger (auto == 1)
  1538. // 2a. DW must have failed to launch
  1539. // -or-
  1540. // we needed to ask the user if he wanted to debug but could not (due
  1541. // to either no UI being shown or us not being able to wait long enuf
  1542. // to find out.)
  1543. if ( !AeAutoDebug &&
  1544. ( frrv == frrvErrNoDW ||
  1545. ( ResponseFlag == OptionOkCancel &&
  1546. ( frrv == frrvErrTimeout || frrv == frrvOkQueued ||
  1547. frrv == frrvOkHeadless ) ) ) )
  1548. {
  1549. Status =NtRaiseHardError( STATUS_UNHANDLED_EXCEPTION | HARDERROR_OVERRIDE_ERRORMODE,
  1550. 4,
  1551. 0,
  1552. Parameters,
  1553. BasepAlreadyHadHardError ? OptionOk : ResponseFlag,
  1554. &Response
  1555. );
  1556. }
  1557. else {
  1558. Status = STATUS_SUCCESS;
  1559. Response = (AeAutoDebug) ? ResponseCancel : ResponseOk;
  1560. }
  1561. //
  1562. // Internally, send OkCancel. If we get back Ok then die.
  1563. // If we get back Cancel, then enter the debugger
  1564. //
  1565. if ( NT_SUCCESS(Status) && Response == ResponseCancel && BasepAlreadyHadHardError == FALSE) {
  1566. if ( !BaseRunningInServerProcess ) {
  1567. BOOL b = FALSE;
  1568. STARTUPINFOW StartupInfo;
  1569. PROCESS_INFORMATION ProcessInformation;
  1570. PWCHAR CmdLine;
  1571. NTSTATUS Status;
  1572. HANDLE EventHandle;
  1573. SECURITY_ATTRIBUTES sa;
  1574. HANDLE CurrentProcess;
  1575. HANDLE CurrentThread;
  1576. ULONG cchSysDir;
  1577. // 21 => 10 for the pid, 10 for the handle, 1 for the
  1578. // trailing null.
  1579. ULONG cchAeCmdLine = wcslen(AeDebuggerCmdLine) + 21;
  1580. //
  1581. // Duplicate the processes handle. We make it inheritable so the debugger will get a copy of it.
  1582. // We do this to prevent the process ID from being reused if this process gets killed before the
  1583. // attach occurs. Process ID are reused very quickly and attaching to the wrong process is
  1584. // confusing.
  1585. //
  1586. if (!DuplicateHandle (GetCurrentProcess (),
  1587. GetCurrentProcess (),
  1588. GetCurrentProcess (),
  1589. &CurrentProcess,
  1590. 0,
  1591. TRUE,
  1592. DUPLICATE_SAME_ACCESS)) {
  1593. CurrentProcess = NULL;
  1594. }
  1595. if (!DuplicateHandle (GetCurrentProcess (),
  1596. GetCurrentThread (),
  1597. GetCurrentProcess (),
  1598. &CurrentThread,
  1599. 0,
  1600. TRUE,
  1601. DUPLICATE_SAME_ACCESS)) {
  1602. CurrentThread = NULL;
  1603. }
  1604. sa.nLength = sizeof(sa);
  1605. sa.lpSecurityDescriptor = NULL;
  1606. sa.bInheritHandle = TRUE;
  1607. EventHandle = CreateEvent(&sa,TRUE,FALSE,NULL);
  1608. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  1609. //
  1610. // If there's a leading quote, assume that the writer of
  1611. // the regkey knew what it was doing. Otherwise, if it's
  1612. // not a relative name, assume the writer knew what it was
  1613. // doing.
  1614. //
  1615. if (AeDebuggerCmdLine[0] != L'\"'
  1616. && RtlDetermineDosPathNameType_U(AeDebuggerCmdLine)
  1617. == RtlPathTypeRelative) {
  1618. //
  1619. // There's no leading quote, and it's a relative name
  1620. // -- so force it into the system directory
  1621. //
  1622. cchSysDir = GetSystemDirectoryW(NULL, 0);
  1623. if (!cchSysDir || (cchSysDir + cchAeCmdLine + 1) > MAX_PATH) {
  1624. // MAX_PATH is the limit to what we're willing to allocate.
  1625. goto cleanup;
  1626. }
  1627. try {
  1628. CmdLine = (PWCHAR) _alloca((cchSysDir + cchAeCmdLine + 1)
  1629. * sizeof(WCHAR));
  1630. } except (EXCEPTION_EXECUTE_HANDLER) {
  1631. goto cleanup;
  1632. }
  1633. cchSysDir = GetSystemDirectoryW(CmdLine, cchSysDir);
  1634. if (! cchSysDir) {
  1635. goto cleanup;
  1636. }
  1637. if (CmdLine[cchSysDir - 1] != L'\\') {
  1638. CmdLine[cchSysDir] = L'\\';
  1639. cchSysDir++;
  1640. }
  1641. } else {
  1642. cchSysDir = 0;
  1643. if (cchAeCmdLine > MAX_PATH) {
  1644. // MAX_PATH is the limit to what we're willing to allocate.
  1645. goto cleanup;
  1646. }
  1647. try {
  1648. CmdLine = (PWCHAR) _alloca(cchAeCmdLine * sizeof(WCHAR));
  1649. } except (EXCEPTION_EXECUTE_HANDLER) {
  1650. goto cleanup;
  1651. }
  1652. }
  1653. if (FAILED(StringCchPrintfW(CmdLine + cchSysDir,
  1654. cchAeCmdLine,
  1655. AeDebuggerCmdLine,
  1656. GetCurrentProcessId(),EventHandle))) {
  1657. goto cleanup;
  1658. }
  1659. StartupInfo.cb = sizeof(StartupInfo);
  1660. StartupInfo.lpDesktop = L"Winsta0\\Default";
  1661. CsrIdentifyAlertableThread();
  1662. b = CreateProcessW(
  1663. NULL,
  1664. CmdLine,
  1665. NULL,
  1666. NULL,
  1667. TRUE,
  1668. 0,
  1669. NULL,
  1670. NULL,
  1671. &StartupInfo,
  1672. &ProcessInformation
  1673. );
  1674. cleanup:
  1675. if (CurrentProcess != NULL) {
  1676. CloseHandle (CurrentProcess);
  1677. }
  1678. if (CurrentThread != NULL) {
  1679. CloseHandle (CurrentThread);
  1680. }
  1681. if ( b && EventHandle) {
  1682. //
  1683. // Do an alertable wait on the event
  1684. //
  1685. do {
  1686. HANDLE WaitHandles[2];
  1687. WaitHandles[0] = EventHandle;
  1688. WaitHandles[1] = ProcessInformation.hProcess;
  1689. Status = NtWaitForMultipleObjects (2,
  1690. WaitHandles,
  1691. WaitAny,
  1692. TRUE,
  1693. NULL);
  1694. } while (Status == STATUS_USER_APC || Status == STATUS_ALERTED);
  1695. //
  1696. // If the debugger process died then see if the debugger is now
  1697. // attached by another thread
  1698. //
  1699. if (Status == 1) {
  1700. Status = NtQueryInformationProcess (GetCurrentProcess(),
  1701. ProcessDebugPort,
  1702. &DebugPort,
  1703. sizeof (DebugPort),
  1704. NULL);
  1705. if (!NT_SUCCESS (Status) || DebugPort == NULL) {
  1706. BasepAlreadyHadHardError = TRUE;
  1707. }
  1708. }
  1709. CloseHandle (EventHandle);
  1710. CloseHandle (ProcessInformation.hProcess);
  1711. CloseHandle (ProcessInformation.hThread);
  1712. return EXCEPTION_CONTINUE_SEARCH;
  1713. }
  1714. }
  1715. BasepAlreadyHadHardError = TRUE;
  1716. }
  1717. #if DBG
  1718. if (!NT_SUCCESS( Status )) {
  1719. DbgPrint( "BASEDLL: Unhandled exception: %lx IP: %x\n",
  1720. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1721. ExceptionInfo->ExceptionRecord->ExceptionAddress
  1722. );
  1723. }
  1724. #endif
  1725. if ( BasepAlreadyHadHardError ) {
  1726. NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode);
  1727. }
  1728. return EXCEPTION_EXECUTE_HANDLER;
  1729. }
  1730. DWORD
  1731. APIENTRY
  1732. TlsAlloc(
  1733. VOID
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. A TLS index may be allocated using TlsAlloc. Win32 garuntees a
  1738. minimum number of TLS indexes are available in each process. The
  1739. constant TLS_MINIMUM_AVAILABLE defines the minimum number of
  1740. available indexes. This minimum is at least 64 for all Win32
  1741. systems.
  1742. Arguments:
  1743. None.
  1744. Return Value:
  1745. Not-0xffffffff - Returns a TLS index that may be used in a
  1746. subsequent call to TlsFree, TlsSetValue, or TlsGetValue. The
  1747. storage associated with the index is initialized to NULL.
  1748. 0xffffffff - The operation failed. Extended error status is available
  1749. using GetLastError.
  1750. --*/
  1751. {
  1752. PPEB Peb;
  1753. PTEB Teb;
  1754. DWORD Index;
  1755. Teb = NtCurrentTeb();
  1756. Peb = Teb->ProcessEnvironmentBlock;
  1757. RtlAcquirePebLock();
  1758. try {
  1759. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsBitmap,1,0);
  1760. if ( Index == 0xffffffff ) {
  1761. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsExpansionBitmap,1,0);
  1762. if ( Index == 0xffffffff ) {
  1763. BaseSetLastNTError(STATUS_NO_MEMORY);
  1764. }
  1765. else {
  1766. if ( !Teb->TlsExpansionSlots ) {
  1767. Teb->TlsExpansionSlots = RtlAllocateHeap(
  1768. RtlProcessHeap(),
  1769. MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
  1770. TLS_EXPANSION_SLOTS * sizeof(PVOID)
  1771. );
  1772. if ( !Teb->TlsExpansionSlots ) {
  1773. RtlClearBits((PRTL_BITMAP)Peb->TlsExpansionBitmap,Index,1);
  1774. Index = 0xffffffff;
  1775. BaseSetLastNTError(STATUS_NO_MEMORY);
  1776. leave;
  1777. }
  1778. }
  1779. Teb->TlsExpansionSlots[Index] = NULL;
  1780. Index += TLS_MINIMUM_AVAILABLE;
  1781. }
  1782. }
  1783. else {
  1784. Teb->TlsSlots[Index] = NULL;
  1785. }
  1786. }
  1787. finally {
  1788. RtlReleasePebLock();
  1789. }
  1790. return Index;
  1791. }
  1792. LPVOID
  1793. APIENTRY
  1794. TlsGetValue(
  1795. DWORD dwTlsIndex
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. This function is used to retrive the value in the TLS storage
  1800. associated with the specified index.
  1801. If the index is valid this function clears the value returned by
  1802. GetLastError(), and returns the value stored in the TLS slot
  1803. associated with the specified index. Otherwise a value of NULL is
  1804. returned with GetLastError updated appropriately.
  1805. It is expected, that DLLs will use TlsAlloc and TlsGetValue as
  1806. follows:
  1807. - Upon DLL initialization, a TLS index will be allocated using
  1808. TlsAlloc. The DLL will then allocate some dynamic storage and
  1809. store its address in the TLS slot using TlsSetValue. This
  1810. completes the per thread initialization for the initial thread
  1811. of the process. The TLS index is stored in instance data for
  1812. the DLL.
  1813. - Each time a new thread attaches to the DLL, the DLL will
  1814. allocate some dynamic storage and store its address in the TLS
  1815. slot using TlsSetValue. This completes the per thread
  1816. initialization for the new thread.
  1817. - Each time an initialized thread makes a DLL call requiring the
  1818. TLS, the DLL will call TlsGetValue to get the TLS data for the
  1819. thread.
  1820. Arguments:
  1821. dwTlsIndex - Supplies a TLS index allocated using TlsAlloc. The
  1822. index specifies which TLS slot is to be located. Translating a
  1823. TlsIndex does not prevent a TlsFree call from proceding.
  1824. Return Value:
  1825. NON-NULL - The function was successful. The value is the data stored
  1826. in the TLS slot associated with the specified index.
  1827. NULL - The operation failed, or the value associated with the
  1828. specified index was NULL. Extended error status is available
  1829. using GetLastError. If this returns non-zero, the index was
  1830. invalid.
  1831. --*/
  1832. {
  1833. PTEB Teb;
  1834. LPVOID *Slot;
  1835. Teb = NtCurrentTeb();
  1836. if ( dwTlsIndex < TLS_MINIMUM_AVAILABLE ) {
  1837. Slot = &Teb->TlsSlots[dwTlsIndex];
  1838. Teb->LastErrorValue = 0;
  1839. return *Slot;
  1840. }
  1841. else {
  1842. if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE+TLS_EXPANSION_SLOTS ) {
  1843. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1844. return NULL;
  1845. }
  1846. else {
  1847. Teb->LastErrorValue = 0;
  1848. if ( Teb->TlsExpansionSlots ) {
  1849. return Teb->TlsExpansionSlots[dwTlsIndex-TLS_MINIMUM_AVAILABLE];
  1850. }
  1851. else {
  1852. return NULL;
  1853. }
  1854. }
  1855. }
  1856. }
  1857. BOOL
  1858. APIENTRY
  1859. TlsSetValue(
  1860. DWORD dwTlsIndex,
  1861. LPVOID lpTlsValue
  1862. )
  1863. /*++
  1864. Routine Description:
  1865. This function is used to store a value in the TLS storage associated
  1866. with the specified index.
  1867. If the index is valid this function stores the value and returns
  1868. TRUE. Otherwise a value of FALSE is returned.
  1869. It is expected, that DLLs will use TlsAlloc and TlsSetValue as
  1870. follows:
  1871. - Upon DLL initialization, a TLS index will be allocated using
  1872. TlsAlloc. The DLL will then allocate some dynamic storage and
  1873. store its address in the TLS slot using TlsSetValue. This
  1874. completes the per thread initialization for the initial thread
  1875. of the process. The TLS index is stored in instance data for
  1876. the DLL.
  1877. - Each time a new thread attaches to the DLL, the DLL will
  1878. allocate some dynamic storage and store its address in the TLS
  1879. slot using TlsSetValue. This completes the per thread
  1880. initialization for the new thread.
  1881. - Each time an initialized thread makes a DLL call requiring the
  1882. TLS, the DLL will call TlsGetValue to get the TLS data for the
  1883. thread.
  1884. Arguments:
  1885. dwTlsIndex - Supplies a TLS index allocated using TlsAlloc. The
  1886. index specifies which TLS slot is to be located. Translating a
  1887. TlsIndex does not prevent a TlsFree call from proceding.
  1888. lpTlsValue - Supplies the value to be stored in the TLS Slot.
  1889. Return Value:
  1890. TRUE - The function was successful. The value lpTlsValue was
  1891. stored.
  1892. FALSE - The operation failed. Extended error status is available
  1893. using GetLastError.
  1894. --*/
  1895. {
  1896. PTEB Teb;
  1897. Teb = NtCurrentTeb();
  1898. if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE ) {
  1899. dwTlsIndex -= TLS_MINIMUM_AVAILABLE;
  1900. if ( dwTlsIndex < TLS_EXPANSION_SLOTS ) {
  1901. if ( !Teb->TlsExpansionSlots ) {
  1902. RtlAcquirePebLock();
  1903. if ( !Teb->TlsExpansionSlots ) {
  1904. Teb->TlsExpansionSlots = RtlAllocateHeap(
  1905. RtlProcessHeap(),
  1906. MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
  1907. TLS_EXPANSION_SLOTS * sizeof(PVOID)
  1908. );
  1909. if ( !Teb->TlsExpansionSlots ) {
  1910. RtlReleasePebLock();
  1911. BaseSetLastNTError(STATUS_NO_MEMORY);
  1912. return FALSE;
  1913. }
  1914. }
  1915. RtlReleasePebLock();
  1916. }
  1917. Teb->TlsExpansionSlots[dwTlsIndex] = lpTlsValue;
  1918. }
  1919. else {
  1920. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1921. return FALSE;
  1922. }
  1923. }
  1924. else {
  1925. Teb->TlsSlots[dwTlsIndex] = lpTlsValue;
  1926. }
  1927. return TRUE;
  1928. }
  1929. BOOL
  1930. APIENTRY
  1931. TlsFree(
  1932. DWORD dwTlsIndex
  1933. )
  1934. /*++
  1935. Routine Description:
  1936. A valid TLS index may be free'd using TlsFree.
  1937. Arguments:
  1938. dwTlsIndex - Supplies a TLS index allocated using TlsAlloc. If the
  1939. index is a valid index, it is released by this call and is made
  1940. available for reuse. DLLs should be carefull to release any
  1941. per-thread data pointed to by all of their threads TLS slots
  1942. before calling this function. It is expected that DLLs will
  1943. only call this function (if at ALL) during their process detach
  1944. routine.
  1945. Return Value:
  1946. TRUE - The operation was successful. Calling TlsTranslateIndex with
  1947. this index will fail. TlsAlloc is free to reallocate this
  1948. index.
  1949. FALSE - The operation failed. Extended error status is available
  1950. using GetLastError.
  1951. --*/
  1952. {
  1953. PPEB Peb;
  1954. BOOLEAN ValidIndex;
  1955. PRTL_BITMAP TlsBitmap;
  1956. NTSTATUS Status;
  1957. DWORD Index2;
  1958. Peb = NtCurrentPeb();
  1959. RtlAcquirePebLock();
  1960. try {
  1961. if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE ) {
  1962. Index2 = dwTlsIndex - TLS_MINIMUM_AVAILABLE;
  1963. if ( Index2 >= TLS_EXPANSION_SLOTS ) {
  1964. ValidIndex = FALSE;
  1965. }
  1966. else {
  1967. TlsBitmap = (PRTL_BITMAP)Peb->TlsExpansionBitmap;
  1968. ValidIndex = RtlAreBitsSet(TlsBitmap,Index2,1);
  1969. }
  1970. }
  1971. else {
  1972. TlsBitmap = (PRTL_BITMAP)Peb->TlsBitmap;
  1973. Index2 = dwTlsIndex;
  1974. ValidIndex = RtlAreBitsSet(TlsBitmap,Index2,1);
  1975. }
  1976. if ( ValidIndex ) {
  1977. Status = NtSetInformationThread(
  1978. NtCurrentThread(),
  1979. ThreadZeroTlsCell,
  1980. &dwTlsIndex,
  1981. sizeof(dwTlsIndex)
  1982. );
  1983. if ( !NT_SUCCESS(Status) ) {
  1984. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1985. ValidIndex = FALSE;
  1986. leave;
  1987. }
  1988. RtlClearBits(TlsBitmap,Index2,1);
  1989. }
  1990. else {
  1991. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1992. }
  1993. }
  1994. finally {
  1995. RtlReleasePebLock();
  1996. }
  1997. return ValidIndex;
  1998. }
  1999. BOOL
  2000. WINAPI
  2001. GetThreadTimes(
  2002. HANDLE hThread,
  2003. LPFILETIME lpCreationTime,
  2004. LPFILETIME lpExitTime,
  2005. LPFILETIME lpKernelTime,
  2006. LPFILETIME lpUserTime
  2007. )
  2008. /*++
  2009. Routine Description:
  2010. This function is used to return various timing information about the
  2011. thread specified by hThread.
  2012. All times are in units of 100ns increments. For lpCreationTime and lpExitTime,
  2013. the times are in terms of the SYSTEM time or GMT time.
  2014. Arguments:
  2015. hThread - Supplies an open handle to the specified thread. The
  2016. handle must have been created with THREAD_QUERY_INFORMATION
  2017. access.
  2018. lpCreationTime - Returns a creation time of the thread.
  2019. lpExitTime - Returns the exit time of a thread. If the thread has
  2020. not exited, this value is not defined.
  2021. lpKernelTime - Returns the amount of time that this thread has
  2022. executed in kernel-mode.
  2023. lpUserTime - Returns the amount of time that this thread has
  2024. executed in user-mode.
  2025. Return Value:
  2026. TRUE - The API was successful
  2027. FALSE - The operation failed. Extended error status is available
  2028. using GetLastError.
  2029. --*/
  2030. {
  2031. NTSTATUS Status;
  2032. KERNEL_USER_TIMES TimeInfo;
  2033. Status = NtQueryInformationThread(
  2034. hThread,
  2035. ThreadTimes,
  2036. (PVOID)&TimeInfo,
  2037. sizeof(TimeInfo),
  2038. NULL
  2039. );
  2040. if ( !NT_SUCCESS(Status) ) {
  2041. BaseSetLastNTError(Status);
  2042. return FALSE;
  2043. }
  2044. *lpCreationTime = *(LPFILETIME)&TimeInfo.CreateTime;
  2045. *lpExitTime = *(LPFILETIME)&TimeInfo.ExitTime;
  2046. *lpKernelTime = *(LPFILETIME)&TimeInfo.KernelTime;
  2047. *lpUserTime = *(LPFILETIME)&TimeInfo.UserTime;
  2048. return TRUE;
  2049. }
  2050. BOOL
  2051. WINAPI
  2052. GetThreadIOPendingFlag(
  2053. IN HANDLE hThread,
  2054. OUT PBOOL lpIOIsPending
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. This function is used to determine whether the thread in question
  2059. has any IO requests pending.
  2060. Arguments:
  2061. hThread - Specifies an open handle to the desired thread. The
  2062. handle must have been created with
  2063. THREAD_QUERY_INFORMATION access.
  2064. lpIOIsPending - Specifes the location to receive the flag.
  2065. Return Value:
  2066. TRUE - The call was successful.
  2067. FALSE - The call failed. Extended error status is available
  2068. using GetLastError().
  2069. --*/
  2070. {
  2071. NTSTATUS Status;
  2072. ULONG Pending;
  2073. Status = NtQueryInformationThread(hThread,
  2074. ThreadIsIoPending,
  2075. &Pending,
  2076. sizeof(Pending),
  2077. NULL);
  2078. if (! NT_SUCCESS(Status)) {
  2079. BaseSetLastNTError(Status);
  2080. return FALSE;
  2081. }
  2082. *lpIOIsPending = (Pending ? TRUE : FALSE);
  2083. return TRUE;
  2084. }
  2085. DWORD_PTR
  2086. WINAPI
  2087. SetThreadAffinityMask(
  2088. HANDLE hThread,
  2089. DWORD_PTR dwThreadAffinityMask
  2090. )
  2091. /*++
  2092. Routine Description:
  2093. This function is used to set the specified thread's processor
  2094. affinity mask. The thread affinity mask is a bit vector where each
  2095. bit represents the processors that the thread is allowed to run on.
  2096. The affinity mask MUST be a proper subset of the containing process'
  2097. process level affinity mask.
  2098. Arguments:
  2099. hThread - Supplies a handle to the thread whose priority is to be
  2100. set. The handle must have been created with
  2101. THREAD_SET_INFORMATION access.
  2102. dwThreadAffinityMask - Supplies the affinity mask to be used for the
  2103. specified thread.
  2104. Return Value:
  2105. non-0 - The API was successful. The return value is the previous
  2106. affinity mask for the thread.
  2107. 0 - The operation failed. Extended error status is available
  2108. using GetLastError.
  2109. --*/
  2110. {
  2111. THREAD_BASIC_INFORMATION BasicInformation;
  2112. NTSTATUS Status;
  2113. DWORD_PTR rv;
  2114. DWORD_PTR LocalThreadAffinityMask;
  2115. Status = NtQueryInformationThread(
  2116. hThread,
  2117. ThreadBasicInformation,
  2118. &BasicInformation,
  2119. sizeof(BasicInformation),
  2120. NULL
  2121. );
  2122. if ( !NT_SUCCESS(Status) ) {
  2123. rv = 0;
  2124. }
  2125. else {
  2126. LocalThreadAffinityMask = dwThreadAffinityMask;
  2127. Status = NtSetInformationThread(
  2128. hThread,
  2129. ThreadAffinityMask,
  2130. &LocalThreadAffinityMask,
  2131. sizeof(LocalThreadAffinityMask)
  2132. );
  2133. if ( !NT_SUCCESS(Status) ) {
  2134. rv = 0;
  2135. }
  2136. else {
  2137. rv = BasicInformation.AffinityMask;
  2138. }
  2139. }
  2140. if ( !rv ) {
  2141. BaseSetLastNTError(Status);
  2142. }
  2143. return rv;
  2144. }
  2145. VOID
  2146. BaseDispatchAPC(
  2147. LPVOID lpApcArgument1,
  2148. LPVOID lpApcArgument2,
  2149. LPVOID lpApcArgument3
  2150. )
  2151. {
  2152. PAPCFUNC pfnAPC;
  2153. ULONG_PTR dwData;
  2154. PACTIVATION_CONTEXT ActivationContext;
  2155. NTSTATUS Status;
  2156. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  2157. pfnAPC = (PAPCFUNC) lpApcArgument1;
  2158. dwData = (ULONG_PTR) lpApcArgument2;
  2159. ActivationContext = (PACTIVATION_CONTEXT) lpApcArgument3;
  2160. if (ActivationContext == INVALID_ACTIVATION_CONTEXT) {
  2161. (*pfnAPC)(dwData);
  2162. } else {
  2163. RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext);
  2164. __try {
  2165. (*pfnAPC)(dwData);
  2166. } __finally {
  2167. RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
  2168. RtlReleaseActivationContext(ActivationContext);
  2169. }
  2170. }
  2171. }
  2172. WINBASEAPI
  2173. DWORD
  2174. WINAPI
  2175. QueueUserAPC(
  2176. PAPCFUNC pfnAPC,
  2177. HANDLE hThread,
  2178. ULONG_PTR dwData
  2179. )
  2180. /*++
  2181. Routine Description:
  2182. This function is used to queue a user-mode APC to the specified thread. The APC
  2183. will fire when the specified thread does an alertable wait.
  2184. Arguments:
  2185. pfnAPC - Supplies the address of the APC routine to execute when the
  2186. APC fires.
  2187. hHandle - Supplies a handle to a thread object. The caller
  2188. must have THREAD_SET_CONTEXT access to the thread.
  2189. dwData - Supplies a DWORD passed to the APC
  2190. Return Value:
  2191. TRUE - The operations was successful
  2192. FALSE - The operation failed. GetLastError() is not defined.
  2193. --*/
  2194. {
  2195. NTSTATUS Status;
  2196. PVOID Argument1 = (PVOID) pfnAPC;
  2197. PVOID Argument2 = (PVOID) dwData;
  2198. PVOID Argument3 = NULL;
  2199. ACTIVATION_CONTEXT_BASIC_INFORMATION acbi = { 0 };
  2200. Status =
  2201. RtlQueryInformationActivationContext(
  2202. RTL_QUERY_INFORMATION_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
  2203. NULL,
  2204. 0,
  2205. ActivationContextBasicInformation,
  2206. &acbi,
  2207. sizeof(acbi),
  2208. NULL);
  2209. if (!NT_SUCCESS(Status)) {
  2210. DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext() returned status %08lx\n", __FUNCTION__, Status);
  2211. return FALSE;
  2212. }
  2213. Argument3 = acbi.ActivationContext;
  2214. if (acbi.Flags & ACTIVATION_CONTEXT_FLAG_NO_INHERIT) {
  2215. // We're not supposed to propogate the activation context; set it to a value to indicate such.
  2216. Argument3 = INVALID_ACTIVATION_CONTEXT;
  2217. }
  2218. Status = NtQueueApcThread(
  2219. hThread,
  2220. &BaseDispatchAPC,
  2221. Argument1,
  2222. Argument2,
  2223. Argument3
  2224. );
  2225. if ( !NT_SUCCESS(Status) ) {
  2226. return 0;
  2227. }
  2228. return 1;
  2229. }
  2230. DWORD
  2231. WINAPI
  2232. SetThreadIdealProcessor(
  2233. HANDLE hThread,
  2234. DWORD dwIdealProcessor
  2235. )
  2236. {
  2237. NTSTATUS Status;
  2238. ULONG rv;
  2239. Status = NtSetInformationThread(
  2240. hThread,
  2241. ThreadIdealProcessor,
  2242. &dwIdealProcessor,
  2243. sizeof(dwIdealProcessor)
  2244. );
  2245. if ( !NT_SUCCESS(Status) ) {
  2246. rv = (DWORD)0xFFFFFFFF;
  2247. BaseSetLastNTError(Status);
  2248. }
  2249. else {
  2250. rv = (ULONG)Status;
  2251. }
  2252. return rv;
  2253. }
  2254. DWORD
  2255. APIENTRY
  2256. FlsAlloc (
  2257. IN PFLS_CALLBACK_FUNCTION lpCallback OPTIONAL
  2258. )
  2259. /*++
  2260. Routine Description:
  2261. This function allocates a fiber local storage index.
  2262. N.B. Fiber local storage is per fiber per thread and is context switched
  2263. on fiber switches. Fiber local storage indexes are allocate across
  2264. a process.
  2265. Arguments:
  2266. lpCallback - Supplies an optional pointer to a callback function.
  2267. Return Value:
  2268. If no fiber local storage index is available, then the last error value
  2269. is set and the distinguished value 0xffffffff is returned. Otherwise,
  2270. the callback function address is saved and the allocated fiber local
  2271. storage index is returned.
  2272. --*/
  2273. {
  2274. DWORD Index;
  2275. PPEB Peb;
  2276. PTEB Teb;
  2277. //
  2278. // Attempt to allocate a fiber local storage index.
  2279. //
  2280. Teb = NtCurrentTeb();
  2281. Peb = Teb->ProcessEnvironmentBlock;
  2282. RtlAcquirePebLock();
  2283. try {
  2284. //
  2285. // Search for the first free entry in the fiber local storage
  2286. // bitmap.
  2287. //
  2288. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->FlsBitmap, 1, 0);
  2289. //
  2290. // If no fiber local storage is available, then set the last error
  2291. // value and return the distinguished value.
  2292. //
  2293. if (Index == 0xffffffff) {
  2294. BaseSetLastNTError(STATUS_NO_MEMORY);
  2295. } else {
  2296. //
  2297. // A fiber local storage index was successfully allocated.
  2298. //
  2299. // If a callback function array has not yet been allocated,
  2300. // then allocate it now.
  2301. //
  2302. if (Peb->FlsCallback == NULL) {
  2303. Peb->FlsCallback = RtlAllocateHeap(Peb->ProcessHeap,
  2304. MAKE_TAG(TMP_TAG) | HEAP_ZERO_MEMORY,
  2305. FLS_MAXIMUM_AVAILABLE * sizeof(PVOID));
  2306. //
  2307. // If a callback function array was not allocated, then clear
  2308. // the allocated slot in the bitmap, set the last error value,
  2309. // and return the distinguished value.
  2310. //
  2311. if (Peb->FlsCallback == NULL) {
  2312. RtlClearBits((PRTL_BITMAP)Peb->FlsBitmap, Index, 1);
  2313. Index = 0xffffffff;
  2314. BaseSetLastNTError(STATUS_NO_MEMORY);
  2315. leave;
  2316. }
  2317. }
  2318. //
  2319. // If the fiber local storage data structure has not yet been
  2320. // allocated for the current thread, then attempt to allocate
  2321. // it now.
  2322. //
  2323. if (Teb->FlsData == NULL) {
  2324. Teb->FlsData = RtlAllocateHeap(Peb->ProcessHeap,
  2325. MAKE_TAG(TMP_TAG) | HEAP_ZERO_MEMORY,
  2326. sizeof(FLS_DATA));
  2327. //
  2328. // If a fiber local storage data structure was allocated, then
  2329. // insert the allocated data structure in the process local
  2330. // storage data structure list. Otherwise, clear the allocated
  2331. // slot in the bitmap, set the last error value, return the
  2332. // distuiguished value.
  2333. //
  2334. if (Teb->FlsData != NULL) {
  2335. InsertTailList(&Peb->FlsListHead,
  2336. &((PFLS_DATA)Teb->FlsData)->Entry);
  2337. } else {
  2338. RtlClearBits((PRTL_BITMAP)Peb->FlsBitmap, Index, 1);
  2339. Index = 0xffffffff;
  2340. BaseSetLastNTError(STATUS_NO_MEMORY);
  2341. leave;
  2342. }
  2343. }
  2344. //
  2345. // Initialize the free function callback address and the fiber
  2346. // local storage value.
  2347. //
  2348. Peb->FlsCallback[Index] = lpCallback;
  2349. ((PFLS_DATA)Teb->FlsData)->Slots[Index] = NULL;
  2350. //
  2351. // If the allocated index is greater than the highest allocated
  2352. // index, then save the new high.
  2353. //
  2354. if (Index > Peb->FlsHighIndex) {
  2355. Peb->FlsHighIndex = Index;
  2356. }
  2357. }
  2358. } finally {
  2359. RtlReleasePebLock();
  2360. }
  2361. return Index;
  2362. }
  2363. PVOID
  2364. APIENTRY
  2365. FlsGetValue (
  2366. DWORD dwFlsIndex
  2367. )
  2368. /*++
  2369. Routine Description:
  2370. This function retrieves a value from the fiber local storage data entry
  2371. specified by the index value.
  2372. N.B. This routine is not synchronized with the possible freeing of
  2373. the specified fiber local storage slot. Therefore, it is possible
  2374. to get stale data. If this type of synchronization is desired it
  2375. must be supplied by the caller.
  2376. Arguments:
  2377. dwFlsIndex - Supplies a fiber local storage index.
  2378. Return Value:
  2379. If the specified fiber local storage index is valid, then the last error
  2380. value is cleared and the value of the fiber local storage data entry is
  2381. returned. Otherwise, the last error value is set and a value of NULL is
  2382. returned.
  2383. --*/
  2384. {
  2385. PTEB Teb;
  2386. //
  2387. // If the fiber local storage index is invalid or the fiber local storage
  2388. // data structure has not been allocated, then set the last error value
  2389. // and return NULL. Otherwise, return the specified value from fiber local
  2390. // storage data.
  2391. //
  2392. Teb = NtCurrentTeb();
  2393. if ((dwFlsIndex > 0) &&
  2394. (dwFlsIndex < FLS_MAXIMUM_AVAILABLE) &&
  2395. (Teb->FlsData != NULL)) {
  2396. ASSERT(RtlAreBitsSet((PRTL_BITMAP)NtCurrentPeb()->FlsBitmap, dwFlsIndex, 1));
  2397. ASSERT(dwFlsIndex <= NtCurrentPeb()->FlsHighIndex);
  2398. Teb->LastErrorValue = 0;
  2399. return ((PFLS_DATA)Teb->FlsData)->Slots[dwFlsIndex];
  2400. } else {
  2401. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  2402. return NULL;
  2403. }
  2404. }
  2405. BOOL
  2406. APIENTRY
  2407. FlsSetValue (
  2408. DWORD dwFlsIndex,
  2409. IN PVOID lpFlsData
  2410. )
  2411. /*++
  2412. Routine Description:
  2413. This function stores a value in the fiber local storage data entry
  2414. specified by the index value.
  2415. N.B. This routine is not synchronized with the possible freeing of
  2416. the specified fiber local storage slot. Therefore, it is possible
  2417. to set stale data. If this type of synchronization is desired it
  2418. must be supplied by the caller.
  2419. Arguments:
  2420. dwTlsIndex - Supplies a fiber local storage index.
  2421. lpFlsData - Supplies the value to be stored in the fiber local storage
  2422. data entry.
  2423. Return Value:
  2424. If the specified index is valid, then the specified value is stored in
  2425. the associated fiber local storage entry and TRUE is returned. Otherwise,
  2426. the last error value is set and FALSE is returned.
  2427. --*/
  2428. {
  2429. PPEB Peb;
  2430. PTEB Teb;
  2431. //
  2432. // If the fiber local storage index is invalid, then set the last error
  2433. // value and return FALSE. Otherwise, attempt to store the specified
  2434. // value in the associated fiber local storage data.
  2435. //
  2436. Teb = NtCurrentTeb();
  2437. Peb = Teb->ProcessEnvironmentBlock;
  2438. if ((dwFlsIndex > 0) && (dwFlsIndex < FLS_MAXIMUM_AVAILABLE)) {
  2439. ASSERT(RtlAreBitsSet((PRTL_BITMAP)Peb->FlsBitmap, dwFlsIndex, 1));
  2440. ASSERT(dwFlsIndex <= Peb->FlsHighIndex);
  2441. //
  2442. // If the fiber local storage data structure has not yet been
  2443. // allocated for the current thread, then attempt to allocate it
  2444. // now.
  2445. //
  2446. if (Teb->FlsData == NULL) {
  2447. Teb->FlsData = RtlAllocateHeap(Peb->ProcessHeap,
  2448. MAKE_TAG(TMP_TAG) | HEAP_ZERO_MEMORY,
  2449. sizeof(FLS_DATA));
  2450. //
  2451. // If a fiber local storage data structure was allocated, then
  2452. // insert the allocated structure in the process fiber local
  2453. // storage list. Otherwise, clear the allocated slot in the bitmap,
  2454. // set the last error value, return the distuiguished value.
  2455. //
  2456. if (Teb->FlsData != NULL) {
  2457. RtlAcquirePebLock();
  2458. try {
  2459. InsertTailList(&Peb->FlsListHead,
  2460. &((PFLS_DATA)Teb->FlsData)->Entry);
  2461. } finally {
  2462. RtlReleasePebLock();
  2463. }
  2464. } else {
  2465. BaseSetLastNTError(STATUS_NO_MEMORY);
  2466. return FALSE;
  2467. }
  2468. }
  2469. //
  2470. // Store the specfied value in the fiber local storage data entry and
  2471. // return TRUE.
  2472. //
  2473. ((PFLS_DATA)Teb->FlsData)->Slots[dwFlsIndex] = lpFlsData;
  2474. return TRUE;
  2475. } else {
  2476. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  2477. return FALSE;
  2478. }
  2479. }
  2480. BOOL
  2481. APIENTRY
  2482. FlsFree (
  2483. DWORD dwFlsIndex
  2484. )
  2485. /*++
  2486. Routine Description:
  2487. This function frees a fiber local storage index.
  2488. Arguments:
  2489. dwFlsIndex - Supplies a fiber local storage index.
  2490. Return Value:
  2491. If the specified index is valid, then the callback function associated
  2492. with the fiber local storage data entry is called if necessary for all
  2493. instances of fiber local storage, the specified index is freed, and TRUE
  2494. is returned. Otherwise, the last error value is set and FALSE is returned.
  2495. --*/
  2496. {
  2497. PFLS_CALLBACK_FUNCTION Callback;
  2498. PFLS_DATA FlsData;
  2499. PLIST_ENTRY NextEntry;
  2500. PPEB Peb;
  2501. BOOLEAN Result;
  2502. PTEB Teb;
  2503. //
  2504. // If the fiber local storage index is invalid, then return FALSE.
  2505. // Otherwise, invoke the callback function associated with the fiber
  2506. // local storage data entry if necessary, free the specified index,
  2507. // and return TRUE.
  2508. //
  2509. Teb = NtCurrentTeb();
  2510. Peb = Teb->ProcessEnvironmentBlock;
  2511. RtlAcquirePebLock();
  2512. try {
  2513. if ((dwFlsIndex > 0) &&
  2514. (dwFlsIndex < FLS_MAXIMUM_AVAILABLE) &&
  2515. (RtlAreBitsSet((PRTL_BITMAP)Peb->FlsBitmap, dwFlsIndex, 1))) {
  2516. //
  2517. // Clear the allocated slot in the fiber local storage bitmap,
  2518. // enumerate fiber local data structures, and invoke callback
  2519. // routines if necessary.
  2520. //
  2521. RtlClearBits((PRTL_BITMAP)Peb->FlsBitmap, dwFlsIndex, 1);
  2522. Callback = Peb->FlsCallback[dwFlsIndex];
  2523. NextEntry = Peb->FlsListHead.Flink;
  2524. while (NextEntry != &Peb->FlsListHead) {
  2525. FlsData = CONTAINING_RECORD(NextEntry, FLS_DATA, Entry);
  2526. if ((Callback != NULL) && (FlsData->Slots[dwFlsIndex])) {
  2527. (Callback)(FlsData->Slots[dwFlsIndex]);
  2528. }
  2529. FlsData->Slots[dwFlsIndex] = NULL;
  2530. NextEntry = NextEntry->Flink;
  2531. }
  2532. Peb->FlsCallback[dwFlsIndex] = NULL;
  2533. Result = TRUE;
  2534. } else {
  2535. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  2536. Result = FALSE;
  2537. }
  2538. } finally {
  2539. RtlReleasePebLock();
  2540. }
  2541. return Result;
  2542. }
  2543. WINBASEAPI
  2544. LPVOID
  2545. WINAPI
  2546. CreateFiber(
  2547. SIZE_T dwStackSize,
  2548. LPFIBER_START_ROUTINE lpStartAddress,
  2549. LPVOID lpParameter
  2550. )
  2551. /*++
  2552. Routine Description:
  2553. This function creates a fiber that executing at lpStartAddress as soon
  2554. as a thread is switched to it.
  2555. Arguments:
  2556. dwStackSize - Commit size of the stack
  2557. lpStartAddress - Routine that the fiber will start running
  2558. lpParameter - Arbitrary context that is passed to the fiber
  2559. Return Value:
  2560. LPVOID - Handle to the Fiber
  2561. --*/
  2562. {
  2563. return CreateFiberEx (dwStackSize, // dwStackCommitSize
  2564. 0, // dwStackReserveSize
  2565. 0, // dwFlags
  2566. lpStartAddress,
  2567. lpParameter);
  2568. }
  2569. WINBASEAPI
  2570. LPVOID
  2571. WINAPI
  2572. CreateFiberEx(
  2573. SIZE_T dwStackCommitSize,
  2574. SIZE_T dwStackReserveSize,
  2575. DWORD dwFlags,
  2576. LPFIBER_START_ROUTINE lpStartAddress,
  2577. LPVOID lpParameter
  2578. )
  2579. /*++
  2580. Routine Description:
  2581. This function creates a fiber that executing at lpStartAddress as soon
  2582. as a thread is switched to it.
  2583. Arguments:
  2584. dwStackCommitSize - Commit size of the stack
  2585. dwStackReserveSize - Reserve size of the stack
  2586. dwFlags - Flags DWORD, FIBER_FLAG_FLOAT_SWITCH is the only valid flag
  2587. lpStartAddress - Routine that the fiber will start running
  2588. lpParameter - Arbitrary context that is passed to the fiber
  2589. Return Value:
  2590. LPVOID - Handle to the Fiber
  2591. --*/
  2592. {
  2593. PFIBER Fiber;
  2594. INITIAL_TEB InitialTeb;
  2595. NTSTATUS Status;
  2596. //
  2597. // If any reserved flags are set, then return an error.
  2598. //
  2599. if ((dwFlags & ~FIBER_FLAG_FLOAT_SWITCH) != 0) {
  2600. SetLastError (ERROR_INVALID_PARAMETER);
  2601. return NULL;
  2602. }
  2603. //
  2604. // Allocate the fiber structure.
  2605. //
  2606. Fiber = RtlAllocateHeap (RtlProcessHeap (), MAKE_TAG (TMP_TAG), sizeof(FIBER));
  2607. if (Fiber == NULL) {
  2608. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2609. return Fiber;
  2610. }
  2611. Status = BaseCreateStack (NtCurrentProcess(),
  2612. dwStackCommitSize,
  2613. dwStackReserveSize,
  2614. &InitialTeb);
  2615. if (!NT_SUCCESS (Status)) {
  2616. BaseSetLastNTError (Status);
  2617. RtlFreeHeap (RtlProcessHeap(), 0, Fiber);
  2618. return NULL;
  2619. }
  2620. RtlZeroMemory (&Fiber->FiberContext, sizeof (Fiber->FiberContext));
  2621. //
  2622. // Initialize the fiber data.
  2623. //
  2624. Fiber->FiberData = lpParameter;
  2625. Fiber->StackBase = InitialTeb.StackBase;
  2626. Fiber->StackLimit = InitialTeb.StackLimit;
  2627. Fiber->DeallocationStack = InitialTeb.StackAllocationBase;
  2628. Fiber->ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)-1;
  2629. Fiber->Wx86Tib = NULL;
  2630. Fiber->FlsData = NULL;
  2631. //
  2632. // If switching of the floating state is specified, then set the floating
  2633. // point flag in the fiber context.
  2634. //
  2635. if ((dwFlags & FIBER_FLAG_FLOAT_SWITCH) != 0) {
  2636. Fiber->FiberContext.ContextFlags = CONTEXT_FLOATING_POINT;
  2637. } else {
  2638. Fiber->FiberContext.ContextFlags = 0;
  2639. }
  2640. #ifdef _IA64_
  2641. Fiber->BStoreLimit = InitialTeb.BStoreLimit;
  2642. Fiber->DeallocationBStore = (PVOID) ((ULONG_PTR)InitialTeb.StackBase +
  2643. ((ULONG_PTR)InitialTeb.StackBase - (ULONG_PTR)InitialTeb.StackAllocationBase));
  2644. #endif // _IA64_
  2645. //
  2646. // Create an initial context for the new fiber.
  2647. //
  2648. BaseInitializeContext (&Fiber->FiberContext,
  2649. lpParameter,
  2650. (PVOID)lpStartAddress,
  2651. InitialTeb.StackBase,
  2652. BaseContextTypeFiber);
  2653. return Fiber;
  2654. }
  2655. WINBASEAPI
  2656. VOID
  2657. WINAPI
  2658. DeleteFiber(
  2659. LPVOID lpFiber
  2660. )
  2661. {
  2662. SIZE_T dwStackSize;
  2663. PFIBER Fiber = lpFiber;
  2664. PTEB Teb;
  2665. //
  2666. // If the current fiber makes this call, then it's just a thread exit
  2667. //
  2668. Teb = NtCurrentTeb();
  2669. if ((Teb->HasFiberData != FALSE) && (Teb->NtTib.FiberData == Fiber)) {
  2670. ExitThread(1);
  2671. }
  2672. dwStackSize = 0;
  2673. NtFreeVirtualMemory(NtCurrentProcess(),
  2674. &Fiber->DeallocationStack,
  2675. &dwStackSize,
  2676. MEM_RELEASE);
  2677. #if defined (WX86)
  2678. if (Fiber->Wx86Tib && Fiber->Wx86Tib->Size == sizeof(WX86TIB)) {
  2679. PVOID BaseAddress = Fiber->Wx86Tib->DeallocationStack;
  2680. dwStackSize = 0;
  2681. NtFreeVirtualMemory(NtCurrentProcess(),
  2682. &BaseAddress,
  2683. &dwStackSize,
  2684. MEM_RELEASE);
  2685. }
  2686. #endif
  2687. //
  2688. // If a fiber local storage data structure has been allocated, then
  2689. // rundown the structure.
  2690. //
  2691. if (Fiber->FlsData != NULL) {
  2692. BaseRundownFls((PFLS_DATA)Fiber->FlsData);
  2693. }
  2694. //
  2695. // Free fiber storage.
  2696. //
  2697. RtlFreeHeap(RtlProcessHeap(), 0, Fiber);
  2698. return;
  2699. }
  2700. WINBASEAPI
  2701. LPVOID
  2702. WINAPI
  2703. ConvertThreadToFiber(
  2704. IN LPVOID lpParameter
  2705. )
  2706. {
  2707. return ConvertThreadToFiberEx(lpParameter, 0);
  2708. }
  2709. WINBASEAPI
  2710. LPVOID
  2711. WINAPI
  2712. ConvertThreadToFiberEx(
  2713. IN LPVOID lpParameter,
  2714. IN DWORD dwFlags
  2715. )
  2716. {
  2717. PFIBER Fiber;
  2718. PTEB Teb;
  2719. //
  2720. // If any reserved flags are set, then return an error.
  2721. //
  2722. if ((dwFlags & ~FIBER_FLAG_FLOAT_SWITCH) != 0) {
  2723. SetLastError(ERROR_INVALID_PARAMETER);
  2724. return NULL;
  2725. }
  2726. //
  2727. // If the thread has already been converted to a fiber, then return an
  2728. // error.
  2729. //
  2730. Teb = NtCurrentTeb();
  2731. if (Teb->HasFiberData != FALSE) {
  2732. SetLastError(ERROR_ALREADY_FIBER);
  2733. return NULL;
  2734. }
  2735. //
  2736. // Allocate the fiber structure.
  2737. //
  2738. Fiber = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), sizeof(FIBER));
  2739. if (Fiber == NULL) {
  2740. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2741. return NULL;
  2742. }
  2743. //
  2744. // Initialize the fiber data.
  2745. //
  2746. Fiber->FiberData = lpParameter;
  2747. Fiber->StackBase = Teb->NtTib.StackBase;
  2748. Fiber->StackLimit = Teb->NtTib.StackLimit;
  2749. Fiber->DeallocationStack = Teb->DeallocationStack;
  2750. Fiber->ExceptionList = Teb->NtTib.ExceptionList;
  2751. Fiber->FlsData = Teb->FlsData;
  2752. //
  2753. // If switching of the floating state is specified, then set the floating
  2754. // point flag in the fiber context.
  2755. //
  2756. Fiber->FiberContext.ContextFlags = CONTEXT_FULL;
  2757. if ((dwFlags & FIBER_FLAG_FLOAT_SWITCH) != 0) {
  2758. Fiber->FiberContext.ContextFlags |= CONTEXT_FLOATING_POINT;
  2759. }
  2760. #ifdef _IA64_
  2761. Fiber->BStoreLimit = Teb->BStoreLimit;
  2762. Fiber->DeallocationBStore = Teb->DeallocationBStore;
  2763. #endif // _IA64_
  2764. //
  2765. // Initialize the fiber address and set thread has fiber data.
  2766. //
  2767. Fiber->Wx86Tib = NULL;
  2768. Teb->NtTib.FiberData = Fiber;
  2769. Teb->HasFiberData = TRUE;
  2770. return Fiber;
  2771. }
  2772. WINBASEAPI
  2773. BOOL
  2774. WINAPI
  2775. ConvertFiberToThread(
  2776. VOID
  2777. )
  2778. {
  2779. PFIBER Fiber;
  2780. PTEB Teb;
  2781. //
  2782. // If the current thread has been converted to a fiber, then convert
  2783. // if back to a thread and return TRUE. Otherwise, set the last error
  2784. // value and return FALSE.
  2785. //
  2786. Teb = NtCurrentTeb();
  2787. if (Teb->HasFiberData == FALSE) {
  2788. SetLastError(ERROR_ALREADY_THREAD);
  2789. return FALSE;
  2790. } else {
  2791. Teb->HasFiberData = FALSE;
  2792. Fiber = Teb->NtTib.FiberData;
  2793. Teb->NtTib.FiberData = NULL;
  2794. ASSERT(Fiber != NULL);
  2795. RtlFreeHeap(RtlProcessHeap (), 0, Fiber);
  2796. return TRUE;
  2797. }
  2798. }
  2799. BOOL
  2800. WINAPI
  2801. SwitchToThread(
  2802. VOID
  2803. )
  2804. /*++
  2805. Routine Description:
  2806. This function causes a yield from the running thread to any other
  2807. thread that is ready and can run on the current processor. The
  2808. yield will be effective for up to one quantum and then the yielding
  2809. thread will be scheduled again according to its priority and
  2810. whatever other threads may also be avaliable to run. The thread
  2811. that yields will not bounce to another processor even it another
  2812. processor is idle or running a lower priority thread.
  2813. Arguments:
  2814. None
  2815. Return Value:
  2816. TRUE - Calling this function caused a switch to another thread to occur
  2817. FALSE - There were no other ready threads, so no context switch occured
  2818. --*/
  2819. {
  2820. if (NtYieldExecution() == STATUS_NO_YIELD_PERFORMED) {
  2821. return FALSE;
  2822. } else {
  2823. return TRUE;
  2824. }
  2825. }
  2826. BOOL
  2827. WINAPI
  2828. RegisterWaitForSingleObject(
  2829. PHANDLE phNewWaitObject,
  2830. HANDLE hObject,
  2831. WAITORTIMERCALLBACK Callback,
  2832. PVOID Context,
  2833. ULONG dwMilliseconds,
  2834. ULONG dwFlags
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. This function registers a wait for a particular object, with an optional
  2839. timeout. This differs from WaitForSingleObject because the wait is performed
  2840. by a different thread that combines several such calls for efficiency. The
  2841. function supplied in Callback is called when the object is signalled, or the
  2842. timeout expires.
  2843. Arguments:
  2844. phNewWaitObject - pointer to new WaitObject returned by this function.
  2845. hObject - HANDLE to a Win32 kernel object (Event, Mutex, File, Process,
  2846. Thread, etc.) that will be waited on. Note: if the object
  2847. handle does not immediately return to the not-signalled state,
  2848. e.g. an auto-reset event, then either WT_EXECUTEINWAITTHREAD or
  2849. WT_EXECUTEONLYONCE should be specified. Otherwise, the thread
  2850. pool will continue to fire the callbacks. If WT_EXECUTEINWAITTHREAD
  2851. is specified, the the object should be deregistered or reset in the
  2852. callback.
  2853. Callback - Function that will be called when the object is signalled or the
  2854. timer expires.
  2855. Context - Context that will be passed to the callback function.
  2856. dwMilliseconds - timeout for the wait. Each time the timer is fired or the event
  2857. is fired, the timer is reset (except if WT_EXECUTEONLYONCE is set).
  2858. dwFlags - Flags indicating options for this wait:
  2859. WT_EXECUTEDEFAULT - Default (0)
  2860. WT_EXECUTEINIOTHREAD - Select an I/O thread for execution
  2861. WT_EXECUTEINUITHREAD - Select a UI thread for execution
  2862. WT_EXECUTEINWAITTHREAD - Execute in the thread that handles waits
  2863. WT_EXECUTEONLYONCE - The callback function will be called only once
  2864. WT_EXECUTELONGFUNCTION - The Callback function can potentially block
  2865. for a long time. Is valid only if
  2866. WT_EXECUTEINWAITTHREAD flag is not set.
  2867. Return Value:
  2868. FALSE - an error occurred, use GetLastError() for more information.
  2869. TRUE - success.
  2870. --*/
  2871. {
  2872. NTSTATUS Status ;
  2873. PPEB Peb;
  2874. *phNewWaitObject = NULL;
  2875. Peb = NtCurrentPeb();
  2876. switch( HandleToUlong(hObject) )
  2877. {
  2878. case STD_INPUT_HANDLE: hObject = Peb->ProcessParameters->StandardInput;
  2879. break;
  2880. case STD_OUTPUT_HANDLE: hObject = Peb->ProcessParameters->StandardOutput;
  2881. break;
  2882. case STD_ERROR_HANDLE: hObject = Peb->ProcessParameters->StandardError;
  2883. break;
  2884. }
  2885. if (CONSOLE_HANDLE(hObject) && VerifyConsoleIoHandle(hObject))
  2886. {
  2887. hObject = GetConsoleInputWaitHandle();
  2888. }
  2889. Status = RtlRegisterWait(
  2890. phNewWaitObject,
  2891. hObject,
  2892. Callback,
  2893. Context,
  2894. dwMilliseconds,
  2895. dwFlags );
  2896. if ( NT_SUCCESS( Status ) )
  2897. {
  2898. return TRUE ;
  2899. }
  2900. BaseSetLastNTError( Status );
  2901. return FALSE ;
  2902. }
  2903. HANDLE
  2904. WINAPI
  2905. RegisterWaitForSingleObjectEx(
  2906. HANDLE hObject,
  2907. WAITORTIMERCALLBACK Callback,
  2908. PVOID Context,
  2909. ULONG dwMilliseconds,
  2910. ULONG dwFlags
  2911. )
  2912. /*++
  2913. Routine Description:
  2914. This function registers a wait for a particular object, with an optional
  2915. timeout. This differs from WaitForSingleObject because the wait is performed
  2916. by a different thread that combines several such calls for efficiency. The
  2917. function supplied in Callback is called when the object is signalled, or the
  2918. timeout expires.
  2919. Arguments:
  2920. hObject - HANDLE to a Win32 kernel object (Event, Mutex, File, Process,
  2921. Thread, etc.) that will be waited on. Note: if the object
  2922. handle does not immediately return to the not-signalled state,
  2923. e.g. an auto-reset event, then either WT_EXECUTEINWAITTHREAD or
  2924. WT_EXECUTEONLYONCE should be specified. Otherwise, the thread
  2925. pool will continue to fire the callbacks. If WT_EXECUTEINWAITTHREAD
  2926. is specified, the the object should be deregistered or reset in the
  2927. callback.
  2928. Callback - Function that will be called when the object is signalled or the
  2929. timer expires.
  2930. Context - Context that will be passed to the callback function.
  2931. dwMilliseconds - timeout for the wait. Each time the timer is fired or the event
  2932. is fired, the timer is reset (except if WT_EXECUTEONLYONCE is set).
  2933. dwFlags - Flags indicating options for this wait:
  2934. WT_EXECUTEDEFAULT - Default (0)
  2935. WT_EXECUTEINIOTHREAD - Select an I/O thread for execution
  2936. WT_EXECUTEINUITHREAD - Select a UI thread for execution
  2937. WT_EXECUTEINWAITTHREAD - Execute in the thread that handles waits
  2938. WT_EXECUTEONLYONCE - The callback function will be called only once
  2939. WT_EXECUTELONGFUNCTION - The Callback function can potentially block
  2940. for a long time. Is valid only if
  2941. WT_EXECUTEINWAITTHREAD flag is not set.
  2942. Return Value:
  2943. NULL - an error occurred, use GetLastError() for more information.
  2944. non-NULL - a virtual handle that can be passed later to
  2945. UnregisterWait
  2946. --*/
  2947. {
  2948. HANDLE WaitHandle ;
  2949. NTSTATUS Status ;
  2950. PPEB Peb;
  2951. Peb = NtCurrentPeb();
  2952. switch( HandleToUlong(hObject) )
  2953. {
  2954. case STD_INPUT_HANDLE: hObject = Peb->ProcessParameters->StandardInput;
  2955. break;
  2956. case STD_OUTPUT_HANDLE: hObject = Peb->ProcessParameters->StandardOutput;
  2957. break;
  2958. case STD_ERROR_HANDLE: hObject = Peb->ProcessParameters->StandardError;
  2959. break;
  2960. }
  2961. if (CONSOLE_HANDLE(hObject) && VerifyConsoleIoHandle(hObject))
  2962. {
  2963. hObject = GetConsoleInputWaitHandle();
  2964. }
  2965. Status = RtlRegisterWait(
  2966. &WaitHandle,
  2967. hObject,
  2968. Callback,
  2969. Context,
  2970. dwMilliseconds,
  2971. dwFlags );
  2972. if ( NT_SUCCESS( Status ) )
  2973. {
  2974. return WaitHandle ;
  2975. }
  2976. BaseSetLastNTError( Status );
  2977. return NULL ;
  2978. }
  2979. BOOL
  2980. WINAPI
  2981. UnregisterWait(
  2982. HANDLE WaitHandle
  2983. )
  2984. /*++
  2985. Routine Description:
  2986. This function cancels a wait for a particular object.
  2987. All objects that were registered by the RtlWaitForSingleObject(Ex) call
  2988. should be deregistered. This is a non-blocking call, and the associated
  2989. callback function can still be executing after the return of this function.
  2990. Arguments:
  2991. WaitHandle - Handle returned from RegisterWaitForSingleObject(Ex)
  2992. Return Value:
  2993. TRUE - The wait was cancelled
  2994. FALSE - an error occurred or a callback function was still executing,
  2995. use GetLastError() for more information.
  2996. --*/
  2997. {
  2998. NTSTATUS Status ;
  2999. if ( WaitHandle )
  3000. {
  3001. Status = RtlDeregisterWait( WaitHandle );
  3002. // set error if it is a non-blocking call and STATUS_PENDING was returned
  3003. if ( Status == STATUS_PENDING || !NT_SUCCESS( Status ) )
  3004. {
  3005. BaseSetLastNTError( Status );
  3006. return FALSE;
  3007. }
  3008. return TRUE ;
  3009. }
  3010. SetLastError( ERROR_INVALID_HANDLE );
  3011. return FALSE ;
  3012. }
  3013. BOOL
  3014. WINAPI
  3015. UnregisterWaitEx(
  3016. HANDLE WaitHandle,
  3017. HANDLE CompletionEvent
  3018. )
  3019. /*++
  3020. Routine Description:
  3021. This function cancels a wait for a particular object.
  3022. All objects that were registered by the RtlWaitForSingleObject(Ex) call
  3023. should be deregistered.
  3024. Arguments:
  3025. WaitHandle - Handle returned from RegisterWaitForSingleObject
  3026. CompletionEvent - Handle to wait on for completion.
  3027. NULL - NonBlocking call.
  3028. INVALID_HANDLE_VALUE - Blocking call. Block till all Callback functions
  3029. associated with the WaitHandle have completed
  3030. Event - NonBlocking call. The Object is deregistered. The Event is signalled
  3031. when the last callback function has completed execution.
  3032. Return Value:
  3033. TRUE - The wait was cancelled
  3034. FALSE - an error occurred or a callback was still executing,
  3035. use GetLastError() for more information.
  3036. --*/
  3037. {
  3038. NTSTATUS Status ;
  3039. if ( WaitHandle )
  3040. {
  3041. Status = RtlDeregisterWaitEx( WaitHandle, CompletionEvent );
  3042. // set error if it is a non-blocking call and STATUS_PENDING was returned
  3043. if ( (CompletionEvent != INVALID_HANDLE_VALUE && Status == STATUS_PENDING)
  3044. || ( ! NT_SUCCESS( Status ) ) )
  3045. {
  3046. BaseSetLastNTError( Status );
  3047. return FALSE;
  3048. }
  3049. return TRUE ;
  3050. }
  3051. SetLastError( ERROR_INVALID_HANDLE );
  3052. return FALSE ;
  3053. }
  3054. BOOL
  3055. WINAPI
  3056. QueueUserWorkItem(
  3057. LPTHREAD_START_ROUTINE Function,
  3058. PVOID Context,
  3059. ULONG Flags
  3060. )
  3061. /*++
  3062. Routine Description:
  3063. This function queues a work item to a thread out of the thread pool. The
  3064. function passed is invoked in a different thread, and passed the Context
  3065. pointer. The caller can specify whether the thread pool should select
  3066. a thread that can have I/O pending, or any thread.
  3067. Arguments:
  3068. Function - Function to call
  3069. Context - Pointer passed to the function when it is invoked.
  3070. Flags -
  3071. - WT_EXECUTEINIOTHREAD
  3072. Indictes to the thread pool that this thread will perform
  3073. I/O. A thread that starts an asynchronous I/O operation
  3074. must wait for it to complete. If a thread exits with
  3075. outstanding I/O requests, those requests will be cancelled.
  3076. This flag is a hint to the thread pool that this function
  3077. will start I/O, so that a thread which can have pending I/O
  3078. will be used.
  3079. - WT_EXECUTELONGFUNCTION
  3080. Indicates to the thread pool that the function might block
  3081. for a long time.
  3082. Return Value:
  3083. TRUE - The work item was queued to another thread.
  3084. FALSE - an error occurred, use GetLastError() for more information.
  3085. --*/
  3086. {
  3087. NTSTATUS Status ;
  3088. Status = RtlQueueWorkItem(
  3089. (WORKERCALLBACKFUNC) Function,
  3090. Context,
  3091. Flags );
  3092. if ( NT_SUCCESS( Status ) )
  3093. {
  3094. return TRUE ;
  3095. }
  3096. BaseSetLastNTError( Status );
  3097. return FALSE ;
  3098. }
  3099. BOOL
  3100. WINAPI
  3101. BindIoCompletionCallback (
  3102. HANDLE FileHandle,
  3103. LPOVERLAPPED_COMPLETION_ROUTINE Function,
  3104. ULONG Flags
  3105. )
  3106. /*++
  3107. Routine Description:
  3108. This function binds the FileHandle opened for overlapped operations
  3109. to the IO completion port associated with worker threads.
  3110. Arguments:
  3111. FileHandle - File Handle on which IO operations will be initiated.
  3112. Function - Function executed in a non-IO worker thread when the
  3113. IO operation completes.
  3114. Flags - Currently set to 0. Not used.
  3115. Return Value:
  3116. TRUE - The file handle was associated with the IO completion port.
  3117. FALSE - an error occurred, use GetLastError() for more information.
  3118. --*/
  3119. {
  3120. NTSTATUS Status ;
  3121. Status = RtlSetIoCompletionCallback(
  3122. FileHandle,
  3123. (APC_CALLBACK_FUNCTION) Function,
  3124. Flags );
  3125. if ( NT_SUCCESS( Status ) )
  3126. {
  3127. return TRUE ;
  3128. }
  3129. BaseSetLastNTError( Status );
  3130. return FALSE ;
  3131. }
  3132. //+---------------------------------------------------------------------------
  3133. //+---------------------------------------------------------------------------
  3134. //
  3135. // Function: BasepCreateDefaultTimerQueue
  3136. //
  3137. // Synopsis: Creates the default timer queue for the process
  3138. //
  3139. // Arguments: (none)
  3140. //
  3141. // History: 5-26-98 RichardW Created
  3142. //
  3143. // Notes:
  3144. //
  3145. //----------------------------------------------------------------------------
  3146. BOOL
  3147. BasepCreateDefaultTimerQueue(
  3148. VOID
  3149. )
  3150. {
  3151. NTSTATUS Status ;
  3152. while ( 1 )
  3153. {
  3154. if ( !InterlockedExchange( &BasepTimerQueueInitFlag, 1 ) )
  3155. {
  3156. //
  3157. // Force the done flag to 0. If it was 1, so one already tried to
  3158. // init and failed.
  3159. //
  3160. InterlockedExchange( &BasepTimerQueueDoneFlag, 0 );
  3161. Status = RtlCreateTimerQueue( &BasepDefaultTimerQueue );
  3162. if ( NT_SUCCESS( Status ) )
  3163. {
  3164. InterlockedIncrement( &BasepTimerQueueDoneFlag );
  3165. return TRUE ;
  3166. }
  3167. //
  3168. // This is awkward. We aren't able to create a timer queue,
  3169. // probably because of low memory. We will fail this call, but decrement
  3170. // the init flag, so that others can try again later. Need to increment
  3171. // the done flag, or any other threads would be stuck.
  3172. //
  3173. BaseSetLastNTError( Status );
  3174. InterlockedIncrement( &BasepTimerQueueDoneFlag );
  3175. InterlockedDecrement( &BasepTimerQueueInitFlag );
  3176. return FALSE ;
  3177. }
  3178. else
  3179. {
  3180. LARGE_INTEGER TimeOut ;
  3181. TimeOut.QuadPart = -1 * 10 * 10000 ;
  3182. //
  3183. // yield the quantum so that the other thread can
  3184. // try to create the timer queue.
  3185. //
  3186. while ( !BasepTimerQueueDoneFlag )
  3187. {
  3188. NtDelayExecution( FALSE, &TimeOut );
  3189. }
  3190. //
  3191. // Make sure it was created. Otherwise, try it again (memory might have
  3192. // freed up). This way, every thread gets an individual chance to create
  3193. // the queue if another thread failed.
  3194. //
  3195. if ( BasepDefaultTimerQueue )
  3196. {
  3197. return TRUE ;
  3198. }
  3199. }
  3200. }
  3201. }
  3202. HANDLE
  3203. WINAPI
  3204. CreateTimerQueue(
  3205. VOID
  3206. )
  3207. /*++
  3208. Routine Description:
  3209. This function creates a queue for timers. Timers on a timer queue are
  3210. lightweight objects that allow the caller to specify a function to
  3211. be called at some point in the future. Any number of timers can be
  3212. created in a particular timer queue.
  3213. Arguments:
  3214. None.
  3215. Return Value:
  3216. non-NULL - a timer queue handle that can be passed to SetTimerQueueTimer,
  3217. ChangeTimerQueueTimer, CancelTimerQueueTimer, and
  3218. DeleteTimerQueue.
  3219. NULL - an error occurred, use GetLastError() for more information.
  3220. --*/
  3221. {
  3222. NTSTATUS Status ;
  3223. HANDLE Handle ;
  3224. Status = RtlCreateTimerQueue( &Handle );
  3225. if ( NT_SUCCESS( Status ) )
  3226. {
  3227. return Handle ;
  3228. }
  3229. BaseSetLastNTError( Status );
  3230. return NULL ;
  3231. }
  3232. BOOL
  3233. WINAPI
  3234. CreateTimerQueueTimer(
  3235. PHANDLE phNewTimer,
  3236. HANDLE TimerQueue,
  3237. WAITORTIMERCALLBACK Callback,
  3238. PVOID Parameter,
  3239. DWORD DueTime,
  3240. DWORD Period,
  3241. ULONG Flags
  3242. )
  3243. /*++
  3244. Routine Description:
  3245. This function creates a timer queue timer, a lightweight timer that
  3246. will fire at the DueTime, and then every Period milliseconds afterwards.
  3247. When the timer fires, the function passed in Callback will be invoked,
  3248. and passed the Parameter pointer.
  3249. Arguments:
  3250. phNewTimer - pointer to new timer handle
  3251. TimerQueue - Timer Queue to attach this timer to. NULL indicates that the
  3252. default process timer queue be used.
  3253. Function - Function to call
  3254. Context - Pointer passed to the function when it is invoked.
  3255. DueTime - Time from now that the timer should fire, expressed in
  3256. milliseconds. If set to INFINITE, then it will never fire.
  3257. If set to 0, then it will fire immediately.
  3258. Period - Time in between firings of this timer.
  3259. If 0, then it is a one shot timer.
  3260. Flags - by default the Callback function is queued to a non-IO worker thread.
  3261. - WT_EXECUTEINIOTHREAD
  3262. Indictes to the thread pool that this thread will perform
  3263. I/O. A thread that starts an asynchronous I/O operation
  3264. must wait for it to complete. If a thread exits with
  3265. outstanding I/O requests, those requests will be cancelled.
  3266. This flag is a hint to the thread pool that this function
  3267. will start I/O, so that a thread with I/O already pending
  3268. will be used.
  3269. - WT_EXECUTEINTIMERTHREAD
  3270. The callback function will be executed in the timer thread.
  3271. - WT_EXECUTELONGFUNCTION
  3272. Indicates that the function might block for a long time. Useful
  3273. only if it is queued to a worker thread.
  3274. Return Value:
  3275. TRUE - no error
  3276. FALSE - an error occurred, use GetLastError() for more information.
  3277. --*/
  3278. {
  3279. NTSTATUS Status ;
  3280. *phNewTimer = NULL ;
  3281. //
  3282. // if the passed timer queue is NULL, use the default one. If it is null,
  3283. // call the initializer that will do it in a nice thread safe fashion.
  3284. //
  3285. if ( !TimerQueue )
  3286. {
  3287. if ( !BasepDefaultTimerQueue )
  3288. {
  3289. if ( !BasepCreateDefaultTimerQueue( ) )
  3290. {
  3291. return FALSE ;
  3292. }
  3293. }
  3294. TimerQueue = BasepDefaultTimerQueue ;
  3295. }
  3296. Status = RtlCreateTimer(
  3297. TimerQueue,
  3298. phNewTimer,
  3299. Callback,
  3300. Parameter,
  3301. DueTime,
  3302. Period,
  3303. Flags );
  3304. if ( NT_SUCCESS( Status ) )
  3305. {
  3306. return TRUE ;
  3307. }
  3308. BaseSetLastNTError( Status );
  3309. return FALSE ;
  3310. }
  3311. BOOL
  3312. WINAPI
  3313. ChangeTimerQueueTimer(
  3314. HANDLE TimerQueue,
  3315. HANDLE Timer,
  3316. ULONG DueTime,
  3317. ULONG Period
  3318. )
  3319. /*++
  3320. Routine Description:
  3321. This function updates a timer queue timer created with SetTimerQueueTimer.
  3322. Arguments:
  3323. TimerQueue - Timer Queue to attach this timer to. NULL indicates the default
  3324. process timer queue.
  3325. Timer - Handle returned from SetTimerQueueTimer.
  3326. DueTime - Time from now that the timer should fire, expressed in
  3327. milliseconds.
  3328. Period - Time in between firings of this timer. If set to 0, then it becomes
  3329. a one shot timer.
  3330. Return Value:
  3331. TRUE - the timer was changed
  3332. FALSE - an error occurred, use GetLastError() for more information.
  3333. --*/
  3334. {
  3335. NTSTATUS Status ;
  3336. //
  3337. // Use the default timer queue if none was passed in. If there isn't one, then
  3338. // the process hasn't created one with SetTimerQueueTimer, and that's an error.
  3339. //
  3340. if ( !TimerQueue )
  3341. {
  3342. TimerQueue = BasepDefaultTimerQueue ;
  3343. if ( !TimerQueue )
  3344. {
  3345. SetLastError( ERROR_INVALID_PARAMETER );
  3346. return FALSE ;
  3347. }
  3348. }
  3349. Status = RtlUpdateTimer( TimerQueue,
  3350. Timer,
  3351. DueTime,
  3352. Period );
  3353. if ( NT_SUCCESS( Status ) )
  3354. {
  3355. return TRUE ;
  3356. }
  3357. BaseSetLastNTError( Status );
  3358. return FALSE ;
  3359. }
  3360. BOOL
  3361. WINAPI
  3362. DeleteTimerQueueTimer(
  3363. HANDLE TimerQueue,
  3364. HANDLE Timer,
  3365. HANDLE CompletionEvent
  3366. )
  3367. /*++
  3368. Routine Description:
  3369. This function cancels a timer queue timer created with SetTimerQueueTimer.
  3370. Arguments:
  3371. TimerQueue - Timer Queue that this timer was created on.
  3372. Timer - Handle returned from SetTimerQueueTimer.
  3373. CompletionEvent -
  3374. - NULL : NonBlocking call. returns immediately.
  3375. - INVALID_HANDLE_VALUE : Blocking call. Returns after all callbacks have executed
  3376. - Event (handle to an event) : NonBlocking call. Returns immediately.
  3377. Event signalled after all callbacks have executed.
  3378. Return Value:
  3379. TRUE - the timer was cancelled.
  3380. FALSE - an error occurred or the call is pending, use GetLastError()
  3381. for more information.
  3382. --*/
  3383. {
  3384. NTSTATUS Status ;
  3385. //
  3386. // Use the default timer queue if none was passed in. If there isn't one, then
  3387. // the process hasn't created one with SetTimerQueueTimer, and that's an error.
  3388. //
  3389. if ( !TimerQueue )
  3390. {
  3391. TimerQueue = BasepDefaultTimerQueue ;
  3392. if ( !TimerQueue )
  3393. {
  3394. SetLastError( ERROR_INVALID_PARAMETER );
  3395. return FALSE ;
  3396. }
  3397. }
  3398. Status = RtlDeleteTimer( TimerQueue, Timer, CompletionEvent );
  3399. // set error if it is a non-blocking call and STATUS_PENDING was returned
  3400. if ( (CompletionEvent != INVALID_HANDLE_VALUE && Status == STATUS_PENDING)
  3401. || ( ! NT_SUCCESS( Status ) ) )
  3402. {
  3403. BaseSetLastNTError( Status );
  3404. return FALSE;
  3405. }
  3406. return TRUE ;
  3407. }
  3408. BOOL
  3409. WINAPI
  3410. DeleteTimerQueueEx(
  3411. HANDLE TimerQueue,
  3412. HANDLE CompletionEvent
  3413. )
  3414. /*++
  3415. Routine Description:
  3416. This function deletes a timer queue created with CreateTimerQueue.
  3417. Any pending timers on the timer queue are cancelled and deleted.
  3418. Arguments:
  3419. TimerQueue - Timer Queue to delete.
  3420. CompletionEvent -
  3421. - NULL : NonBlocking call. returns immediately.
  3422. - INVALID_HANDLE_VALUE : Blocking call. Returns after all callbacks
  3423. have executed
  3424. - Event (handle to an event) : NonBlocking call. Returns immediately.
  3425. Event signalled after all callbacks have executed.
  3426. Return Value:
  3427. TRUE - the timer queue was deleted.
  3428. FALSE - an error occurred, use GetLastError() for more information.
  3429. --*/
  3430. {
  3431. NTSTATUS Status ;
  3432. if ( TimerQueue )
  3433. {
  3434. Status = RtlDeleteTimerQueueEx( TimerQueue, CompletionEvent );
  3435. // set error if it is a non-blocking call and STATUS_PENDING was returned
  3436. if ( (CompletionEvent != INVALID_HANDLE_VALUE && Status == STATUS_PENDING)
  3437. || ( ! NT_SUCCESS( Status ) ) )
  3438. {
  3439. BaseSetLastNTError( Status );
  3440. return FALSE;
  3441. }
  3442. return TRUE ;
  3443. }
  3444. SetLastError( ERROR_INVALID_HANDLE );
  3445. return FALSE ;
  3446. }
  3447. BOOL
  3448. WINAPI
  3449. ThreadPoolCleanup (
  3450. ULONG Flags
  3451. )
  3452. /*++
  3453. Routine Description:
  3454. Called by terminating process for thread pool to cleanup and
  3455. delete all its threads.
  3456. Arguments:
  3457. Flags - currently not used
  3458. Return Value:
  3459. NO_ERROR
  3460. --*/
  3461. {
  3462. // RtlThreadPoolCleanup( Flags ) ;
  3463. return TRUE ;
  3464. }
  3465. /*OBSOLETE FUNCTION - REPLACED BY CreateTimerQueueTimer */
  3466. HANDLE
  3467. WINAPI
  3468. SetTimerQueueTimer(
  3469. HANDLE TimerQueue,
  3470. WAITORTIMERCALLBACK Callback,
  3471. PVOID Parameter,
  3472. DWORD DueTime,
  3473. DWORD Period,
  3474. BOOL PreferIo
  3475. )
  3476. /*OBSOLETE FUNCTION - REPLACED BY CreateTimerQueueTimer */
  3477. {
  3478. NTSTATUS Status ;
  3479. HANDLE Handle ;
  3480. //
  3481. // if the passed timer queue is NULL, use the default one. If it is null,
  3482. // call the initializer that will do it in a nice thread safe fashion.
  3483. //
  3484. if ( !TimerQueue )
  3485. {
  3486. if ( !BasepDefaultTimerQueue )
  3487. {
  3488. if ( !BasepCreateDefaultTimerQueue( ) )
  3489. {
  3490. return NULL ;
  3491. }
  3492. }
  3493. TimerQueue = BasepDefaultTimerQueue ;
  3494. }
  3495. Status = RtlCreateTimer(
  3496. TimerQueue,
  3497. &Handle,
  3498. Callback,
  3499. Parameter,
  3500. DueTime,
  3501. Period,
  3502. (PreferIo ? WT_EXECUTEINIOTHREAD : 0 ) );
  3503. if ( NT_SUCCESS( Status ) )
  3504. {
  3505. return Handle ;
  3506. }
  3507. BaseSetLastNTError( Status );
  3508. return NULL ;
  3509. }
  3510. /*OBSOLETE: Replaced by DeleteTimerQueueEx */
  3511. BOOL
  3512. WINAPI
  3513. DeleteTimerQueue(
  3514. HANDLE TimerQueue
  3515. )
  3516. /*++
  3517. OBSOLETE: Replaced by DeleteTimerQueueEx
  3518. Routine Description:
  3519. This function deletes a timer queue created with CreateTimerQueue.
  3520. Any pending timers on the timer queue are cancelled and deleted.
  3521. This is a non-blocking call. Callbacks might still be running after
  3522. this call returns.
  3523. Arguments:
  3524. TimerQueue - Timer Queue to delete.
  3525. Return Value:
  3526. TRUE - the timer queue was deleted.
  3527. FALSE - an error occurred, use GetLastError() for more information.
  3528. --*/
  3529. {
  3530. NTSTATUS Status ;
  3531. if (TimerQueue)
  3532. {
  3533. Status = RtlDeleteTimerQueueEx( TimerQueue, NULL );
  3534. // set error if it is a non-blocking call and STATUS_PENDING was returned
  3535. /*
  3536. if ( Status == STATUS_PENDING || ! NT_SUCCESS( Status ) )
  3537. {
  3538. BaseSetLastNTError( Status );
  3539. return FALSE;
  3540. }
  3541. */
  3542. return TRUE ;
  3543. }
  3544. SetLastError( ERROR_INVALID_HANDLE );
  3545. return FALSE ;
  3546. }
  3547. /*OBSOLETE: USE DeleteTimerQueueTimer*/
  3548. BOOL
  3549. WINAPI
  3550. CancelTimerQueueTimer(
  3551. HANDLE TimerQueue,
  3552. HANDLE Timer
  3553. )
  3554. /*OBSOLETE: USE DeleteTimerQueueTimer*/
  3555. {
  3556. NTSTATUS Status ;
  3557. //
  3558. // Use the default timer queue if none was passed in. If there isn't one, then
  3559. // the process hasn't created one with SetTimerQueueTimer, and that's an error.
  3560. //
  3561. if ( !TimerQueue )
  3562. {
  3563. TimerQueue = BasepDefaultTimerQueue ;
  3564. if ( !TimerQueue )
  3565. {
  3566. SetLastError( ERROR_INVALID_PARAMETER );
  3567. return FALSE ;
  3568. }
  3569. }
  3570. Status = RtlDeleteTimer( TimerQueue, Timer, NULL );
  3571. if ( NT_SUCCESS( Status ) )
  3572. {
  3573. return TRUE ;
  3574. }
  3575. BaseSetLastNTError( Status );
  3576. return FALSE ;
  3577. }