My biggest commit so far (everything compiles and apparently runs fine):
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /* $Id: thread.c,v 1.37 2003/04/26 23:13:28 hyperion 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 <k32.h>
16
17 #define NDEBUG
18 #include <kernel32/kernel32.h>
19
20 //static VOID ThreadAttachDlls (VOID);
21
22 /* FUNCTIONS *****************************************************************/
23
24 /* FIXME: please put this in some header */
25 extern NTSTATUS CDECL RtlCreateUserThreadVa
26 (
27 HANDLE ProcessHandle,
28 POBJECT_ATTRIBUTES ObjectAttributes,
29 BOOLEAN CreateSuspended,
30 LONG StackZeroBits,
31 PULONG StackReserve,
32 PULONG StackCommit,
33 PTHREAD_START_ROUTINE StartAddress,
34 PHANDLE ThreadHandle,
35 PCLIENT_ID ClientId,
36 ULONG ParameterCount,
37 ...
38 );
39
40 static EXCEPTION_DISPOSITION __cdecl
41 _except_handler(EXCEPTION_RECORD *ExceptionRecord,
42 void * EstablisherFrame,
43 CONTEXT *ContextRecord,
44 void * DispatcherContext)
45 {
46 ExitThread(0);
47
48 /* We should not get to here */
49 return(ExceptionContinueSearch);
50 }
51
52
53 static VOID STDCALL
54 ThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
55 LPVOID lpParameter)
56 {
57 UINT uExitCode;
58
59 __try1(_except_handler)
60 {
61 /* FIXME: notify csrss of thread creation ?? */
62 uExitCode = (lpStartAddress)(lpParameter);
63 }
64 __except1
65 {
66 }
67
68 ExitThread(uExitCode);
69 }
70
71
72 HANDLE STDCALL CreateThread
73 (
74 LPSECURITY_ATTRIBUTES lpThreadAttributes,
75 DWORD dwStackSize,
76 LPTHREAD_START_ROUTINE lpStartAddress,
77 LPVOID lpParameter,
78 DWORD dwCreationFlags,
79 LPDWORD lpThreadId
80 )
81 {
82 return CreateRemoteThread
83 (
84 NtCurrentProcess(),
85 lpThreadAttributes,
86 dwStackSize,
87 lpStartAddress,
88 lpParameter,
89 dwCreationFlags,
90 lpThreadId
91 );
92 }
93
94
95 HANDLE STDCALL CreateRemoteThread
96 (
97 HANDLE hProcess,
98 LPSECURITY_ATTRIBUTES lpThreadAttributes,
99 DWORD dwStackSize,
100 LPTHREAD_START_ROUTINE lpStartAddress,
101 LPVOID lpParameter,
102 DWORD dwCreationFlags,
103 LPDWORD lpThreadId
104 )
105 {
106 PSECURITY_DESCRIPTOR pSD = NULL;
107 HANDLE hThread;
108 CLIENT_ID cidClientId;
109 NTSTATUS nErrCode;
110 ULONG_PTR nStackReserve;
111 ULONG_PTR nStackCommit;
112 OBJECT_ATTRIBUTES oaThreadAttribs;
113 PIMAGE_NT_HEADERS pinhHeader =
114 RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
115
116 /* FIXME: do more checks - e.g. the image may not have an optional header */
117 if(pinhHeader == NULL)
118 {
119 nStackReserve = 0x100000;
120 nStackCommit = PAGE_SIZE;
121 }
122 else
123 {
124 nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve;
125 nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit;
126 }
127
128 /* FIXME: this should be defined in winbase.h */
129 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
130 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
131 #endif
132
133 /* use defaults */
134 if(dwStackSize == 0);
135 /* dwStackSize specifies the size to reserve */
136 else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
137 nStackReserve = dwStackSize;
138 /* dwStackSize specifies the size to commit */
139 else
140 nStackCommit = dwStackSize;
141
142 /* fix the stack reserve size */
143 if(nStackCommit > nStackReserve)
144 nStackReserve = ROUNDUP(nStackCommit, 0x100000);
145
146 /* initialize the attributes for the thread object */
147 InitializeObjectAttributes
148 (
149 &oaThreadAttribs,
150 NULL,
151 0,
152 NULL,
153 NULL
154 );
155
156 if(lpThreadAttributes)
157 {
158 /* make the handle inheritable */
159 if(lpThreadAttributes->bInheritHandle)
160 oaThreadAttribs.Attributes |= OBJ_INHERIT;
161
162 /* user-defined security descriptor */
163 oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor;
164 }
165
166 /* create the thread */
167 nErrCode = RtlCreateUserThreadVa
168 (
169 hProcess,
170 &oaThreadAttribs,
171 dwCreationFlags & CREATE_SUSPENDED,
172 0,
173 &nStackReserve,
174 &nStackCommit,
175 (PTHREAD_START_ROUTINE)ThreadStartup,
176 &hThread,
177 &cidClientId,
178 2,
179 lpStartAddress,
180 lpParameter
181 );
182
183 /* failure */
184 if(!NT_SUCCESS(nErrCode))
185 {
186 SetLastErrorByStatus(nErrCode);
187 return NULL;
188 }
189
190 /* success */
191 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
192 return hThread;
193 }
194
195 PTEB
196 GetTeb(VOID)
197 {
198 return(NtCurrentTeb());
199 }
200
201
202 WINBOOL STDCALL
203 SwitchToThread(VOID)
204 {
205 NTSTATUS errCode;
206 errCode = NtYieldExecution();
207 return TRUE;
208 }
209
210
211 DWORD STDCALL
212 GetCurrentThreadId(VOID)
213 {
214 return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
215 }
216
217
218 VOID STDCALL
219 ExitThread(DWORD uExitCode)
220 {
221 BOOLEAN LastThread;
222 NTSTATUS Status;
223
224 /*
225 * Terminate process if this is the last thread
226 * of the current process
227 */
228 Status = NtQueryInformationThread(NtCurrentThread(),
229 ThreadAmILastThread,
230 &LastThread,
231 sizeof(BOOLEAN),
232 NULL);
233 if (NT_SUCCESS(Status) && LastThread == TRUE)
234 {
235 ExitProcess(uExitCode);
236 }
237
238 /* FIXME: notify csrss of thread termination */
239
240 LdrShutdownThread();
241
242 Status = NtTerminateThread(NtCurrentThread(),
243 uExitCode);
244 if (!NT_SUCCESS(Status))
245 {
246 SetLastErrorByStatus(Status);
247 }
248 }
249
250
251 WINBOOL STDCALL
252 GetThreadTimes(HANDLE hThread,
253 LPFILETIME lpCreationTime,
254 LPFILETIME lpExitTime,
255 LPFILETIME lpKernelTime,
256 LPFILETIME lpUserTime)
257 {
258 KERNEL_USER_TIMES KernelUserTimes;
259 ULONG ReturnLength;
260 NTSTATUS Status;
261
262 Status = NtQueryInformationThread(hThread,
263 ThreadTimes,
264 &KernelUserTimes,
265 sizeof(KERNEL_USER_TIMES),
266 &ReturnLength);
267 if (!NT_SUCCESS(Status))
268 {
269 SetLastErrorByStatus(Status);
270 return(FALSE);
271 }
272
273 memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
274 memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
275 memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
276 memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
277
278 return(TRUE);
279 }
280
281
282 WINBOOL STDCALL
283 GetThreadContext(HANDLE hThread,
284 LPCONTEXT lpContext)
285 {
286 NTSTATUS Status;
287
288 Status = NtGetContextThread(hThread,
289 lpContext);
290 if (!NT_SUCCESS(Status))
291 {
292 SetLastErrorByStatus(Status);
293 return(FALSE);
294 }
295
296 return(TRUE);
297 }
298
299
300 WINBOOL STDCALL
301 SetThreadContext(HANDLE hThread,
302 CONST CONTEXT *lpContext)
303 {
304 NTSTATUS Status;
305
306 Status = NtSetContextThread(hThread,
307 (void *)lpContext);
308 if (!NT_SUCCESS(Status))
309 {
310 SetLastErrorByStatus(Status);
311 return(FALSE);
312 }
313
314 return(TRUE);
315 }
316
317
318 WINBOOL STDCALL
319 GetExitCodeThread(HANDLE hThread,
320 LPDWORD lpExitCode)
321 {
322 THREAD_BASIC_INFORMATION ThreadBasic;
323 ULONG DataWritten;
324 NTSTATUS Status;
325
326 Status = NtQueryInformationThread(hThread,
327 ThreadBasicInformation,
328 &ThreadBasic,
329 sizeof(THREAD_BASIC_INFORMATION),
330 &DataWritten);
331 if (!NT_SUCCESS(Status))
332 {
333 SetLastErrorByStatus(Status);
334 return(FALSE);
335 }
336
337 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
338
339 return(TRUE);
340 }
341
342
343 DWORD STDCALL
344 ResumeThread(HANDLE hThread)
345 {
346 ULONG PreviousResumeCount;
347 NTSTATUS Status;
348
349 Status = NtResumeThread(hThread,
350 &PreviousResumeCount);
351 if (!NT_SUCCESS(Status))
352 {
353 SetLastErrorByStatus(Status);
354 return(-1);
355 }
356
357 return(PreviousResumeCount);
358 }
359
360
361 WINBOOL STDCALL
362 TerminateThread(HANDLE hThread,
363 DWORD dwExitCode)
364 {
365 NTSTATUS Status;
366
367 if (0 == hThread)
368 {
369 SetLastError(ERROR_INVALID_HANDLE);
370 return(FALSE);
371 }
372
373 Status = NtTerminateThread(hThread,
374 dwExitCode);
375 if (!NT_SUCCESS(Status))
376 {
377 SetLastErrorByStatus(Status);
378 return(FALSE);
379 }
380
381 return(TRUE);
382 }
383
384
385 DWORD STDCALL
386 SuspendThread(HANDLE hThread)
387 {
388 ULONG PreviousSuspendCount;
389 NTSTATUS Status;
390
391 Status = NtSuspendThread(hThread,
392 &PreviousSuspendCount);
393 if (!NT_SUCCESS(Status))
394 {
395 SetLastErrorByStatus(Status);
396 return(-1);
397 }
398
399 return(PreviousSuspendCount);
400 }
401
402
403 DWORD STDCALL
404 SetThreadAffinityMask(HANDLE hThread,
405 DWORD dwThreadAffinityMask)
406 {
407 THREAD_BASIC_INFORMATION ThreadBasic;
408 KAFFINITY AffinityMask;
409 ULONG DataWritten;
410 NTSTATUS Status;
411
412 AffinityMask = (KAFFINITY)dwThreadAffinityMask;
413
414 Status = NtQueryInformationThread(hThread,
415 ThreadBasicInformation,
416 &ThreadBasic,
417 sizeof(THREAD_BASIC_INFORMATION),
418 &DataWritten);
419 if (!NT_SUCCESS(Status))
420 {
421 SetLastErrorByStatus(Status);
422 return(0);
423 }
424
425 Status = NtSetInformationThread(hThread,
426 ThreadAffinityMask,
427 &AffinityMask,
428 sizeof(KAFFINITY));
429 if (!NT_SUCCESS(Status))
430 SetLastErrorByStatus(Status);
431
432 return(ThreadBasic.AffinityMask);
433 }
434
435
436 WINBOOL STDCALL
437 SetThreadPriority(HANDLE hThread,
438 int nPriority)
439 {
440 THREAD_BASIC_INFORMATION ThreadBasic;
441 ULONG DataWritten;
442 NTSTATUS Status;
443
444 Status = NtQueryInformationThread(hThread,
445 ThreadBasicInformation,
446 &ThreadBasic,
447 sizeof(THREAD_BASIC_INFORMATION),
448 &DataWritten);
449 if (!NT_SUCCESS(Status))
450 {
451 SetLastErrorByStatus(Status);
452 return(FALSE);
453 }
454
455 ThreadBasic.BasePriority = nPriority;
456
457 Status = NtSetInformationThread(hThread,
458 ThreadBasicInformation,
459 &ThreadBasic,
460 sizeof(THREAD_BASIC_INFORMATION));
461 if (!NT_SUCCESS(Status))
462 {
463 SetLastErrorByStatus(Status);
464 return(FALSE);
465 }
466
467 return(TRUE);
468 }
469
470
471 int STDCALL
472 GetThreadPriority(HANDLE hThread)
473 {
474 THREAD_BASIC_INFORMATION ThreadBasic;
475 ULONG DataWritten;
476 NTSTATUS Status;
477
478 Status = NtQueryInformationThread(hThread,
479 ThreadBasicInformation,
480 &ThreadBasic,
481 sizeof(THREAD_BASIC_INFORMATION),
482 &DataWritten);
483 if (!NT_SUCCESS(Status))
484 {
485 SetLastErrorByStatus(Status);
486 return(THREAD_PRIORITY_ERROR_RETURN);
487 }
488
489 return(ThreadBasic.BasePriority);
490 }
491
492
493 WINBOOL STDCALL
494 GetThreadPriorityBoost(IN HANDLE hThread,
495 OUT PBOOL pDisablePriorityBoost)
496 {
497 ULONG PriorityBoost;
498 ULONG DataWritten;
499 NTSTATUS Status;
500
501 Status = NtQueryInformationThread(hThread,
502 ThreadPriorityBoost,
503 &PriorityBoost,
504 sizeof(ULONG),
505 &DataWritten);
506 if (!NT_SUCCESS(Status))
507 {
508 SetLastErrorByStatus(Status);
509 return(FALSE);
510 }
511
512 *pDisablePriorityBoost = !((WINBOOL)PriorityBoost);
513
514 return(TRUE);
515 }
516
517
518 WINBOOL STDCALL
519 SetThreadPriorityBoost(IN HANDLE hThread,
520 IN WINBOOL bDisablePriorityBoost)
521 {
522 ULONG PriorityBoost;
523 NTSTATUS Status;
524
525 PriorityBoost = (ULONG)!bDisablePriorityBoost;
526
527 Status = NtSetInformationThread(hThread,
528 ThreadPriorityBoost,
529 &PriorityBoost,
530 sizeof(ULONG));
531 if (!NT_SUCCESS(Status))
532 {
533 SetLastErrorByStatus(Status);
534 return(FALSE);
535 }
536
537 return(TRUE);
538 }
539
540
541 WINBOOL STDCALL
542 GetThreadSelectorEntry(IN HANDLE hThread,
543 IN DWORD dwSelector,
544 OUT LPLDT_ENTRY lpSelectorEntry)
545 {
546 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
547 return(FALSE);
548 }
549
550
551 WINBOOL STDCALL
552 SetThreadIdealProcessor(HANDLE hThread,
553 DWORD dwIdealProcessor)
554 {
555 ULONG IdealProcessor;
556 NTSTATUS Status;
557
558 IdealProcessor = (ULONG)dwIdealProcessor;
559
560 Status = NtSetInformationThread(hThread,
561 ThreadIdealProcessor,
562 &IdealProcessor,
563 sizeof(ULONG));
564 if (!NT_SUCCESS(Status))
565 {
566 SetLastErrorByStatus(Status);
567 return(FALSE);
568 }
569
570 return(TRUE);
571 }
572
573 /* EOF */