branch update for HEAD-2003021201
[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
21 //static VOID ThreadAttachDlls (VOID);
22
23 /* FUNCTIONS *****************************************************************/
24
25 static EXCEPTION_DISPOSITION __cdecl
26 _except_handler(struct _EXCEPTION_RECORD *ExceptionRecord,
27                 void * EstablisherFrame,
28                 struct _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
58 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
59              DWORD dwStackSize,
60              LPTHREAD_START_ROUTINE lpStartAddress,
61              LPVOID lpParameter,
62              DWORD dwCreationFlags,
63              LPDWORD lpThreadId)
64 {
65   return(CreateRemoteThread(NtCurrentProcess(),
66                             lpThreadAttributes,
67                             dwStackSize,
68                             lpStartAddress,
69                             lpParameter,
70                             dwCreationFlags,
71                             lpThreadId));
72 }
73
74
75 HANDLE STDCALL
76 CreateRemoteThread(HANDLE hProcess,
77                    LPSECURITY_ATTRIBUTES lpThreadAttributes,
78                    DWORD dwStackSize,
79                    LPTHREAD_START_ROUTINE lpStartAddress,
80                    LPVOID lpParameter,
81                    DWORD dwCreationFlags,
82                    LPDWORD lpThreadId)
83 {
84   HANDLE ThreadHandle;
85   OBJECT_ATTRIBUTES ObjectAttributes;
86   CLIENT_ID ClientId;
87   CONTEXT ThreadContext;
88   INITIAL_TEB InitialTeb;
89   BOOLEAN CreateSuspended = FALSE;
90   PVOID BaseAddress;
91   ULONG OldPageProtection;
92   NTSTATUS Status;
93
94   ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
95   ObjectAttributes.RootDirectory = NULL;
96   ObjectAttributes.ObjectName = NULL;
97   ObjectAttributes.Attributes = 0;
98   if (lpThreadAttributes != NULL)
99     {
100       if (lpThreadAttributes->bInheritHandle)
101         ObjectAttributes.Attributes = OBJ_INHERIT;
102       ObjectAttributes.SecurityDescriptor = 
103         lpThreadAttributes->lpSecurityDescriptor;
104     }
105   ObjectAttributes.SecurityQualityOfService = NULL;
106
107   if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
108     CreateSuspended = TRUE;
109   else
110     CreateSuspended = FALSE;
111
112   InitialTeb.StackReserve = 0x100000; /* 1MByte */
113   /* FIXME: use correct commit size */
114 #if 0
115   InitialTeb.StackCommit = (dwStackSize == 0) ? PAGE_SIZE : dwStackSize;
116 #endif
117   InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
118
119   /* size of guard page */
120   InitialTeb.StackCommit += PAGE_SIZE;
121
122   /* Reserve stack */
123   InitialTeb.StackAllocate = NULL;
124   Status = NtAllocateVirtualMemory(hProcess,
125                                    &InitialTeb.StackAllocate,
126                                    0,
127                                    &InitialTeb.StackReserve,
128                                    MEM_RESERVE,
129                                    PAGE_READWRITE);
130   if (!NT_SUCCESS(Status))
131     {
132       DPRINT("Error reserving stack space!\n");
133       SetLastErrorByStatus(Status);
134       return(NULL);
135     }
136
137   DPRINT("StackDeallocation: %p ReserveSize: 0x%lX\n",
138          InitialTeb.StackDeallocation, InitialTeb.StackReserve);
139
140   InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
141   InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
142
143   DPRINT("StackBase: %p\nStackCommit: 0x%lX\n",
144          InitialTeb.StackBase,
145          InitialTeb.StackCommit);
146
147   /* Commit stack pages */
148   Status = NtAllocateVirtualMemory(hProcess,
149                                    &InitialTeb.StackLimit,
150                                    0,
151                                    &InitialTeb.StackCommit,
152                                    MEM_COMMIT,
153                                    PAGE_READWRITE);
154   if (!NT_SUCCESS(Status))
155     {
156       /* release the stack space */
157       NtFreeVirtualMemory(hProcess,
158                           InitialTeb.StackAllocate,
159                           &InitialTeb.StackReserve,
160                           MEM_RELEASE);
161
162       DPRINT("Error comitting stack page(s)!\n");
163       SetLastErrorByStatus(Status);
164       return(NULL);
165     }
166
167   DPRINT("StackLimit: %p\n",
168          InitialTeb.StackLimit);
169
170   /* Protect guard page */
171   Status = NtProtectVirtualMemory(hProcess,
172                                   InitialTeb.StackLimit,
173                                   PAGE_SIZE,
174                                   PAGE_GUARD | PAGE_READWRITE,
175                                   &OldPageProtection);
176   if (!NT_SUCCESS(Status))
177     {
178       /* release the stack space */
179       NtFreeVirtualMemory(hProcess,
180                           InitialTeb.StackAllocate,
181                           &InitialTeb.StackReserve,
182                           MEM_RELEASE);
183
184       DPRINT("Error comitting guard page!\n");
185       SetLastErrorByStatus(Status);
186       return(NULL);
187     }
188
189   memset(&ThreadContext,0,sizeof(CONTEXT));
190   ThreadContext.Eip = (LONG)ThreadStartup;
191   ThreadContext.SegGs = USER_DS;
192   ThreadContext.SegFs = TEB_SELECTOR;
193   ThreadContext.SegEs = USER_DS;
194   ThreadContext.SegDs = USER_DS;
195   ThreadContext.SegCs = USER_CS;
196   ThreadContext.SegSs = USER_DS;
197   ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 12;
198   ThreadContext.EFlags = (1<<1) + (1<<9);
199
200   /* initialize call stack */
201   *((PULONG)((ULONG)InitialTeb.StackBase - 4)) = (ULONG)lpParameter;
202   *((PULONG)((ULONG)InitialTeb.StackBase - 8)) = (ULONG)lpStartAddress;
203   *((PULONG)((ULONG)InitialTeb.StackBase - 12)) = 0xdeadbeef;
204
205   DPRINT("Esp: %p\n", ThreadContext.Esp);
206   DPRINT("Eip: %p\n", ThreadContext.Eip);
207
208   Status = NtCreateThread(&ThreadHandle,
209                           THREAD_ALL_ACCESS,
210                           &ObjectAttributes,
211                           hProcess,
212                           &ClientId,
213                           &ThreadContext,
214                           &InitialTeb,
215                           CreateSuspended);
216   if (!NT_SUCCESS(Status))
217     {
218       NtFreeVirtualMemory(hProcess,
219                           InitialTeb.StackAllocate,
220                           &InitialTeb.StackReserve,
221                           MEM_RELEASE);
222
223       DPRINT("NtCreateThread() failed!\n");
224       SetLastErrorByStatus(Status);
225       return(NULL);
226     }
227
228   if (lpThreadId != NULL)
229     memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
230
231   return(ThreadHandle);
232 }
233
234
235 PTEB
236 GetTeb(VOID)
237 {
238   return(NtCurrentTeb());
239 }
240
241
242 WINBOOL STDCALL
243 SwitchToThread(VOID)
244 {
245   NTSTATUS errCode;
246   errCode = NtYieldExecution();
247   return TRUE;
248 }
249
250
251 DWORD STDCALL
252 GetCurrentThreadId(VOID)
253 {
254   return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
255 }
256
257
258 VOID STDCALL
259 ExitThread(DWORD uExitCode)
260 {
261   BOOLEAN LastThread;
262   NTSTATUS Status;
263
264   /*
265    * Terminate process if this is the last thread
266    * of the current process
267    */
268   Status = NtQueryInformationThread(NtCurrentThread(),
269                                     ThreadAmILastThread,
270                                     &LastThread,
271                                     sizeof(BOOLEAN),
272                                     NULL);
273   if (NT_SUCCESS(Status) && LastThread == TRUE)
274     {
275       ExitProcess(uExitCode);
276     }
277
278   /* FIXME: notify csrss of thread termination */
279
280   LdrShutdownThread();
281
282   Status = NtTerminateThread(NtCurrentThread(),
283                              uExitCode);
284   if (!NT_SUCCESS(Status))
285     {
286       SetLastErrorByStatus(Status);
287     }
288 }
289
290
291 WINBOOL STDCALL
292 GetThreadTimes(HANDLE hThread,
293                LPFILETIME lpCreationTime,
294                LPFILETIME lpExitTime,
295                LPFILETIME lpKernelTime,
296                LPFILETIME lpUserTime)
297 {
298   KERNEL_USER_TIMES KernelUserTimes;
299   ULONG ReturnLength;
300   NTSTATUS Status;
301
302   Status = NtQueryInformationThread(hThread,
303                                     ThreadTimes,
304                                     &KernelUserTimes,
305                                     sizeof(KERNEL_USER_TIMES),
306                                     &ReturnLength);
307   if (!NT_SUCCESS(Status))
308     {
309       SetLastErrorByStatus(Status);
310       return(FALSE);
311     }
312
313   memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
314   memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
315   memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
316   memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
317
318   return(TRUE);
319 }
320
321
322 WINBOOL STDCALL
323 GetThreadContext(HANDLE hThread,
324                  LPCONTEXT lpContext)
325 {
326   NTSTATUS Status;
327
328   Status = NtGetContextThread(hThread,
329                               lpContext);
330   if (!NT_SUCCESS(Status))
331     {
332       SetLastErrorByStatus(Status);
333       return(FALSE);
334     }
335
336   return(TRUE);
337 }
338
339
340 WINBOOL STDCALL
341 SetThreadContext(HANDLE hThread,
342                  CONST CONTEXT *lpContext)
343 {
344   NTSTATUS Status;
345
346   Status = NtSetContextThread(hThread,
347                               (void *)lpContext);
348   if (!NT_SUCCESS(Status))
349     {
350       SetLastErrorByStatus(Status);
351       return(FALSE);
352     }
353
354   return(TRUE);
355 }
356
357
358 WINBOOL STDCALL
359 GetExitCodeThread(HANDLE hThread,
360                   LPDWORD lpExitCode)
361 {
362   THREAD_BASIC_INFORMATION ThreadBasic;
363   ULONG DataWritten;
364   NTSTATUS Status;
365
366   Status = NtQueryInformationThread(hThread,
367                                     ThreadBasicInformation,
368                                     &ThreadBasic,
369                                     sizeof(THREAD_BASIC_INFORMATION),
370                                     &DataWritten);
371   if (!NT_SUCCESS(Status))
372     {
373       SetLastErrorByStatus(Status);
374       return(FALSE);
375     }
376
377   memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
378
379   return(TRUE);
380 }
381
382
383 DWORD STDCALL
384 ResumeThread(HANDLE hThread)
385 {
386   ULONG PreviousResumeCount;
387   NTSTATUS Status;
388
389   Status = NtResumeThread(hThread,
390                           &PreviousResumeCount);
391   if (!NT_SUCCESS(Status))
392     {
393       SetLastErrorByStatus(Status);
394       return(-1);
395     }
396
397   return(PreviousResumeCount);
398 }
399
400
401 WINBOOL STDCALL
402 TerminateThread(HANDLE hThread,
403                 DWORD dwExitCode)
404 {
405   NTSTATUS Status;
406
407   if (0 == hThread)
408     {
409       SetLastError(ERROR_INVALID_HANDLE);
410       return(FALSE);
411     }
412
413   Status = NtTerminateThread(hThread,
414                              dwExitCode);
415   if (!NT_SUCCESS(Status))
416     {
417       SetLastErrorByStatus(Status);
418       return(FALSE);
419     }
420
421   return(TRUE);
422 }
423
424
425 DWORD STDCALL
426 SuspendThread(HANDLE hThread)
427 {
428   ULONG PreviousSuspendCount;
429   NTSTATUS Status;
430
431   Status = NtSuspendThread(hThread,
432                            &PreviousSuspendCount);
433   if (!NT_SUCCESS(Status))
434     {
435       SetLastErrorByStatus(Status);
436       return(-1);
437     }
438
439   return(PreviousSuspendCount);
440 }
441
442
443 DWORD STDCALL
444 SetThreadAffinityMask(HANDLE hThread,
445                       DWORD dwThreadAffinityMask)
446 {
447   THREAD_BASIC_INFORMATION ThreadBasic;
448   KAFFINITY AffinityMask;
449   ULONG DataWritten;
450   NTSTATUS Status;
451
452   AffinityMask = (KAFFINITY)dwThreadAffinityMask;
453
454   Status = NtQueryInformationThread(hThread,
455                                     ThreadBasicInformation,
456                                     &ThreadBasic,
457                                     sizeof(THREAD_BASIC_INFORMATION),
458                                     &DataWritten);
459   if (!NT_SUCCESS(Status))
460     {
461       SetLastErrorByStatus(Status);
462       return(0);
463     }
464
465   Status = NtSetInformationThread(hThread,
466                                   ThreadAffinityMask,
467                                   &AffinityMask,
468                                   sizeof(KAFFINITY));
469   if (!NT_SUCCESS(Status))
470     SetLastErrorByStatus(Status);
471
472   return(ThreadBasic.AffinityMask);
473 }
474
475
476 WINBOOL STDCALL
477 SetThreadPriority(HANDLE hThread,
478                   int nPriority)
479 {
480   THREAD_BASIC_INFORMATION ThreadBasic;
481   ULONG DataWritten;
482   NTSTATUS Status;
483
484   Status = NtQueryInformationThread(hThread,
485                                     ThreadBasicInformation,
486                                     &ThreadBasic,
487                                     sizeof(THREAD_BASIC_INFORMATION),
488                                     &DataWritten);
489   if (!NT_SUCCESS(Status))
490     {
491       SetLastErrorByStatus(Status);
492       return(FALSE);
493     }
494
495   ThreadBasic.BasePriority = nPriority;
496
497   Status = NtSetInformationThread(hThread,
498                                   ThreadBasicInformation,
499                                   &ThreadBasic,
500                                   sizeof(THREAD_BASIC_INFORMATION));
501   if (!NT_SUCCESS(Status))
502     {
503       SetLastErrorByStatus(Status);
504       return(FALSE);
505     }
506
507   return(TRUE);
508 }
509
510
511 int STDCALL
512 GetThreadPriority(HANDLE hThread)
513 {
514   THREAD_BASIC_INFORMATION ThreadBasic;
515   ULONG DataWritten;
516   NTSTATUS Status;
517
518   Status = NtQueryInformationThread(hThread,
519                                     ThreadBasicInformation,
520                                     &ThreadBasic,
521                                     sizeof(THREAD_BASIC_INFORMATION),
522                                     &DataWritten);
523   if (!NT_SUCCESS(Status))
524     {
525       SetLastErrorByStatus(Status);
526       return(THREAD_PRIORITY_ERROR_RETURN);
527     }
528
529   return(ThreadBasic.BasePriority);
530 }
531
532
533 WINBOOL STDCALL
534 GetThreadPriorityBoost(IN HANDLE hThread,
535                        OUT PBOOL pDisablePriorityBoost)
536 {
537   ULONG PriorityBoost;
538   ULONG DataWritten;
539   NTSTATUS Status;
540
541   Status = NtQueryInformationThread(hThread,
542                                     ThreadPriorityBoost,
543                                     &PriorityBoost,
544                                     sizeof(ULONG),
545                                     &DataWritten);
546   if (!NT_SUCCESS(Status))
547     {
548       SetLastErrorByStatus(Status);
549       return(FALSE);
550     }
551
552   *pDisablePriorityBoost = !((WINBOOL)PriorityBoost);
553
554   return(TRUE);
555 }
556
557
558 WINBOOL STDCALL
559 SetThreadPriorityBoost(IN HANDLE hThread,
560                        IN WINBOOL bDisablePriorityBoost)
561 {
562   ULONG PriorityBoost;
563   NTSTATUS Status;
564
565   PriorityBoost = (ULONG)!bDisablePriorityBoost;
566
567   Status = NtSetInformationThread(hThread,
568                                   ThreadPriorityBoost,
569                                   &PriorityBoost,
570                                   sizeof(ULONG));
571   if (!NT_SUCCESS(Status))
572     {
573       SetLastErrorByStatus(Status);
574       return(FALSE);
575     }
576
577   return(TRUE);
578 }
579
580
581 WINBOOL STDCALL
582 GetThreadSelectorEntry(IN HANDLE hThread,
583                        IN DWORD dwSelector,
584                        OUT LPLDT_ENTRY lpSelectorEntry)
585 {
586   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
587   return(FALSE);
588 }
589
590
591 WINBOOL STDCALL
592 SetThreadIdealProcessor(HANDLE hThread,
593                         DWORD dwIdealProcessor)
594 {
595   ULONG IdealProcessor;
596   NTSTATUS Status;
597
598   IdealProcessor = (ULONG)dwIdealProcessor;
599
600   Status = NtSetInformationThread(hThread,
601                                   ThreadIdealProcessor,
602                                   &IdealProcessor,
603                                   sizeof(ULONG));
604   if (!NT_SUCCESS(Status))
605     {
606       SetLastErrorByStatus(Status);
607       return(FALSE);
608     }
609
610   return(TRUE);
611 }
612
613 /* EOF */