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