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