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