2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Rtl user thread functions
5 * FILE: lib/rtl/thread.c
7 * Alex Ionescu (alex@relsoft.net)
12 /* INCLUDES *****************************************************************/
19 /* PRIVATE FUNCTIONS *******************************************************/
23 RtlpCreateUserStack(IN HANDLE hProcess
,
24 IN SIZE_T StackReserve OPTIONAL
,
25 IN SIZE_T StackCommit OPTIONAL
,
26 IN ULONG StackZeroBits OPTIONAL
,
27 OUT PINITIAL_TEB InitialTeb
)
30 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
31 PIMAGE_NT_HEADERS Headers
;
33 BOOLEAN UseGuard
= FALSE
;
34 ULONG Dummy
, GuardPageSize
;
36 /* Get some memory information */
37 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
39 sizeof(SYSTEM_BASIC_INFORMATION
),
41 if (!NT_SUCCESS(Status
)) return Status
;
43 /* Use the Image Settings if we are dealing with the current Process */
44 if (hProcess
== NtCurrentProcess())
46 /* Get the Image Headers */
47 Headers
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
49 /* If we didn't get the parameters, find them ourselves */
50 if (!StackReserve
) StackReserve
= Headers
->OptionalHeader
.
52 if (!StackCommit
) StackCommit
= Headers
->OptionalHeader
.
57 /* Use the System Settings if needed */
58 if (!StackReserve
) StackReserve
= SystemBasicInfo
.AllocationGranularity
;
59 if (!StackCommit
) StackCommit
= SystemBasicInfo
.PageSize
;
62 /* Align everything to Page Size */
63 StackReserve
= ROUND_UP(StackReserve
, SystemBasicInfo
.AllocationGranularity
);
64 StackCommit
= ROUND_UP(StackCommit
, SystemBasicInfo
.PageSize
);
66 // FIXME: Remove once Guard Page support is here
68 StackCommit
= StackReserve
;
71 /* Reserve memory for the stack */
72 Status
= ZwAllocateVirtualMemory(hProcess
,
78 if (!NT_SUCCESS(Status
)) return Status
;
80 /* Now set up some basic Initial TEB Parameters */
81 InitialTeb
->PreviousStackBase
= NULL
;
82 InitialTeb
->PreviousStackLimit
= NULL
;
83 InitialTeb
->AllocatedStackBase
= (PVOID
)Stack
;
84 InitialTeb
->StackBase
= (PVOID
)(Stack
+ StackReserve
);
86 /* Update the Stack Position */
87 Stack
+= StackReserve
- StackCommit
;
89 /* Check if we will need a guard page */
90 if (StackReserve
> StackCommit
)
92 /* Remove a page to set as guard page */
93 Stack
-= SystemBasicInfo
.PageSize
;
94 StackCommit
+= SystemBasicInfo
.PageSize
;
98 /* Allocate memory for the stack */
99 Status
= ZwAllocateVirtualMemory(hProcess
,
105 if (!NT_SUCCESS(Status
)) return Status
;
107 /* Now set the current Stack Limit */
108 InitialTeb
->StackLimit
= (PVOID
)Stack
;
110 /* Create a guard page */
113 /* Attempt maximum space possible */
114 GuardPageSize
= SystemBasicInfo
.PageSize
;
115 Status
= ZwProtectVirtualMemory(hProcess
,
118 PAGE_GUARD
| PAGE_READWRITE
,
120 if (!NT_SUCCESS(Status
)) return Status
;
122 /* Update the Stack Limit keeping in mind the Guard Page */
123 InitialTeb
->StackLimit
= (PVOID
)((ULONG_PTR
)InitialTeb
->StackLimit
-
128 return STATUS_SUCCESS
;
133 RtlpFreeUserStack(IN HANDLE Process
,
134 IN PINITIAL_TEB InitialTeb
)
140 Status
= ZwFreeVirtualMemory(Process
,
141 &InitialTeb
->AllocatedStackBase
,
145 /* Clear the initial TEB */
146 RtlZeroMemory(InitialTeb
, sizeof(INITIAL_TEB
));
150 /* FUNCTIONS ***************************************************************/
157 RtlCreateUserThread(IN HANDLE ProcessHandle
,
158 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL
,
159 IN BOOLEAN CreateSuspended
,
160 IN ULONG StackZeroBits OPTIONAL
,
161 IN SIZE_T StackReserve OPTIONAL
,
162 IN SIZE_T StackCommit OPTIONAL
,
163 IN PTHREAD_START_ROUTINE StartAddress
,
164 IN PVOID Parameter OPTIONAL
,
165 OUT PHANDLE ThreadHandle OPTIONAL
,
166 OUT PCLIENT_ID ClientId OPTIONAL
)
171 INITIAL_TEB InitialTeb
;
172 OBJECT_ATTRIBUTES ObjectAttributes
;
175 /* First, we'll create the Stack */
176 Status
= RtlpCreateUserStack(ProcessHandle
,
181 if (!NT_SUCCESS(Status
)) return Status
;
183 /* Next, we'll set up the Initial Context */
184 RtlInitializeContext(ProcessHandle
,
188 InitialTeb
.StackBase
);
190 /* We are now ready to create the Kernel Thread Object */
191 InitializeObjectAttributes(&ObjectAttributes
,
196 Status
= ZwCreateThread(&Handle
,
204 if (!NT_SUCCESS(Status
))
207 RtlpFreeUserStack(ProcessHandle
, &InitialTeb
);
211 /* Return thread data */
213 *ThreadHandle
= Handle
;
216 if (ClientId
) *ClientId
= ThreadCid
;
219 /* Return success or the previous failure */
228 RtlExitUserThread(NTSTATUS Status
)
230 /* Call the Loader and tell him to notify the DLLs */
234 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
235 NtTerminateThread(NtCurrentThread(), Status
);
243 RtlFreeUserThreadStack(HANDLE ProcessHandle
,
247 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
248 SIZE_T Dummy
, Size
= 0;
251 /* Query the Basic Info */
252 Status
= NtQueryInformationThread(ThreadHandle
,
253 ThreadBasicInformation
,
255 sizeof(THREAD_BASIC_INFORMATION
),
257 if (!NT_SUCCESS(Status
) || !ThreadBasicInfo
.TebBaseAddress
) return;
259 /* Get the deallocation stack */
260 Status
= NtReadVirtualMemory(ProcessHandle
,
261 &((PTEB
)ThreadBasicInfo
.TebBaseAddress
)->
266 if (!NT_SUCCESS(Status
) || !StackLocation
) return;
269 NtFreeVirtualMemory(ProcessHandle
, &StackLocation
, &Size
, MEM_RELEASE
);
277 return NtCurrentTeb();