Windows NT 4.0 source code leak
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.

2181 lines
57 KiB

4 years ago
  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. HANDLE
  13. APIENTRY
  14. CreateThread(
  15. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  16. DWORD dwStackSize,
  17. LPTHREAD_START_ROUTINE lpStartAddress,
  18. LPVOID lpParameter,
  19. DWORD dwCreationFlags,
  20. LPDWORD lpThreadId
  21. )
  22. /*++
  23. Routine Description:
  24. A thread object can be created to execute within the address space of the
  25. calling process using CreateThread.
  26. See CreateRemoteThread for a description of the arguments and return value.
  27. --*/
  28. {
  29. return CreateRemoteThread( NtCurrentProcess(),
  30. lpThreadAttributes,
  31. dwStackSize,
  32. lpStartAddress,
  33. lpParameter,
  34. dwCreationFlags,
  35. lpThreadId
  36. );
  37. }
  38. HANDLE
  39. APIENTRY
  40. CreateRemoteThread(
  41. HANDLE hProcess,
  42. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  43. DWORD dwStackSize,
  44. LPTHREAD_START_ROUTINE lpStartAddress,
  45. LPVOID lpParameter,
  46. DWORD dwCreationFlags,
  47. LPDWORD lpThreadId
  48. )
  49. /*++
  50. Routine Description:
  51. A thread object can be created to execute within the address space of the
  52. another process using CreateRemoteThread.
  53. Creating a thread causes a new thread of execution to begin in the address
  54. space of the current process. The thread has access to all objects opened
  55. by the process.
  56. The thread begins executing at the address specified by the StartAddress
  57. parameter. If the thread returns from this procedure, the results are
  58. un-specified.
  59. The thread remains in the system until it has terminated and
  60. all handles to the thread
  61. have been closed through a call to CloseHandle.
  62. When a thread terminates, it attains a state of signaled satisfying all
  63. waits on the object.
  64. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
  65. object type specific access flags are valid for thread objects:
  66. - THREAD_QUERY_INFORMATION - This access is required to read
  67. certain information from the thread object.
  68. - SYNCHRONIZE - This access is required to wait on a thread
  69. object.
  70. - THREAD_GET_CONTEXT - This access is required to read the
  71. context of a thread using GetThreadContext.
  72. - THREAD_SET_CONTEXT - This access is required to write the
  73. context of a thread using SetThreadContext.
  74. - THREAD_SUSPEND_RESUME - This access is required to suspend or
  75. resume a thread using SuspendThread or ResumeThread.
  76. - THREAD_ALL_ACCESS - This set of access flags specifies all of
  77. the possible access flags for a thread object.
  78. Arguments:
  79. hProcess - Supplies the handle to the process in which the thread is
  80. to be create in.
  81. lpThreadAttributes - An optional parameter that may be used to specify
  82. the attributes of the new thread. If the parameter is not
  83. specified, then the thread is created without a security
  84. descriptor, and the resulting handle is not inherited on process
  85. creation.
  86. dwStackSize - Supplies the size in bytes of the stack for the new thread.
  87. A value of zero specifies that the thread's stack size should be
  88. the same size as the stack size of the first thread in the process.
  89. This size is specified in the application's executable file.
  90. lpStartAddress - Supplies the starting address of the new thread. The
  91. address is logically a procedure that never returns and that
  92. accepts a single 32-bit pointer argument.
  93. lpParameter - Supplies a single parameter value passed to the thread.
  94. dwCreationFlags - Supplies additional flags that control the creation
  95. of the thread.
  96. dwCreationFlags Flags:
  97. CREATE_SUSPENDED - The thread is created in a suspended state.
  98. The creator can resume this thread using ResumeThread.
  99. Until this is done, the thread will not begin execution.
  100. lpThreadId - Returns the thread identifier of the thread. The
  101. thread ID is valid until the thread terminates.
  102. Return Value:
  103. NON-NULL - Returns a handle to the new thread. The handle has full
  104. access to the new thread and may be used in any API that
  105. requires a handle to a thread object.
  106. NULL - The operation failed. Extended error status is available
  107. using GetLastError.
  108. --*/
  109. {
  110. NTSTATUS Status;
  111. OBJECT_ATTRIBUTES Obja;
  112. POBJECT_ATTRIBUTES pObja;
  113. HANDLE Handle;
  114. CONTEXT ThreadContext;
  115. INITIAL_TEB InitialTeb;
  116. CLIENT_ID ClientId;
  117. BASE_API_MSG m;
  118. ULONG i;
  119. PBASE_CREATETHREAD_MSG a = (PBASE_CREATETHREAD_MSG)&m.u.CreateThread;
  120. #if defined (WX86)
  121. BOOL bWx86 = FALSE;
  122. HANDLE Wx86Info;
  123. PWX86TIB Wx86Tib;
  124. #endif
  125. //
  126. // Allocate a stack for this thread in the address space of the target
  127. // process.
  128. //
  129. Status = BaseCreateStack(
  130. hProcess,
  131. dwStackSize,
  132. 0L,
  133. &InitialTeb
  134. );
  135. if ( !NT_SUCCESS(Status) ) {
  136. BaseSetLastNTError(Status);
  137. return NULL;
  138. }
  139. //
  140. // Create an initial context for the new thread.
  141. //
  142. BaseInitializeContext(
  143. &ThreadContext,
  144. lpParameter,
  145. (PVOID)lpStartAddress,
  146. InitialTeb.StackBase,
  147. BaseContextTypeThread
  148. );
  149. pObja = BaseFormatObjectAttributes(&Obja,lpThreadAttributes,NULL);
  150. Status = NtCreateThread(
  151. &Handle,
  152. THREAD_ALL_ACCESS,
  153. pObja,
  154. hProcess,
  155. &ClientId,
  156. &ThreadContext,
  157. &InitialTeb,
  158. TRUE
  159. );
  160. if (!NT_SUCCESS(Status)) {
  161. BaseFreeThreadStack(hProcess,NULL, &InitialTeb);
  162. BaseSetLastNTError(Status);
  163. return NULL;
  164. }
  165. try {
  166. #if defined (WX86)
  167. //
  168. // Check the Target Processes to see if this is a Wx86 process
  169. //
  170. Status = NtQueryInformationProcess(hProcess,
  171. ProcessWx86Information,
  172. &Wx86Info,
  173. sizeof(Wx86Info),
  174. NULL
  175. );
  176. if (!NT_SUCCESS(Status)) {
  177. leave;
  178. }
  179. Wx86Tib = (PWX86TIB)NtCurrentTeb()->Vdm;
  180. //
  181. // if Wx86 process, setup for emulation
  182. //
  183. if ((ULONG)Wx86Info == sizeof(WX86TIB)) {
  184. //
  185. // create a WX86Tib and initialize it's Teb->Vdm.
  186. //
  187. Status = BaseCreateWx86Tib(hProcess,
  188. Handle,
  189. (ULONG)lpStartAddress,
  190. dwStackSize,
  191. 0L,
  192. (Wx86Tib &&
  193. Wx86Tib->Size == sizeof(WX86TIB) &&
  194. Wx86Tib->EmulateInitialPc)
  195. );
  196. if (!NT_SUCCESS(Status)) {
  197. leave;
  198. }
  199. bWx86 = TRUE;
  200. }
  201. else if (Wx86Tib && Wx86Tib->EmulateInitialPc) {
  202. //
  203. // if not Wx86 process, and caller wants to call x86 code in that
  204. // process, fail the call.
  205. //
  206. Status = STATUS_ACCESS_DENIED;
  207. leave;
  208. }
  209. #endif // WX86
  210. //
  211. // Call the Windows server to let it know about the
  212. // process.
  213. //
  214. if ( !BaseRunningInServerProcess ) {
  215. a->ThreadHandle = Handle;
  216. a->ClientId = ClientId;
  217. CsrClientCallServer( (PCSR_API_MSG)&m,
  218. NULL,
  219. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  220. BasepCreateThread
  221. ),
  222. sizeof( *a )
  223. );
  224. Status = m.ReturnValue;
  225. }
  226. else {
  227. if (hProcess != NtCurrentProcess()) {
  228. CSRREMOTEPROCPROC ProcAddress;
  229. ProcAddress = (CSRREMOTEPROCPROC)GetProcAddress(
  230. GetModuleHandleA("csrsrv"),
  231. "CsrCreateRemoteThread"
  232. );
  233. if (ProcAddress) {
  234. Status = (ProcAddress)(Handle, &ClientId);
  235. }
  236. }
  237. }
  238. if (!NT_SUCCESS(Status)) {
  239. Status = (NTSTATUS)STATUS_NO_MEMORY;
  240. }
  241. else {
  242. if ( ARGUMENT_PRESENT(lpThreadId) ) {
  243. *lpThreadId = (DWORD)ClientId.UniqueThread;
  244. }
  245. if (!( dwCreationFlags & CREATE_SUSPENDED) ) {
  246. NtResumeThread(Handle,&i);
  247. }
  248. }
  249. }
  250. finally {
  251. if (!NT_SUCCESS(Status)) {
  252. BaseFreeThreadStack(hProcess,
  253. Handle,
  254. &InitialTeb
  255. );
  256. NtTerminateThread(Handle, Status);
  257. BaseSetLastNTError(Status);
  258. Handle = NULL;
  259. }
  260. }
  261. return Handle;
  262. }
  263. BOOL
  264. APIENTRY
  265. SetThreadPriority(
  266. HANDLE hThread,
  267. int nPriority
  268. )
  269. /*++
  270. Routine Description:
  271. The specified thread's priority can be set using SetThreadPriority.
  272. A thread's priority may be set using SetThreadPriority. This call
  273. allows the thread's relative execution importance to be communicated
  274. to the system. The system normally schedules threads according to
  275. their priority. The system is free to temporarily boost the
  276. priority of a thread when signifigant events occur (e.g. keyboard
  277. or mouse input...). Similarly, as a thread runs without blocking,
  278. the system will decay its priority. The system will never decay the
  279. priority below the value set by this call.
  280. In the absence of system originated priority boosts, threads will be
  281. scheduled in a round-robin fashion at each priority level from
  282. THREAD_PRIORITY_TIME_CRITICAL to THREAD_PRIORITY_IDLE. Only when there
  283. are no runnable threads at a higher level, will scheduling of
  284. threads at a lower level take place.
  285. All threads initially start at THREAD_PRIORITY_NORMAL.
  286. If for some reason the thread needs more priority, it can be
  287. switched to THREAD_PRIORITY_ABOVE_NORMAL or THREAD_PRIORITY_HIGHEST.
  288. Switching to THREAD_PRIORITY_TIME_CRITICAL should only be done in extreme
  289. situations. Since these threads are given the highes priority, they
  290. should only run in short bursts. Running for long durations will
  291. soak up the systems processing bandwidth starving threads at lower
  292. levels.
  293. If a thread needs to do low priority work, or should only run there
  294. is nothing else to do, its priority should be set to
  295. THREAD_PRIORITY_BELOW_NORMAL or THREAD_PRIORITY_LOWEST. For extreme
  296. cases, THREAD_PRIORITY_IDLE can be used.
  297. Care must be taken when manipulating priorites. If priorities are
  298. used carelessly (every thread is set to THREAD_PRIORITY_TIME_CRITICAL),
  299. the effects of priority modifications can produce undesireable
  300. effects (e.g. starvation, no effect...).
  301. Arguments:
  302. hThread - Supplies a handle to the thread whose priority is to be
  303. set. The handle must have been created with
  304. THREAD_SET_INFORMATION access.
  305. nPriority - Supplies the priority value for the thread. The
  306. following five priority values (ordered from lowest priority to
  307. highest priority) are allowed.
  308. nPriority Values:
  309. THREAD_PRIORITY_IDLE - The thread's priority should be set to
  310. the lowest possible settable priority.
  311. THREAD_PRIORITY_LOWEST - The thread's priority should be set to
  312. the next lowest possible settable priority.
  313. THREAD_PRIORITY_BELOW_NORMAL - The thread's priority should be
  314. set to just below normal.
  315. THREAD_PRIORITY_NORMAL - The thread's priority should be set to
  316. the normal priority value. This is the value that all
  317. threads begin execution at.
  318. THREAD_PRIORITY_ABOVE_NORMAL - The thread's priority should be
  319. set to just above normal priority.
  320. THREAD_PRIORITY_HIGHEST - The thread's priority should be set to
  321. the next highest possible settable priority.
  322. THREAD_PRIORITY_TIME_CRITICAL - The thread's priority should be set
  323. to the highest possible settable priority. This priority is
  324. very likely to interfere with normal operation of the
  325. system.
  326. Return Value:
  327. TRUE - The operation was successful
  328. FALSE/NULL - The operation failed. Extended error status is available
  329. using GetLastError.
  330. --*/
  331. {
  332. NTSTATUS Status;
  333. LONG BasePriority;
  334. BasePriority = (LONG)nPriority;
  335. //
  336. // saturation is indicated by calling with a value of 16 or -16
  337. //
  338. if ( BasePriority == THREAD_PRIORITY_TIME_CRITICAL ) {
  339. BasePriority = ((HIGH_PRIORITY + 1) / 2);
  340. }
  341. else if ( BasePriority == THREAD_PRIORITY_IDLE ) {
  342. BasePriority = -((HIGH_PRIORITY + 1) / 2);
  343. }
  344. Status = NtSetInformationThread(
  345. hThread,
  346. ThreadBasePriority,
  347. &BasePriority,
  348. sizeof(BasePriority)
  349. );
  350. if ( !NT_SUCCESS(Status) ) {
  351. BaseSetLastNTError(Status);
  352. return FALSE;
  353. }
  354. return TRUE;
  355. }
  356. int
  357. APIENTRY
  358. GetThreadPriority(
  359. HANDLE hThread
  360. )
  361. /*++
  362. Routine Description:
  363. The specified thread's priority can be read using GetThreadPriority.
  364. Arguments:
  365. hThread - Supplies a handle to the thread whose priority is to be
  366. set. The handle must have been created with
  367. THREAD_QUERY_INFORMATION access.
  368. Return Value:
  369. The value of the thread's current priority is returned. If an error
  370. occured, the value THREAD_PRIORITY_ERROR_RETURN is returned.
  371. Extended error status is available using GetLastError.
  372. --*/
  373. {
  374. NTSTATUS Status;
  375. THREAD_BASIC_INFORMATION BasicInfo;
  376. int returnvalue;
  377. Status = NtQueryInformationThread(
  378. hThread,
  379. ThreadBasicInformation,
  380. &BasicInfo,
  381. sizeof(BasicInfo),
  382. NULL
  383. );
  384. if ( !NT_SUCCESS(Status) ) {
  385. BaseSetLastNTError(Status);
  386. return (int)THREAD_PRIORITY_ERROR_RETURN;
  387. }
  388. returnvalue = (int)BasicInfo.BasePriority;
  389. if ( returnvalue > THREAD_BASE_PRIORITY_MAX ) {
  390. returnvalue = THREAD_PRIORITY_TIME_CRITICAL;
  391. }
  392. else if ( returnvalue < THREAD_BASE_PRIORITY_MIN ) {
  393. returnvalue = THREAD_PRIORITY_IDLE;
  394. }
  395. return returnvalue;
  396. }
  397. BOOL
  398. WINAPI
  399. SetThreadPriorityBoost(
  400. HANDLE hThread,
  401. BOOL bDisablePriorityBoost
  402. )
  403. {
  404. NTSTATUS Status;
  405. ULONG DisableBoost;
  406. DisableBoost = bDisablePriorityBoost ? 1 : 0;
  407. Status = NtSetInformationThread(
  408. hThread,
  409. ThreadPriorityBoost,
  410. &DisableBoost,
  411. sizeof(DisableBoost)
  412. );
  413. if ( !NT_SUCCESS(Status) ) {
  414. BaseSetLastNTError(Status);
  415. return FALSE;
  416. }
  417. return TRUE;
  418. }
  419. BOOL
  420. WINAPI
  421. GetThreadPriorityBoost(
  422. HANDLE hThread,
  423. PBOOL pDisablePriorityBoost
  424. )
  425. {
  426. NTSTATUS Status;
  427. DWORD DisableBoost;
  428. BOOL returnvalue;
  429. Status = NtQueryInformationThread(
  430. hThread,
  431. ThreadPriorityBoost,
  432. &DisableBoost,
  433. sizeof(DisableBoost),
  434. NULL
  435. );
  436. if ( !NT_SUCCESS(Status) ) {
  437. BaseSetLastNTError(Status);
  438. return FALSE;
  439. }
  440. *pDisablePriorityBoost = DisableBoost;
  441. return TRUE;
  442. }
  443. VOID
  444. APIENTRY
  445. ExitThread(
  446. DWORD dwExitCode
  447. )
  448. /*++
  449. Routine Description:
  450. The current thread can exit using ExitThread.
  451. ExitThread is the prefered method of exiting a thread. When this
  452. API is called (either explicitly or by returning from a thread
  453. procedure), The current thread's stack is deallocated and the thread
  454. terminates. If the thread is the last thread in the process when
  455. this API is called, the behavior of this API does not change. DLLs
  456. are not notified as a result of a call to ExitThread.
  457. Arguments:
  458. dwExitCode - Supplies the termination status for the thread.
  459. Return Value:
  460. None.
  461. --*/
  462. {
  463. MEMORY_BASIC_INFORMATION MemInfo;
  464. NTSTATUS st;
  465. ULONG LastThread;
  466. st = NtQueryInformationThread(
  467. NtCurrentThread(),
  468. ThreadAmILastThread,
  469. &LastThread,
  470. sizeof(LastThread),
  471. NULL
  472. );
  473. if ( st == STATUS_SUCCESS && LastThread ) {
  474. ExitProcess(dwExitCode);
  475. }
  476. else {
  477. LdrShutdownThread();
  478. st = NtQueryVirtualMemory(
  479. NtCurrentProcess(),
  480. NtCurrentTeb()->NtTib.StackLimit,
  481. MemoryBasicInformation,
  482. (PVOID)&MemInfo,
  483. sizeof(MemInfo),
  484. NULL
  485. );
  486. if ( !NT_SUCCESS(st) ) {
  487. RtlRaiseStatus(st);
  488. }
  489. BaseSwitchStackThenTerminate(
  490. MemInfo.AllocationBase,
  491. &NtCurrentTeb()->UserReserved[0],
  492. dwExitCode
  493. );
  494. }
  495. }
  496. BOOL
  497. APIENTRY
  498. TerminateThread(
  499. HANDLE hThread,
  500. DWORD dwExitCode
  501. )
  502. /*++
  503. Routine Description:
  504. A thread may be terminated using TerminateThread.
  505. TerminateThread is used to cause a thread to terminate user-mode
  506. execution. There is nothing a thread can to to predict or prevent
  507. when this occurs. If a process has a handle with appropriate
  508. termination access to the thread or to the threads process, then the
  509. thread can be unconditionally terminated without notice. When this
  510. occurs, the target thread has no chance to execute any user-mode
  511. code and its initial stack is not deallocated. The thread attains a
  512. state of signaled satisfying any waits on the thread. The thread's
  513. termination status is updated from its initial value of
  514. STATUS_PENDING to the value of the TerminationStatus parameter.
  515. Terminating a thread does not remove a thread from the system. The
  516. thread is not removed from the system until the last handle to the
  517. thread is closed.
  518. Arguments:
  519. hThread - Supplies a handle to the thread to terminate. The handle
  520. must have been created with THREAD_TERMINATE access.
  521. dwExitCode - Supplies the termination status for the thread.
  522. Return Value:
  523. TRUE - The operation was successful
  524. FALSE/NULL - The operation failed. Extended error status is available
  525. using GetLastError.
  526. --*/
  527. {
  528. NTSTATUS Status;
  529. if ( hThread == NULL ) {
  530. SetLastError(ERROR_INVALID_HANDLE);
  531. return FALSE;
  532. }
  533. Status = NtTerminateThread(hThread,(NTSTATUS)dwExitCode);
  534. if ( NT_SUCCESS(Status) ) {
  535. return TRUE;
  536. }
  537. else {
  538. BaseSetLastNTError(Status);
  539. return FALSE;
  540. }
  541. }
  542. BOOL
  543. APIENTRY
  544. GetExitCodeThread(
  545. HANDLE hThread,
  546. LPDWORD lpExitCode
  547. )
  548. /*++
  549. Routine Description:
  550. The termination status of a thread can be read using
  551. GetExitCodeThread.
  552. If a Thread is in the signaled state, calling this function returns
  553. the termination status of the thread. If the thread is not yet
  554. signaled, the termination status returned is STILL_ACTIVE.
  555. Arguments:
  556. hThread - Supplies a handle to the thread whose termination status is
  557. to be read. The handle must have been created with
  558. THREAD_QUERY_INFORMATION access.
  559. lpExitCode - Returns the current termination status of the
  560. thread.
  561. Return Value:
  562. TRUE - The operation was successful
  563. FALSE/NULL - The operation failed. Extended error status is available
  564. using GetLastError.
  565. --*/
  566. {
  567. NTSTATUS Status;
  568. THREAD_BASIC_INFORMATION BasicInformation;
  569. Status = NtQueryInformationThread(
  570. hThread,
  571. ThreadBasicInformation,
  572. &BasicInformation,
  573. sizeof(BasicInformation),
  574. NULL
  575. );
  576. if ( NT_SUCCESS(Status) ) {
  577. *lpExitCode = BasicInformation.ExitStatus;
  578. return TRUE;
  579. }
  580. else {
  581. BaseSetLastNTError(Status);
  582. return FALSE;
  583. }
  584. }
  585. HANDLE
  586. APIENTRY
  587. GetCurrentThread(
  588. VOID
  589. )
  590. /*++
  591. Routine Description:
  592. A pseudo handle to the current thread may be retrieved using
  593. GetCurrentThread.
  594. A special constant is exported by Win32 that is interpreted as a
  595. handle to the current thread. This handle may be used to specify
  596. the current thread whenever a thread handle is required. On Win32,
  597. this handle has THREAD_ALL_ACCESS to the current thread. On
  598. NT/Win32, this handle has the maximum access allowed by any security
  599. descriptor placed on the current thread.
  600. Arguments:
  601. None.
  602. Return Value:
  603. Returns the pseudo handle of the current thread.
  604. --*/
  605. {
  606. return NtCurrentThread();
  607. }
  608. DWORD
  609. APIENTRY
  610. GetCurrentThreadId(
  611. VOID
  612. )
  613. /*++
  614. Routine Description:
  615. The thread ID of the current thread may be retrieved using
  616. GetCurrentThreadId.
  617. Arguments:
  618. None.
  619. Return Value:
  620. Returns a unique value representing the thread ID of the currently
  621. executing thread. The return value may be used to identify a thread
  622. in the system.
  623. --*/
  624. {
  625. return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
  626. }
  627. BOOL
  628. APIENTRY
  629. GetThreadContext(
  630. HANDLE hThread,
  631. LPCONTEXT lpContext
  632. )
  633. /*++
  634. Routine Description:
  635. The context of a specified thread can be retreived using
  636. GetThreadContext.
  637. This function is used to retreive the context of the specified
  638. thread. The API allows selective context to be retrieved based on
  639. the value of the ContextFlags field of the context structure. The
  640. specified thread does not have to be being debugged in order for
  641. this API to operate. The caller must simply have a handle to the
  642. thread that was created with THREAD_GET_CONTEXT access.
  643. Arguments:
  644. hThread - Supplies an open handle to a thread whose context is to be
  645. retreived. The handle must have been created with
  646. THREAD_GET_CONTEXT access to the thread.
  647. lpContext - Supplies the address of a context structure that
  648. receives the appropriate context of the specified thread. The
  649. value of the ContextFlags field of this structure specifies
  650. which portions of a threads context are to be retreived. The
  651. context structure is highly machine specific. There are
  652. currently two versions of the context structure. One version
  653. exists for x86 processors, and another exists for MIPS
  654. processors.
  655. Return Value:
  656. TRUE - The operation was successful.
  657. FALSE/NULL - The operation failed. Extended error status is available
  658. using GetLastError.
  659. --*/
  660. {
  661. NTSTATUS Status;
  662. Status = NtGetContextThread(hThread,lpContext);
  663. if ( !NT_SUCCESS(Status) ) {
  664. BaseSetLastNTError(Status);
  665. return FALSE;
  666. }
  667. else {
  668. return TRUE;
  669. }
  670. }
  671. BOOL
  672. APIENTRY
  673. SetThreadContext(
  674. HANDLE hThread,
  675. CONST CONTEXT *lpContext
  676. )
  677. /*++
  678. Routine Description:
  679. This function is used to set the context in the specified thread.
  680. The API allows selective context to be set based on the value of the
  681. ContextFlags field of the context structure. The specified thread
  682. does not have to be being debugged in order for this API to operate.
  683. The caller must simply have a handle to the thread that was created
  684. with THREAD_SET_CONTEXT access.
  685. Arguments:
  686. hThread - Supplies an open handle to a thread whose context is to be
  687. written. The handle must have been created with
  688. THREAD_SET_CONTEXT access to the thread.
  689. lpContext - Supplies the address of a context structure that
  690. contains the context that is to be set in the specified thread.
  691. The value of the ContextFlags field of this structure specifies
  692. which portions of a threads context are to be set. Some values
  693. in the context structure are not settable and are silently set
  694. to the correct value. This includes cpu status register bits
  695. that specify the priviledged processor mode, debug register
  696. global enabling bits, and other state that must be completely
  697. controlled by the operating system.
  698. Return Value:
  699. TRUE - The operation was successful.
  700. FALSE/NULL - The operation failed. Extended error status is available
  701. using GetLastError.
  702. --*/
  703. {
  704. NTSTATUS Status;
  705. Status = NtSetContextThread(hThread,(PCONTEXT)lpContext);
  706. if ( !NT_SUCCESS(Status) ) {
  707. BaseSetLastNTError(Status);
  708. return FALSE;
  709. }
  710. else {
  711. return TRUE;
  712. }
  713. }
  714. DWORD
  715. APIENTRY
  716. SuspendThread(
  717. HANDLE hThread
  718. )
  719. /*++
  720. Routine Description:
  721. A thread can be suspended using SuspendThread.
  722. Suspending a thread causes the thread to stop executing user-mode
  723. (or application) code. Each thread has a suspend count (with a
  724. maximum value of MAXIMUM_SUSPEND_COUNT). If the suspend count is
  725. greater than zero, the thread is suspended; otherwise, the thread is
  726. not suspended and is eligible for execution.
  727. Calling SuspendThread causes the target thread's suspend count to
  728. increment. Attempting to increment past the maximum suspend count
  729. causes an error without incrementing the count.
  730. Arguments:
  731. hThread - Supplies a handle to the thread that is to be suspended.
  732. The handle must have been created with THREAD_SUSPEND_RESUME
  733. access to the thread.
  734. Return Value:
  735. -1 - The operation failed. Extended error status is available using
  736. GetLastError.
  737. Other - The target thread was suspended. The return value is the thread's
  738. previous suspend count.
  739. --*/
  740. {
  741. NTSTATUS Status;
  742. DWORD PreviousSuspendCount;
  743. Status = NtSuspendThread(hThread,&PreviousSuspendCount);
  744. if ( !NT_SUCCESS(Status) ) {
  745. BaseSetLastNTError(Status);
  746. return (DWORD)-1;
  747. }
  748. else {
  749. return PreviousSuspendCount;
  750. }
  751. }
  752. DWORD
  753. APIENTRY
  754. ResumeThread(
  755. IN HANDLE hThread
  756. )
  757. /*++
  758. Routine Description:
  759. A thread can be resumed using ResumeThread.
  760. Resuming a thread object checks the suspend count of the subject
  761. thread. If the suspend count is zero, then the thread is not
  762. currently suspended and no operation is performed. Otherwise, the
  763. subject thread's suspend count is decremented. If the resultant
  764. value is zero , then the execution of the subject thread is resumed.
  765. The previous suspend count is returned as the function value. If
  766. the return value is zero, then the subject thread was not previously
  767. suspended. If the return value is one, then the subject thread's
  768. the subject thread is still suspended and must be resumed the number
  769. of times specified by the return value minus one before it will
  770. actually resume execution.
  771. Note that while reporting debug events, all threads withing the
  772. reporting process are frozen. This has nothing to do with
  773. SuspendThread or ResumeThread. Debuggers are expected to use
  774. SuspendThread and ResumeThread to limit the set of threads that can
  775. execute within a process. By suspending all threads in a process
  776. except for the one reporting a debug event, it is possible to
  777. "single step" a single thread. The other threads will not be
  778. released by a continue if they are suspended.
  779. Arguments:
  780. hThread - Supplies a handle to the thread that is to be resumed.
  781. The handle must have been created with THREAD_SUSPEND_RESUME
  782. access to the thread.
  783. Return Value:
  784. -1 - The operation failed. Extended error status is available using
  785. GetLastError.
  786. Other - The target thread was resumed (or was not previously
  787. suspended). The return value is the thread's previous suspend
  788. count.
  789. --*/
  790. {
  791. NTSTATUS Status;
  792. DWORD PreviousSuspendCount;
  793. Status = NtResumeThread(hThread,&PreviousSuspendCount);
  794. if ( !NT_SUCCESS(Status) ) {
  795. BaseSetLastNTError(Status);
  796. return (DWORD)-1;
  797. }
  798. else {
  799. return PreviousSuspendCount;
  800. }
  801. }
  802. VOID
  803. APIENTRY
  804. RaiseException(
  805. DWORD dwExceptionCode,
  806. DWORD dwExceptionFlags,
  807. DWORD nNumberOfArguments,
  808. CONST DWORD *lpArguments
  809. )
  810. /*++
  811. Routine Description:
  812. Raising an exception causes the exception dispatcher to go through
  813. its search for an exception handler. This includes debugger
  814. notification, frame based handler searching, and system default
  815. actions.
  816. Arguments:
  817. dwExceptionCode - Supplies the exception code of the exception being
  818. raised. This value may be obtained in exception filters and in
  819. exception handlers by calling GetExceptionCode.
  820. dwExceptionFlags - Supplies a set of flags associated with the exception.
  821. dwExceptionFlags Flags:
  822. EXCEPTION_NONCONTINUABLE - The exception is non-continuable.
  823. Returning EXCEPTION_CONTINUE_EXECUTION from an exception
  824. marked in this way causes the
  825. STATUS_NONCONTINUABLE_EXCEPTION exception.
  826. nNumberOfArguments - Supplies the number of arguments associated
  827. with the exception. This value may not exceed
  828. EXCEPTION_MAXIMUM_PARAMETERS. This parameter is ignored if
  829. lpArguments is NULL.
  830. lpArguments - An optional parameter, that if present supplies the
  831. arguments for the exception.
  832. Return Value:
  833. None.
  834. --*/
  835. {
  836. EXCEPTION_RECORD ExceptionRecord;
  837. ULONG n;
  838. PULONG s,d;
  839. ExceptionRecord.ExceptionCode = (DWORD)dwExceptionCode;
  840. ExceptionRecord.ExceptionFlags = dwExceptionFlags & EXCEPTION_NONCONTINUABLE;
  841. ExceptionRecord.ExceptionRecord = NULL;
  842. ExceptionRecord.ExceptionAddress = (PVOID)RaiseException;
  843. if ( ARGUMENT_PRESENT(lpArguments) ) {
  844. n = nNumberOfArguments;
  845. if ( n > EXCEPTION_MAXIMUM_PARAMETERS ) {
  846. n = EXCEPTION_MAXIMUM_PARAMETERS;
  847. }
  848. ExceptionRecord.NumberParameters = n;
  849. s = (PULONG)lpArguments;
  850. d = ExceptionRecord.ExceptionInformation;
  851. while(n--){
  852. *d++ = *s++;
  853. }
  854. }
  855. else {
  856. ExceptionRecord.NumberParameters = 0;
  857. }
  858. RtlRaiseException(&ExceptionRecord);
  859. }
  860. UINT
  861. GetErrorMode();
  862. BOOLEAN BasepAlreadyHadHardError = FALSE;
  863. LPTOP_LEVEL_EXCEPTION_FILTER BasepCurrentTopLevelFilter;
  864. LPTOP_LEVEL_EXCEPTION_FILTER
  865. WINAPI
  866. SetUnhandledExceptionFilter(
  867. LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
  868. )
  869. /*++
  870. Routine Description:
  871. This function allows an application to supersede the top level
  872. exception handler that Win32 places at the top of each thread and
  873. process.
  874. If an exception occurs, and it makes it to the Win32 unhandled
  875. exception filter, and the process is not being debugged, the Win32
  876. filter will call the unhandled exception filter specified by
  877. lpTopLevelExceptionFilter.
  878. This filter may return:
  879. EXCEPTION_EXECUTE_HANDLER - Return from the Win32
  880. UnhandledExceptionFilter and execute the associated
  881. exception handler. This will usually result in process
  882. termination
  883. EXCEPTION_CONTINUE_EXECUTION - Return from the Win32
  884. UnhandledExceptionFilter and continue execution from the
  885. point of the exception. The filter is of course free to
  886. modify the continuation state my modifying the passed
  887. exception information.
  888. EXCEPTION_CONTINUE_SEARCH - Proceed with normal execution of the
  889. Win32 UnhandledExceptionFilter. e.g. obey the SetErrorMode
  890. flags, or invoke the Application Error popup.
  891. This function is not a general vectored exception handling
  892. mechanism. It is intended to be used to establish a per-process
  893. exception filter that can monitor unhandled exceptions at the
  894. process level and respond to these exceptions appropriately.
  895. Arguments:
  896. lpTopLevelExceptionFilter - Supplies the address of a top level
  897. filter function that will be called whenever the Win32
  898. UnhandledExceptionFilter gets control, and the process is NOT
  899. being debugged. A value of NULL specifies default handling
  900. within the Win32 UnhandledExceptionFilter.
  901. Return Value:
  902. This function returns the address of the previous exception filter
  903. established with this API. A value of NULL means that there is no
  904. current top level handler.
  905. --*/
  906. {
  907. LPTOP_LEVEL_EXCEPTION_FILTER PreviousTopLevelFilter;
  908. PreviousTopLevelFilter = BasepCurrentTopLevelFilter;
  909. BasepCurrentTopLevelFilter = lpTopLevelExceptionFilter;
  910. return PreviousTopLevelFilter;
  911. }
  912. LONG
  913. BasepCheckForReadOnlyResource(
  914. PVOID Va
  915. )
  916. {
  917. ULONG RegionSize;
  918. ULONG OldProtect;
  919. NTSTATUS Status;
  920. MEMORY_BASIC_INFORMATION MemInfo;
  921. PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
  922. ULONG ResourceSize;
  923. char *rbase, *va;
  924. LONG ReturnValue;
  925. //
  926. // Locate the base address that continas this va
  927. //
  928. Status = NtQueryVirtualMemory(
  929. NtCurrentProcess(),
  930. Va,
  931. MemoryBasicInformation,
  932. (PVOID)&MemInfo,
  933. sizeof(MemInfo),
  934. NULL
  935. );
  936. if ( !NT_SUCCESS(Status) ) {
  937. return EXCEPTION_CONTINUE_SEARCH;
  938. }
  939. //
  940. // if the va is readonly and in an image then continue
  941. //
  942. if ( !((MemInfo.Protect == PAGE_READONLY) && (MemInfo.Type == MEM_IMAGE)) ){
  943. return EXCEPTION_CONTINUE_SEARCH;
  944. }
  945. ReturnValue = EXCEPTION_CONTINUE_SEARCH;
  946. try {
  947. ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
  948. RtlImageDirectoryEntryToData(MemInfo.AllocationBase,
  949. TRUE,
  950. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  951. &ResourceSize
  952. );
  953. rbase = (char *)ResourceDirectory;
  954. va = (char *)Va;
  955. if ( rbase && va >= rbase && va < rbase+ResourceSize ) {
  956. RegionSize = 1;
  957. Status = NtProtectVirtualMemory(
  958. NtCurrentProcess(),
  959. &va,
  960. &RegionSize,
  961. PAGE_READWRITE,
  962. &OldProtect
  963. );
  964. if ( NT_SUCCESS(Status) ) {
  965. ReturnValue = EXCEPTION_CONTINUE_EXECUTION;
  966. }
  967. }
  968. }
  969. except (EXCEPTION_EXECUTE_HANDLER) {
  970. ;
  971. }
  972. return ReturnValue;
  973. }
  974. LONG
  975. UnhandledExceptionFilter(
  976. struct _EXCEPTION_POINTERS *ExceptionInfo
  977. )
  978. {
  979. NTSTATUS Status;
  980. ULONG Parameters[ 4 ];
  981. ULONG Response;
  982. HANDLE DebugPort;
  983. CHAR AeDebuggerCmdLine[256];
  984. CHAR AeAutoDebugString[8];
  985. BOOLEAN AeAutoDebug;
  986. ULONG ResponseFlag;
  987. LONG FilterReturn;
  988. PRTL_CRITICAL_SECTION PebLockPointer;
  989. //
  990. // If we take a write fault, then attampt to make the memory writable. If this
  991. // succeeds, then silently proceed
  992. //
  993. if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION
  994. && ExceptionInfo->ExceptionRecord->ExceptionInformation[0] ) {
  995. FilterReturn = BasepCheckForReadOnlyResource((PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
  996. if ( FilterReturn == EXCEPTION_CONTINUE_EXECUTION ) {
  997. return FilterReturn;
  998. }
  999. }
  1000. //
  1001. // If the process is being debugged, just let the exception happen
  1002. // so that the debugger can see it. This way the debugger can ignore
  1003. // all first chance exceptions.
  1004. //
  1005. DebugPort = (HANDLE)NULL;
  1006. Status = NtQueryInformationProcess(
  1007. GetCurrentProcess(),
  1008. ProcessDebugPort,
  1009. (PVOID)&DebugPort,
  1010. sizeof(DebugPort),
  1011. NULL
  1012. );
  1013. if ( NT_SUCCESS(Status) && DebugPort ) {
  1014. //
  1015. // Process is being debugged.
  1016. // Return a code that specifies that the exception
  1017. // processing is to continue
  1018. //
  1019. return EXCEPTION_CONTINUE_SEARCH;
  1020. }
  1021. if ( BasepCurrentTopLevelFilter ) {
  1022. FilterReturn = (BasepCurrentTopLevelFilter)(ExceptionInfo);
  1023. if ( FilterReturn == EXCEPTION_EXECUTE_HANDLER ||
  1024. FilterReturn == EXCEPTION_CONTINUE_EXECUTION ) {
  1025. return FilterReturn;
  1026. }
  1027. }
  1028. if ( GetErrorMode() & SEM_NOGPFAULTERRORBOX ) {
  1029. return EXCEPTION_EXECUTE_HANDLER;
  1030. }
  1031. //
  1032. // The process is not being debugged, so do the hard error
  1033. // popup.
  1034. //
  1035. Parameters[ 0 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode;
  1036. Parameters[ 1 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionAddress;
  1037. //
  1038. // For inpage i/o errors, juggle the real status code to overwrite the
  1039. // read/write field
  1040. //
  1041. if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR ) {
  1042. Parameters[ 2 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 2 ];
  1043. }
  1044. else {
  1045. Parameters[ 2 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 0 ];
  1046. }
  1047. Parameters[ 3 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ];
  1048. //
  1049. // See if a debugger has been programmed in. If so, use the
  1050. // debugger specified. If not then there is no AE Cancel support
  1051. // DEVL systems will default the debugger command line. Retail
  1052. // systems will not.
  1053. //
  1054. ResponseFlag = OptionOk;
  1055. AeAutoDebug = FALSE;
  1056. //
  1057. // If we are holding the PebLock, then the createprocess will fail
  1058. // because a new thread will also need this lock. Avoid this by peeking
  1059. // inside the PebLock and looking to see if we own it. If we do, then just allow
  1060. // a regular popup.
  1061. //
  1062. PebLockPointer = NtCurrentPeb()->FastPebLock;
  1063. if ( PebLockPointer->OwningThread != NtCurrentTeb()->ClientId.UniqueThread ) {
  1064. try {
  1065. if ( GetProfileString(
  1066. "AeDebug",
  1067. "Debugger",
  1068. NULL,
  1069. AeDebuggerCmdLine,
  1070. sizeof(AeDebuggerCmdLine)-1
  1071. ) ) {
  1072. ResponseFlag = OptionOkCancel;
  1073. }
  1074. if ( GetProfileString(
  1075. "AeDebug",
  1076. "Auto",
  1077. "0",
  1078. AeAutoDebugString,
  1079. sizeof(AeAutoDebugString)-1
  1080. ) ) {
  1081. if ( !strcmp(AeAutoDebugString,"1") ) {
  1082. if ( ResponseFlag == OptionOkCancel ) {
  1083. AeAutoDebug = TRUE;
  1084. }
  1085. }
  1086. }
  1087. }
  1088. except (EXCEPTION_EXECUTE_HANDLER) {
  1089. ResponseFlag = OptionOk;
  1090. AeAutoDebug = FALSE;
  1091. }
  1092. }
  1093. if ( !AeAutoDebug ) {
  1094. Status =NtRaiseHardError( STATUS_UNHANDLED_EXCEPTION | 0x10000000,
  1095. 4,
  1096. 0,
  1097. Parameters,
  1098. BasepAlreadyHadHardError ? OptionOk : ResponseFlag,
  1099. &Response
  1100. );
  1101. }
  1102. else {
  1103. Status = STATUS_SUCCESS;
  1104. Response = ResponseCancel;
  1105. }
  1106. //
  1107. // Internally, send OkCancel. If we get back Ok then die.
  1108. // If we get back Cancel, then enter the debugger
  1109. //
  1110. if ( NT_SUCCESS(Status) && Response == ResponseCancel && BasepAlreadyHadHardError == FALSE) {
  1111. if ( !BaseRunningInServerProcess ) {
  1112. BOOL b;
  1113. STARTUPINFO StartupInfo;
  1114. PROCESS_INFORMATION ProcessInformation;
  1115. CHAR CmdLine[256];
  1116. NTSTATUS Status;
  1117. HANDLE EventHandle;
  1118. SECURITY_ATTRIBUTES sa;
  1119. BasepAlreadyHadHardError = TRUE;
  1120. sa.nLength = sizeof(sa);
  1121. sa.lpSecurityDescriptor = NULL;
  1122. sa.bInheritHandle = TRUE;
  1123. EventHandle = CreateEvent(&sa,TRUE,FALSE,NULL);
  1124. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  1125. sprintf(CmdLine,AeDebuggerCmdLine,GetCurrentProcessId(),EventHandle);
  1126. StartupInfo.cb = sizeof(StartupInfo);
  1127. StartupInfo.lpDesktop = "Winsta0\\Default";
  1128. CsrIdentifyAlertableThread();
  1129. b = CreateProcess(
  1130. NULL,
  1131. CmdLine,
  1132. NULL,
  1133. NULL,
  1134. TRUE,
  1135. 0,
  1136. NULL,
  1137. NULL,
  1138. &StartupInfo,
  1139. &ProcessInformation
  1140. );
  1141. if ( b && EventHandle) {
  1142. //
  1143. // Do an alertable wait on the event
  1144. //
  1145. Status = NtWaitForSingleObject(
  1146. EventHandle,
  1147. TRUE,
  1148. NULL
  1149. );
  1150. return EXCEPTION_CONTINUE_SEARCH;
  1151. }
  1152. }
  1153. }
  1154. #if DBG
  1155. if (!NT_SUCCESS( Status )) {
  1156. DbgPrint( "BASEDLL: Unhandled exception: %lx IP: %x\n",
  1157. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1158. ExceptionInfo->ExceptionRecord->ExceptionAddress
  1159. );
  1160. }
  1161. #endif
  1162. if ( BasepAlreadyHadHardError ) {
  1163. NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode);
  1164. }
  1165. return EXCEPTION_EXECUTE_HANDLER;
  1166. }
  1167. DWORD
  1168. APIENTRY
  1169. TlsAlloc(
  1170. VOID
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. A TLS index may be allocated using TlsAlloc. Win32 garuntees a
  1175. minimum number of TLS indexes are available in each process. The
  1176. constant TLS_MINIMUM_AVAILABLE defines the minimum number of
  1177. available indexes. This minimum is at least 64 for all Win32
  1178. systems.
  1179. Arguments:
  1180. None.
  1181. Return Value:
  1182. Not-0xffffffff - Returns a TLS index that may be used in a
  1183. subsequent call to TlsFree, TlsSetValue, or TlsGetValue. The
  1184. storage associated with the index is initialized to NULL.
  1185. 0xffffffff - The operation failed. Extended error status is available
  1186. using GetLastError.
  1187. --*/
  1188. {
  1189. PPEB Peb;
  1190. DWORD Index;
  1191. Peb = NtCurrentPeb();
  1192. RtlAcquirePebLock();
  1193. try {
  1194. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsBitmap,1,0);
  1195. if ( Index == 0xffffffff ) {
  1196. BaseSetLastNTError(STATUS_NO_MEMORY);
  1197. }
  1198. else {
  1199. NtCurrentTeb()->TlsSlots[Index] = NULL;
  1200. }
  1201. }
  1202. finally {
  1203. RtlReleasePebLock();
  1204. }
  1205. return Index;
  1206. }
  1207. LPVOID
  1208. APIENTRY
  1209. TlsGetValue(
  1210. DWORD dwTlsIndex
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. This function is used to retrive the value in the TLS storage
  1215. associated with the specified index.
  1216. If the index is valid this function clears the value returned by
  1217. GetLastError(), and returns the value stored in the TLS slot
  1218. associated with the specified index. Otherwise a value of NULL is
  1219. returned with GetLastError updated appropriately.
  1220. It is expected, that DLLs will use TlsAlloc and TlsGetValue as
  1221. follows:
  1222. - Upon DLL initialization, a TLS index will be allocated using
  1223. TlsAlloc. The DLL will then allocate some dynamic storage and
  1224. store its address in the TLS slot using TlsSetValue. This
  1225. completes the per thread initialization for the initial thread
  1226. of the process. The TLS index is stored in instance data for
  1227. the DLL.
  1228. - Each time a new thread attaches to the DLL, the DLL will
  1229. allocate some dynamic storage and store its address in the TLS
  1230. slot using TlsSetValue. This completes the per thread
  1231. initialization for the new thread.
  1232. - Each time an initialized thread makes a DLL call requiring the
  1233. TLS, the DLL will call TlsGetValue to get the TLS data for the
  1234. thread.
  1235. Arguments:
  1236. dwTlsIndex - Supplies a TLS index allocated using TlsAlloc. The
  1237. index specifies which TLS slot is to be located. Translating a
  1238. TlsIndex does not prevent a TlsFree call from proceding.
  1239. Return Value:
  1240. NON-NULL - The function was successful. The value is the data stored
  1241. in the TLS slot associated with the specified index.
  1242. NULL - The operation failed, or the value associated with the
  1243. specified index was NULL. Extended error status is available
  1244. using GetLastError. If this returns non-zero, the index was
  1245. invalid.
  1246. --*/
  1247. {
  1248. PTEB Teb;
  1249. LPVOID *Slot;
  1250. DWORD BitMapSize;
  1251. Teb = NtCurrentTeb();
  1252. BitMapSize = ((PRTL_BITMAP)(Teb->ProcessEnvironmentBlock->TlsBitmap))->SizeOfBitMap;
  1253. if ( dwTlsIndex >= BitMapSize ) {
  1254. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1255. return NULL;
  1256. }
  1257. Slot = &Teb->TlsSlots[dwTlsIndex];
  1258. Teb->LastErrorValue = 0;
  1259. return *Slot;
  1260. }
  1261. BOOL
  1262. APIENTRY
  1263. TlsSetValue(
  1264. DWORD dwTlsIndex,
  1265. LPVOID lpTlsValue
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. This function is used to store a value in the TLS storage associated
  1270. with the specified index.
  1271. If the index is valid this function stores the value and returns
  1272. TRUE. Otherwise a value of FALSE is returned.
  1273. It is expected, that DLLs will use TlsAlloc and TlsSetValue as
  1274. follows:
  1275. - Upon DLL initialization, a TLS index will be allocated using
  1276. TlsAlloc. The DLL will then allocate some dynamic storage and
  1277. store its address in the TLS slot using TlsSetValue. This
  1278. completes the per thread initialization for the initial thread
  1279. of the process. The TLS index is stored in instance data for
  1280. the DLL.
  1281. - Each time a new thread attaches to the DLL, the DLL will
  1282. allocate some dynamic storage and store its address in the TLS
  1283. slot using TlsSetValue. This completes the per thread
  1284. initialization for the new thread.
  1285. - Each time an initialized thread makes a DLL call requiring the
  1286. TLS, the DLL will call TlsGetValue to get the TLS data for the
  1287. thread.
  1288. Arguments:
  1289. dwTlsIndex - Supplies a TLS index allocated using TlsAlloc. The
  1290. index specifies which TLS slot is to be located. Translating a
  1291. TlsIndex does not prevent a TlsFree call from proceding.
  1292. lpTlsValue - Supplies the value to be stored in the TLS Slot.
  1293. Return Value:
  1294. TRUE - The function was successful. The value lpTlsValue was
  1295. stored.
  1296. FALSE - The operation failed. Extended error status is available
  1297. using GetLastError.
  1298. --*/
  1299. {
  1300. PTEB Teb;
  1301. DWORD BitMapSize;
  1302. Teb = NtCurrentTeb();
  1303. BitMapSize = ((PRTL_BITMAP)(Teb->ProcessEnvironmentBlock->TlsBitmap))->SizeOfBitMap;
  1304. if ( dwTlsIndex >= BitMapSize ) {
  1305. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1306. return FALSE;
  1307. }
  1308. Teb->TlsSlots[dwTlsIndex] = lpTlsValue;
  1309. return TRUE;
  1310. }
  1311. BOOL
  1312. APIENTRY
  1313. TlsFree(
  1314. DWORD dwTlsIndex
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. A valid TLS index may be free'd using TlsFree.
  1319. Arguments:
  1320. dwTlsIndex - Supplies a TLS index allocated using TlsAlloc. If the
  1321. index is a valid index, it is released by this call and is made
  1322. available for reuse. DLLs should be carefull to release any
  1323. per-thread data pointed to by all of their threads TLS slots
  1324. before calling this function. It is expected that DLLs will
  1325. only call this function (if at ALL) during their process detach
  1326. routine.
  1327. Return Value:
  1328. TRUE - The operation was successful. Calling TlsTranslateIndex with
  1329. this index will fail. TlsAlloc is free to reallocate this
  1330. index.
  1331. FALSE - The operation failed. Extended error status is available
  1332. using GetLastError.
  1333. --*/
  1334. {
  1335. PPEB Peb;
  1336. BOOLEAN ValidIndex;
  1337. PRTL_BITMAP TlsBitmap;
  1338. NTSTATUS Status;
  1339. Peb = NtCurrentPeb();
  1340. TlsBitmap = (PRTL_BITMAP)Peb->TlsBitmap;
  1341. RtlAcquirePebLock();
  1342. try {
  1343. if ( dwTlsIndex >= TlsBitmap->SizeOfBitMap ) {
  1344. ValidIndex = FALSE;
  1345. }
  1346. else {
  1347. ValidIndex = RtlAreBitsSet(TlsBitmap,dwTlsIndex,1);
  1348. }
  1349. if ( ValidIndex ) {
  1350. Status = NtSetInformationThread(
  1351. NtCurrentThread(),
  1352. ThreadZeroTlsCell,
  1353. &dwTlsIndex,
  1354. sizeof(dwTlsIndex)
  1355. );
  1356. if ( !NT_SUCCESS(Status) ) {
  1357. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1358. return FALSE;
  1359. }
  1360. RtlClearBits(TlsBitmap,dwTlsIndex,1);
  1361. }
  1362. else {
  1363. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1364. }
  1365. }
  1366. finally {
  1367. RtlReleasePebLock();
  1368. }
  1369. return ValidIndex;
  1370. }
  1371. BOOL
  1372. WINAPI
  1373. GetThreadTimes(
  1374. HANDLE hThread,
  1375. LPFILETIME lpCreationTime,
  1376. LPFILETIME lpExitTime,
  1377. LPFILETIME lpKernelTime,
  1378. LPFILETIME lpUserTime
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. This function is used to return various timing information about the
  1383. thread specified by hThread.
  1384. All times are in units of 100ns increments. For lpCreationTime and lpExitTime,
  1385. the times are in terms of the SYSTEM time or GMT time.
  1386. Arguments:
  1387. hThread - Supplies an open handle to the specified thread. The
  1388. handle must have been created with THREAD_QUERY_INFORMATION
  1389. access.
  1390. lpCreationTime - Returns a creation time of the thread.
  1391. lpExitTime - Returns the exit time of a thread. If the thread has
  1392. not exited, this value is not defined.
  1393. lpKernelTime - Returns the amount of time that this thread has
  1394. executed in kernel-mode.
  1395. lpUserTime - Returns the amount of time that this thread has
  1396. executed in user-mode.
  1397. Return Value:
  1398. TRUE - The API was successful
  1399. FALSE - The operation failed. Extended error status is available
  1400. using GetLastError.
  1401. --*/
  1402. {
  1403. NTSTATUS Status;
  1404. KERNEL_USER_TIMES TimeInfo;
  1405. Status = NtQueryInformationThread(
  1406. hThread,
  1407. ThreadTimes,
  1408. (PVOID)&TimeInfo,
  1409. sizeof(TimeInfo),
  1410. NULL
  1411. );
  1412. if ( !NT_SUCCESS(Status) ) {
  1413. BaseSetLastNTError(Status);
  1414. return FALSE;
  1415. }
  1416. *lpCreationTime = *(LPFILETIME)&TimeInfo.CreateTime;
  1417. *lpExitTime = *(LPFILETIME)&TimeInfo.ExitTime;
  1418. *lpKernelTime = *(LPFILETIME)&TimeInfo.KernelTime;
  1419. *lpUserTime = *(LPFILETIME)&TimeInfo.UserTime;
  1420. return TRUE;
  1421. }
  1422. DWORD
  1423. WINAPI
  1424. SetThreadAffinityMask(
  1425. HANDLE hThread,
  1426. DWORD dwThreadAffinityMask
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This function is used to set the specified thread's processor
  1431. affinity mask. The thread affinity mask is a bit vector where each
  1432. bit represents the processors that the thread is allowed to run on.
  1433. The affinity mask MUST be a proper subset of the containing process'
  1434. process level affinity mask.
  1435. Arguments:
  1436. hThread - Supplies a handle to the thread whose priority is to be
  1437. set. The handle must have been created with
  1438. THREAD_SET_INFORMATION access.
  1439. dwThreadAffinityMask - Supplies the affinity mask to be used for the
  1440. specified thread.
  1441. Return Value:
  1442. non-0 - The API was successful. The return value is the previous
  1443. affinity mask for the thread.
  1444. 0 - The operation failed. Extended error status is available
  1445. using GetLastError.
  1446. --*/
  1447. {
  1448. THREAD_BASIC_INFORMATION BasicInformation;
  1449. NTSTATUS Status;
  1450. DWORD rv;
  1451. KAFFINITY LocalThreadAffinityMask;
  1452. Status = NtQueryInformationThread(
  1453. hThread,
  1454. ThreadBasicInformation,
  1455. &BasicInformation,
  1456. sizeof(BasicInformation),
  1457. NULL
  1458. );
  1459. if ( !NT_SUCCESS(Status) ) {
  1460. rv = 0;
  1461. }
  1462. else {
  1463. LocalThreadAffinityMask = (KAFFINITY)dwThreadAffinityMask;
  1464. Status = NtSetInformationThread(
  1465. hThread,
  1466. ThreadAffinityMask,
  1467. &LocalThreadAffinityMask,
  1468. sizeof(LocalThreadAffinityMask)
  1469. );
  1470. if ( !NT_SUCCESS(Status) ) {
  1471. rv = 0;
  1472. }
  1473. else {
  1474. rv = (DWORD)BasicInformation.AffinityMask;
  1475. }
  1476. }
  1477. if ( !rv ) {
  1478. BaseSetLastNTError(Status);
  1479. }
  1480. return rv;
  1481. }
  1482. VOID
  1483. BaseDispatchAPC(
  1484. LPVOID lpApcArgument1,
  1485. LPVOID lpApcArgument2,
  1486. LPVOID lpApcArgument3
  1487. )
  1488. {
  1489. PAPCFUNC pfnAPC;
  1490. DWORD dwData;
  1491. pfnAPC = (PAPCFUNC)lpApcArgument1;
  1492. dwData = (DWORD)lpApcArgument2;
  1493. (pfnAPC)(dwData);
  1494. }
  1495. WINBASEAPI
  1496. DWORD
  1497. WINAPI
  1498. QueueUserAPC(
  1499. PAPCFUNC pfnAPC,
  1500. HANDLE hThread,
  1501. DWORD dwData
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. This function is used to queue a user-mode APC to the specified thread. The APC
  1506. will fire when the specified thread does an alertable wait.
  1507. Arguments:
  1508. pfnAPC - Supplies the address of the APC routine to execute when the
  1509. APC fires.
  1510. hHandle - Supplies a handle to a thread object. The caller
  1511. must have THREAD_SET_CONTEXT access to the thread.
  1512. dwData - Supplies a DWORD passed to the APC
  1513. Return Value:
  1514. TRUE - The operations was successful
  1515. FALSE - The operation failed. GetLastError() is not defined.
  1516. --*/
  1517. {
  1518. NTSTATUS Status;
  1519. Status = NtQueueApcThread(
  1520. hThread,
  1521. (PPS_APC_ROUTINE)BaseDispatchAPC,
  1522. (PVOID)pfnAPC,
  1523. (PVOID)dwData,
  1524. NULL
  1525. );
  1526. if ( !NT_SUCCESS(Status) ) {
  1527. return 0;
  1528. }
  1529. return 1;
  1530. }
  1531. DWORD
  1532. WINAPI
  1533. SetThreadIdealProcessor(
  1534. HANDLE hThread,
  1535. DWORD dwIdealProcessor
  1536. )
  1537. {
  1538. NTSTATUS Status;
  1539. ULONG rv;
  1540. Status = NtSetInformationThread(
  1541. NtCurrentThread(),
  1542. ThreadIdealProcessor,
  1543. &dwIdealProcessor,
  1544. sizeof(dwIdealProcessor)
  1545. );
  1546. if ( !NT_SUCCESS(Status) ) {
  1547. rv = (DWORD)0xFFFFFFFF;
  1548. BaseSetLastNTError(Status);
  1549. }
  1550. else {
  1551. rv = (ULONG)Status;
  1552. }
  1553. return rv;
  1554. }
  1555. WINBASEAPI
  1556. LPVOID
  1557. WINAPI
  1558. CreateFiber(
  1559. DWORD dwStackSize,
  1560. LPFIBER_START_ROUTINE lpStartAddress,
  1561. LPVOID lpParameter
  1562. )
  1563. {
  1564. NTSTATUS Status;
  1565. PFIBER Fiber;
  1566. INITIAL_TEB InitialTeb;
  1567. Fiber = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), sizeof(*Fiber) );
  1568. if ( !Fiber ) {
  1569. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1570. return Fiber;
  1571. }
  1572. Status = BaseCreateStack(
  1573. NtCurrentProcess(),
  1574. dwStackSize,
  1575. 0L,
  1576. &InitialTeb
  1577. );
  1578. if ( !NT_SUCCESS(Status) ) {
  1579. BaseSetLastNTError(Status);
  1580. RtlFreeHeap(RtlProcessHeap(), 0, Fiber);
  1581. return NULL;
  1582. }
  1583. Fiber->FiberData = lpParameter;
  1584. Fiber->StackBase = InitialTeb.StackBase;
  1585. Fiber->StackLimit = InitialTeb.StackLimit;
  1586. Fiber->DeallocationStack = InitialTeb.StackAllocationBase;
  1587. Fiber->ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)-1;
  1588. //
  1589. // Create an initial context for the new fiber.
  1590. //
  1591. BaseInitializeContext(
  1592. &Fiber->FiberContext,
  1593. lpParameter,
  1594. (PVOID)lpStartAddress,
  1595. InitialTeb.StackBase,
  1596. BaseContextTypeFiber
  1597. );
  1598. return Fiber;
  1599. }
  1600. WINBASEAPI
  1601. VOID
  1602. WINAPI
  1603. DeleteFiber(
  1604. LPVOID lpFiber
  1605. )
  1606. {
  1607. DWORD dwStackSize;
  1608. //
  1609. // If the current fiber makes this call, then it's just a thread exit
  1610. //
  1611. if ( NtCurrentTeb()->NtTib.FiberData == lpFiber ) {
  1612. ExitThread(1);
  1613. }
  1614. dwStackSize = 0;
  1615. NtFreeVirtualMemory( NtCurrentProcess(),
  1616. &((PFIBER)lpFiber)->DeallocationStack,
  1617. &dwStackSize,
  1618. MEM_RELEASE
  1619. );
  1620. RtlFreeHeap(RtlProcessHeap(),0,lpFiber);
  1621. }
  1622. WINBASEAPI
  1623. LPVOID
  1624. WINAPI
  1625. ConvertThreadToFiber(
  1626. LPVOID lpParameter
  1627. )
  1628. {
  1629. NTSTATUS Status;
  1630. PFIBER Fiber;
  1631. PTEB Teb;
  1632. Fiber = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), sizeof(*Fiber) );
  1633. if ( !Fiber ) {
  1634. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1635. return Fiber;
  1636. }
  1637. Teb = NtCurrentTeb();
  1638. Fiber->FiberData = lpParameter;
  1639. Fiber->StackBase = Teb->NtTib.StackBase;
  1640. Fiber->StackLimit = Teb->NtTib.StackLimit;
  1641. Fiber->DeallocationStack = Teb->DeallocationStack;
  1642. Fiber->ExceptionList = Teb->NtTib.ExceptionList;
  1643. Teb->NtTib.FiberData = Fiber;
  1644. return Fiber;
  1645. }
  1646. BOOL
  1647. WINAPI
  1648. SwitchToThread(
  1649. VOID
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. This function causes a yield from the running thread to any other
  1654. thread that is ready and can run on the current processor. The
  1655. yield will be effective for up to one quantum and then the yielding
  1656. thread will be scheduled again according to its priority and
  1657. whatever other threads may also be avaliable to run. The thread
  1658. that yields will not bounce to another processor even it another
  1659. processor is idle or running a lower priority thread.
  1660. Arguments:
  1661. None
  1662. Return Value:
  1663. TRUE - Calling this function caused a switch to another thread to occur
  1664. FALSE - There were no other ready threads, so no context switch occured
  1665. --*/
  1666. {
  1667. if ( NtYieldExecution() == STATUS_NO_YIELD_PERFORMED ) {
  1668. return FALSE;
  1669. }
  1670. else {
  1671. return TRUE;
  1672. }
  1673. }