Implemented dll detach on thread termination
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /* $Id: thread.c,v 1.19 2000/09/05 13:52:44 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/thread/thread.c
6 * PURPOSE: Thread functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Tls functions are modified from WINE
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <windows.h>
17 #include <kernel32/thread.h>
18 #include <ntdll/ldr.h>
19 #include <string.h>
20 #include <napi/i386/segment.h>
21
22 #define NDEBUG
23 #include <kernel32/kernel32.h>
24 #include <kernel32/error.h>
25
26
27 /* FUNCTIONS *****************************************************************/
28
29 static VOID STDCALL
30 ThreadStartup (LPTHREAD_START_ROUTINE lpStartAddress,
31 LPVOID lpParameter)
32 {
33 UINT uExitCode;
34
35 uExitCode = (lpStartAddress)(lpParameter);
36
37 NtTerminateThread(NtCurrentThread(),
38 uExitCode);
39 }
40
41
42 HANDLE STDCALL CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
43 DWORD dwStackSize,
44 LPTHREAD_START_ROUTINE lpStartAddress,
45 LPVOID lpParameter,
46 DWORD dwCreationFlags,
47 LPDWORD lpThreadId)
48 {
49 return(CreateRemoteThread(NtCurrentProcess(),
50 lpThreadAttributes,
51 dwStackSize,
52 lpStartAddress,
53 lpParameter,
54 dwCreationFlags,
55 lpThreadId));
56 }
57
58 HANDLE STDCALL CreateRemoteThread(HANDLE hProcess,
59 LPSECURITY_ATTRIBUTES lpThreadAttributes,
60 DWORD dwStackSize,
61 LPTHREAD_START_ROUTINE lpStartAddress,
62 LPVOID lpParameter,
63 DWORD dwCreationFlags,
64 LPDWORD lpThreadId)
65 {
66 HANDLE ThreadHandle;
67 OBJECT_ATTRIBUTES ObjectAttributes;
68 CLIENT_ID ClientId;
69 CONTEXT ThreadContext;
70 INITIAL_TEB InitialTeb;
71 BOOLEAN CreateSuspended = FALSE;
72 PVOID BaseAddress;
73 DWORD StackSize;
74 NTSTATUS Status;
75
76 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
77 ObjectAttributes.RootDirectory = NULL;
78 ObjectAttributes.ObjectName = NULL;
79 ObjectAttributes.Attributes = 0;
80 if (lpThreadAttributes != NULL)
81 {
82 if (lpThreadAttributes->bInheritHandle)
83 ObjectAttributes.Attributes = OBJ_INHERIT;
84 ObjectAttributes.SecurityDescriptor =
85 lpThreadAttributes->lpSecurityDescriptor;
86 }
87 ObjectAttributes.SecurityQualityOfService = NULL;
88
89 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
90 CreateSuspended = TRUE;
91 else
92 CreateSuspended = FALSE;
93
94 StackSize = (dwStackSize == 0) ? 4096 : dwStackSize;
95
96 BaseAddress = 0;
97
98 Status = NtAllocateVirtualMemory(hProcess,
99 &BaseAddress,
100 0,
101 (PULONG)&StackSize,
102 MEM_COMMIT,
103 PAGE_READWRITE);
104 if (!NT_SUCCESS(Status))
105 {
106 DPRINT("Could not allocate stack space!\n");
107 return NULL;
108 }
109
110
111 DPRINT("Stack base address: %p\n", BaseAddress);
112
113 memset(&ThreadContext,0,sizeof(CONTEXT));
114 ThreadContext.Eip = (LONG)ThreadStartup;
115 ThreadContext.SegGs = USER_DS;
116 ThreadContext.SegFs = USER_DS;
117 ThreadContext.SegEs = USER_DS;
118 ThreadContext.SegDs = USER_DS;
119 ThreadContext.SegCs = USER_CS;
120 ThreadContext.SegSs = USER_DS;
121 ThreadContext.Esp = (ULONG)(BaseAddress + StackSize - 12);
122 ThreadContext.EFlags = (1<<1) + (1<<9);
123
124 /* initialize call stack */
125 *((PULONG)(BaseAddress + StackSize - 4)) = (ULONG)lpParameter;
126 *((PULONG)(BaseAddress + StackSize - 8)) = (ULONG)lpStartAddress;
127 *((PULONG)(BaseAddress + StackSize - 12)) = 0xdeadbeef;
128
129 DPRINT("Esp: %p\n", ThreadContext.Esp);
130 DPRINT("Eip: %p\n", ThreadContext.Eip);
131
132 Status = NtCreateThread(&ThreadHandle,
133 THREAD_ALL_ACCESS,
134 &ObjectAttributes,
135 hProcess,
136 &ClientId,
137 &ThreadContext,
138 &InitialTeb,
139 CreateSuspended);
140
141 if (!NT_SUCCESS(Status))
142 {
143 DPRINT("NtCreateThread() failed!\n");
144 return NULL;
145 }
146
147 if ( lpThreadId != NULL )
148 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
149
150 return ThreadHandle;
151 }
152
153 NT_TEB *GetTeb(VOID)
154 {
155 return NtCurrentTeb();
156 }
157
158 WINBOOL STDCALL SwitchToThread(VOID)
159 {
160 NTSTATUS errCode;
161 errCode = NtYieldExecution();
162 return TRUE;
163 }
164
165 DWORD STDCALL GetCurrentThreadId()
166 {
167 return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
168 }
169
170 VOID STDCALL ExitThread(UINT uExitCode)
171 {
172 NTSTATUS errCode;
173 BOOLEAN LastThread;
174 NTSTATUS Status;
175
176 /*
177 * Terminate process if this is the last thread
178 * of the current process
179 */
180 Status = NtQueryInformationThread(NtCurrentThread(),
181 ThreadAmILastThread,
182 &LastThread,
183 sizeof(BOOLEAN),
184 NULL);
185 if (NT_SUCCESS(Status) && LastThread == TRUE)
186 {
187 ExitProcess (uExitCode);
188 }
189
190 /* FIXME: notify csrss of thread termination */
191
192 LdrShutdownThread();
193
194 errCode = NtTerminateThread(NtCurrentThread(),
195 uExitCode);
196 if (!NT_SUCCESS(errCode))
197 {
198 SetLastErrorByStatus(errCode);
199 }
200 }
201
202 WINBOOL STDCALL GetThreadTimes(HANDLE hThread,
203 LPFILETIME lpCreationTime,
204 LPFILETIME lpExitTime,
205 LPFILETIME lpKernelTime,
206 LPFILETIME lpUserTime)
207 {
208 NTSTATUS errCode;
209 KERNEL_USER_TIMES KernelUserTimes;
210 ULONG ReturnLength;
211
212 errCode = NtQueryInformationThread(hThread,
213 ThreadTimes,
214 &KernelUserTimes,
215 sizeof(KERNEL_USER_TIMES),
216 &ReturnLength);
217 if (!NT_SUCCESS(errCode))
218 {
219 SetLastErrorByStatus(errCode);
220 return FALSE;
221 }
222 memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
223 memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
224 memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
225 memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
226 return TRUE;
227 }
228
229
230 WINBOOL STDCALL GetThreadContext(HANDLE hThread,
231 LPCONTEXT lpContext)
232 {
233 NTSTATUS errCode;
234
235 errCode = NtGetContextThread(hThread,
236 lpContext);
237 if (!NT_SUCCESS(errCode))
238 {
239 SetLastErrorByStatus(errCode);
240 return FALSE;
241 }
242 return TRUE;
243 }
244
245 WINBOOL STDCALL SetThreadContext(HANDLE hThread,
246 CONST CONTEXT *lpContext)
247 {
248 NTSTATUS errCode;
249
250 errCode = NtSetContextThread(hThread,
251 (void *)lpContext);
252 if (!NT_SUCCESS(errCode))
253 {
254 SetLastErrorByStatus(errCode);
255 return FALSE;
256 }
257 return TRUE;
258 }
259
260 WINBOOL STDCALL GetExitCodeThread(HANDLE hThread,
261 LPDWORD lpExitCode)
262 {
263 NTSTATUS errCode;
264 THREAD_BASIC_INFORMATION ThreadBasic;
265 ULONG DataWritten;
266
267 errCode = NtQueryInformationThread(hThread,
268 ThreadBasicInformation,
269 &ThreadBasic,
270 sizeof(THREAD_BASIC_INFORMATION),
271 &DataWritten);
272 if (!NT_SUCCESS(errCode))
273 {
274 SetLastErrorByStatus(errCode);
275 return FALSE;
276 }
277 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
278 return TRUE;
279 }
280
281 DWORD STDCALL ResumeThread(HANDLE hThread)
282 {
283 NTSTATUS errCode;
284 ULONG PreviousResumeCount;
285
286 errCode = NtResumeThread(hThread,
287 &PreviousResumeCount);
288 if (!NT_SUCCESS(errCode))
289 {
290 SetLastErrorByStatus(errCode);
291 return -1;
292 }
293 return PreviousResumeCount;
294 }
295
296
297 WINBOOL
298 STDCALL
299 TerminateThread (
300 HANDLE hThread,
301 DWORD dwExitCode
302 )
303 {
304 NTSTATUS errCode;
305
306 errCode = NtTerminateThread(hThread,
307 dwExitCode);
308 if (!NT_SUCCESS(errCode))
309 {
310 SetLastErrorByStatus(errCode);
311 return FALSE;
312 }
313 return TRUE;
314 }
315
316
317 DWORD STDCALL SuspendThread(HANDLE hThread)
318 {
319 NTSTATUS errCode;
320 ULONG PreviousSuspendCount;
321
322 errCode = NtSuspendThread(hThread,
323 &PreviousSuspendCount);
324 if (!NT_SUCCESS(errCode))
325 {
326 SetLastErrorByStatus(errCode);
327 return -1;
328 }
329 return PreviousSuspendCount;
330 }
331
332 DWORD STDCALL SetThreadAffinityMask(HANDLE hThread,
333 DWORD dwThreadAffinityMask)
334 {
335 return 0;
336 }
337
338 WINBOOL STDCALL SetThreadPriority(HANDLE hThread,
339 int nPriority)
340 {
341 NTSTATUS errCode;
342 THREAD_BASIC_INFORMATION ThreadBasic;
343 ULONG DataWritten;
344
345 errCode = NtQueryInformationThread(hThread,
346 ThreadBasicInformation,
347 &ThreadBasic,
348 sizeof(THREAD_BASIC_INFORMATION),
349 &DataWritten);
350 if (!NT_SUCCESS(errCode))
351 {
352 SetLastErrorByStatus(errCode);
353 return FALSE;
354 }
355 ThreadBasic.BasePriority = nPriority;
356 errCode = NtSetInformationThread(hThread,
357 ThreadBasicInformation,
358 &ThreadBasic,
359 sizeof(THREAD_BASIC_INFORMATION));
360 if (!NT_SUCCESS(errCode))
361 {
362 SetLastErrorByStatus(errCode);
363 return FALSE;
364 }
365 return TRUE;
366 }
367
368 int STDCALL GetThreadPriority(HANDLE hThread)
369 {
370 NTSTATUS errCode;
371 THREAD_BASIC_INFORMATION ThreadBasic;
372 ULONG DataWritten;
373
374 errCode = NtQueryInformationThread(hThread,
375 ThreadBasicInformation,
376 &ThreadBasic,
377 sizeof(THREAD_BASIC_INFORMATION),
378 &DataWritten);
379 if (!NT_SUCCESS(errCode))
380 {
381 SetLastErrorByStatus(errCode);
382 return THREAD_PRIORITY_ERROR_RETURN;
383 }
384 return ThreadBasic.BasePriority;
385 }
386
387 /* EOF */