Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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