ntdll: Process --help and --version args earlier on during startup.
[wine] / dlls / kernel / thread.c
1 /*
2  * Win32 threads
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
38 #include "thread.h"
39 #include "wine/winbase16.h"
40 #include "wine/exception.h"
41 #include "wine/library.h"
42 #include "wine/server.h"
43 #include "wine/debug.h"
44
45 #include "kernel_private.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(thread);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
49
50
51 struct new_thread_info
52 {
53     LPTHREAD_START_ROUTINE func;
54     void                  *arg;
55 };
56
57
58 /***********************************************************************
59  *           THREAD_Start
60  *
61  * Start execution of a newly created thread. Does not return.
62  */
63 static void CALLBACK THREAD_Start( void *ptr )
64 {
65     struct new_thread_info *info = ptr;
66     LPTHREAD_START_ROUTINE func = info->func;
67     void *arg = info->arg;
68
69     RtlFreeHeap( GetProcessHeap(), 0, info );
70
71     if (TRACE_ON(relay))
72         DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
73
74     __TRY
75     {
76         ExitThread( func( arg ) );
77     }
78     __EXCEPT(UnhandledExceptionFilter)
79     {
80         TerminateThread( GetCurrentThread(), GetExceptionCode() );
81     }
82     __ENDTRY
83 }
84
85
86 /***********************************************************************
87  *           CreateThread   (KERNEL32.@)
88  */
89 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
90                             LPTHREAD_START_ROUTINE start, LPVOID param,
91                             DWORD flags, LPDWORD id )
92 {
93      return CreateRemoteThread( GetCurrentProcess(),
94                                 sa, stack, start, param, flags, id );
95 }
96
97
98 /***************************************************************************
99  *                  CreateRemoteThread   (KERNEL32.@)
100  *
101  * Creates a thread that runs in the address space of another process
102  *
103  * PARAMS
104  *
105  * RETURNS
106  *   Success: Handle to the new thread.
107  *   Failure: NULL. Use GetLastError() to find the error cause.
108  *
109  * BUGS
110  *   Improper memory allocation: there's no ability to free new_thread_info
111  *   in other process.
112  *   Bad start address for RtlCreateUserThread because the library
113  *   may be loaded at different address in other process.
114  */
115 HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
116                                   LPTHREAD_START_ROUTINE start, LPVOID param,
117                                   DWORD flags, LPDWORD id )
118 {
119     HANDLE handle;
120     CLIENT_ID client_id;
121     NTSTATUS status;
122     SIZE_T stack_reserve = 0, stack_commit = 0;
123     struct new_thread_info *info;
124
125     if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
126     {
127         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
128         return 0;
129     }
130     info->func = start;
131     info->arg  = param;
132
133     if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
134     else stack_commit = stack;
135
136     status = RtlCreateUserThread( hProcess, NULL, TRUE,
137                                   NULL, stack_reserve, stack_commit,
138                                   THREAD_Start, info, &handle, &client_id );
139     if (status == STATUS_SUCCESS)
140     {
141         if (id) *id = (DWORD)client_id.UniqueThread;
142         if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
143             SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
144         if (!(flags & CREATE_SUSPENDED))
145         {
146             ULONG ret;
147             if (NtResumeThread( handle, &ret ))
148             {
149                 NtClose( handle );
150                 RtlFreeHeap( GetProcessHeap(), 0, info );
151                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
152                 handle = 0;
153             }
154         }
155     }
156     else
157     {
158         RtlFreeHeap( GetProcessHeap(), 0, info );
159         SetLastError( RtlNtStatusToDosError(status) );
160         handle = 0;
161     }
162     return handle;
163 }
164
165
166 /***********************************************************************
167  * OpenThread  [KERNEL32.@]   Retrieves a handle to a thread from its thread id
168  */
169 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
170 {
171     NTSTATUS status;
172     HANDLE handle;
173     OBJECT_ATTRIBUTES attr;
174     CLIENT_ID cid;
175
176     attr.Length = sizeof(attr);
177     attr.RootDirectory = 0;
178     attr.Attributes = bInheritHandle ? OBJ_INHERIT : 0;
179     attr.ObjectName = NULL;
180     attr.SecurityDescriptor = NULL;
181     attr.SecurityQualityOfService = NULL;
182
183     cid.UniqueProcess = 0; /* FIXME */
184     cid.UniqueThread = (HANDLE)dwThreadId;
185     status = NtOpenThread( &handle, dwDesiredAccess, &attr, &cid );
186     if (status)
187     {
188         SetLastError( RtlNtStatusToDosError(status) );
189         handle = 0;
190     }
191     return handle;
192 }
193
194
195 /***********************************************************************
196  * ExitThread [KERNEL32.@]  Ends a thread
197  *
198  * RETURNS
199  *    None
200  */
201 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
202 {
203     BOOL last;
204     SERVER_START_REQ( terminate_thread )
205     {
206         /* send the exit code to the server */
207         req->handle    = GetCurrentThread();
208         req->exit_code = code;
209         wine_server_call( req );
210         last = reply->last;
211     }
212     SERVER_END_REQ;
213
214     if (last)
215     {
216         LdrShutdownProcess();
217         exit( code );
218     }
219     else RtlExitUserThread( code );
220 }
221
222
223 /**********************************************************************
224  * TerminateThread [KERNEL32.@]  Terminates a thread
225  *
226  * RETURNS
227  *    Success: TRUE
228  *    Failure: FALSE
229  */
230 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
231                              DWORD exit_code)  /* [in] Exit code for thread */
232 {
233     NTSTATUS status = NtTerminateThread( handle, exit_code );
234     if (status) SetLastError( RtlNtStatusToDosError(status) );
235     return !status;
236 }
237
238
239 /***********************************************************************
240  *           FreeLibraryAndExitThread (KERNEL32.@)
241  */
242 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
243 {
244     FreeLibrary(hLibModule);
245     ExitThread(dwExitCode);
246 }
247
248
249 /**********************************************************************
250  *              GetExitCodeThread (KERNEL32.@)
251  *
252  * Gets termination status of thread.
253  *
254  * RETURNS
255  *    Success: TRUE
256  *    Failure: FALSE
257  */
258 BOOL WINAPI GetExitCodeThread(
259     HANDLE hthread, /* [in]  Handle to thread */
260     LPDWORD exitcode) /* [out] Address to receive termination status */
261 {
262     THREAD_BASIC_INFORMATION info;
263     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
264                                                 &info, sizeof(info), NULL );
265
266     if (status)
267     {
268         SetLastError( RtlNtStatusToDosError(status) );
269         return FALSE;
270     }
271     if (exitcode) *exitcode = info.ExitStatus;
272     return TRUE;
273 }
274
275
276 /***********************************************************************
277  * SetThreadContext [KERNEL32.@]  Sets context of thread.
278  *
279  * RETURNS
280  *    Success: TRUE
281  *    Failure: FALSE
282  */
283 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
284                               const CONTEXT *context ) /* [in] Address of context structure */
285 {
286     NTSTATUS status = NtSetContextThread( handle, context );
287     if (status) SetLastError( RtlNtStatusToDosError(status) );
288     return !status;
289 }
290
291
292 /***********************************************************************
293  * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
294  *
295  * RETURNS
296  *    Success: TRUE
297  *    Failure: FALSE
298  */
299 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
300                               CONTEXT *context ) /* [out] Address of context structure */
301 {
302     NTSTATUS status = NtGetContextThread( handle, context );
303     if (status) SetLastError( RtlNtStatusToDosError(status) );
304     return !status;
305 }
306
307
308 /**********************************************************************
309  * SuspendThread [KERNEL32.@]  Suspends a thread.
310  *
311  * RETURNS
312  *    Success: Previous suspend count
313  *    Failure: 0xFFFFFFFF
314  */
315 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
316 {
317     DWORD ret;
318     NTSTATUS status = NtSuspendThread( hthread, &ret );
319
320     if (status)
321     {
322         ret = ~0U;
323         SetLastError( RtlNtStatusToDosError(status) );
324     }
325     return ret;
326 }
327
328
329 /**********************************************************************
330  * ResumeThread [KERNEL32.@]  Resumes a thread.
331  *
332  * Decrements a thread's suspend count.  When count is zero, the
333  * execution of the thread is resumed.
334  *
335  * RETURNS
336  *    Success: Previous suspend count
337  *    Failure: 0xFFFFFFFF
338  *    Already running: 0
339  */
340 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
341 {
342     DWORD ret;
343     NTSTATUS status = NtResumeThread( hthread, &ret );
344
345     if (status)
346     {
347         ret = ~0U;
348         SetLastError( RtlNtStatusToDosError(status) );
349     }
350     return ret;
351 }
352
353
354 /**********************************************************************
355  * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
356  *
357  * RETURNS
358  *    Success: Thread's priority level.
359  *    Failure: THREAD_PRIORITY_ERROR_RETURN
360  */
361 INT WINAPI GetThreadPriority(
362     HANDLE hthread) /* [in] Handle to thread */
363 {
364     THREAD_BASIC_INFORMATION info;
365     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
366                                                 &info, sizeof(info), NULL );
367
368     if (status)
369     {
370         SetLastError( RtlNtStatusToDosError(status) );
371         return THREAD_PRIORITY_ERROR_RETURN;
372     }
373     return info.Priority;
374 }
375
376
377 /**********************************************************************
378  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
379  *
380  * RETURNS
381  *    Success: TRUE
382  *    Failure: FALSE
383  */
384 BOOL WINAPI SetThreadPriority(
385     HANDLE hthread, /* [in] Handle to thread */
386     INT priority)   /* [in] Thread priority level */
387 {
388     DWORD       prio = priority;
389     NTSTATUS    status;
390
391     status = NtSetInformationThread(hthread, ThreadBasePriority,
392                                     &prio, sizeof(prio));
393
394     if (status)
395     {
396         SetLastError( RtlNtStatusToDosError(status) );
397         return FALSE;
398     }
399
400     return TRUE;
401 }
402
403
404 /**********************************************************************
405  * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
406  *
407  * Always reports that priority boost is disabled.
408  *
409  * RETURNS
410  *    Success: TRUE.
411  *    Failure: FALSE
412  */
413 BOOL WINAPI GetThreadPriorityBoost(
414     HANDLE hthread, /* [in] Handle to thread */
415     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
416 {
417     if (pstate) *pstate = FALSE;
418     return NO_ERROR;
419 }
420
421
422 /**********************************************************************
423  * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
424  *
425  * Priority boost is not implemented. Thsi function always returns
426  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
427  *
428  * RETURNS
429  *    Always returns FALSE to indicate a failure
430  */
431 BOOL WINAPI SetThreadPriorityBoost(
432     HANDLE hthread, /* [in] Handle to thread */
433     BOOL disable)   /* [in] TRUE to disable priority boost */
434 {
435     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
436     return FALSE;
437 }
438
439
440 /**********************************************************************
441  *           SetThreadAffinityMask   (KERNEL32.@)
442  */
443 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
444 {
445     NTSTATUS                    status;
446     THREAD_BASIC_INFORMATION    tbi;
447
448     status = NtQueryInformationThread( hThread, ThreadBasicInformation, 
449                                        &tbi, sizeof(tbi), NULL );
450     if (status)
451     {
452         SetLastError( RtlNtStatusToDosError(status) );
453         return 0;
454     }
455     status = NtSetInformationThread( hThread, ThreadAffinityMask, 
456                                      &dwThreadAffinityMask,
457                                      sizeof(dwThreadAffinityMask));
458     if (status)
459     {
460         SetLastError( RtlNtStatusToDosError(status) );
461         return 0;
462     }
463     return tbi.AffinityMask;
464 }
465
466
467 /**********************************************************************
468  * SetThreadIdealProcessor [KERNEL32.@]  Obtains timing information.
469  *
470  * RETURNS
471  *    Success: Value of last call to SetThreadIdealProcessor
472  *    Failure: -1
473  */
474 DWORD WINAPI SetThreadIdealProcessor(
475     HANDLE hThread,          /* [in] Specifies the thread of interest */
476     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
477 {
478     FIXME("(%p): stub\n",hThread);
479     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
480     return -1L;
481 }
482
483
484 /* callback for QueueUserAPC */
485 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
486 {
487     PAPCFUNC func = (PAPCFUNC)arg1;
488     func( arg2 );
489 }
490
491 /***********************************************************************
492  *              QueueUserAPC  (KERNEL32.@)
493  */
494 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
495 {
496     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
497
498     if (status) SetLastError( RtlNtStatusToDosError(status) );
499     return !status;
500 }
501
502 /***********************************************************************
503  *              QueueUserWorkItem  (KERNEL32.@)
504  */
505 BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
506 {
507     NTSTATUS status;
508
509     TRACE("(%p,%p,0x%08lx)\n", Function, Context, Flags);
510
511     status = RtlQueueWorkItem( Function, Context, Flags );
512
513     if (status) SetLastError( RtlNtStatusToDosError(status) );
514     return !status;
515 }
516
517 /**********************************************************************
518  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
519  *
520  * RETURNS
521  *    Success: TRUE
522  *    Failure: FALSE
523  */
524 BOOL WINAPI GetThreadTimes(
525     HANDLE thread,         /* [in]  Specifies the thread of interest */
526     LPFILETIME creationtime, /* [out] When the thread was created */
527     LPFILETIME exittime,     /* [out] When the thread was destroyed */
528     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
529     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
530 {
531     KERNEL_USER_TIMES   kusrt;
532     NTSTATUS            status;
533
534     status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
535                                       sizeof(kusrt), NULL);
536     if (status)
537     {
538         SetLastError( RtlNtStatusToDosError(status) );
539         return FALSE;
540     }
541     if (creationtime)
542     {
543         creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
544         creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
545     }
546     if (exittime)
547     {
548         exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
549         exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
550     }
551     if (kerneltime)
552     {
553         kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
554         kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
555     }
556     if (usertime)
557     {
558         usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
559         usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
560     }
561     
562     return TRUE;
563 }
564
565
566 /**********************************************************************
567  * VWin32_BoostThreadGroup [KERNEL.535]
568  */
569 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
570 {
571     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
572 }
573
574
575 /**********************************************************************
576  * VWin32_BoostThreadStatic [KERNEL.536]
577  */
578 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
579 {
580     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
581 }
582
583
584 /***********************************************************************
585  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
586  *
587  * RETURNS
588  *    Pseudohandle for the current thread
589  */
590 #undef GetCurrentThread
591 HANDLE WINAPI GetCurrentThread(void)
592 {
593     return (HANDLE)0xfffffffe;
594 }
595
596
597 #ifdef __i386__
598
599 /***********************************************************************
600  *              SetLastError (KERNEL.147)
601  *              SetLastError (KERNEL32.@)
602  */
603 /* void WINAPI SetLastError( DWORD error ); */
604 __ASM_GLOBAL_FUNC( SetLastError,
605                    "movl 4(%esp),%eax\n\t"
606                    ".byte 0x64\n\t"
607                    "movl %eax,0x34\n\t"
608                    "ret $4" )
609
610 /***********************************************************************
611  *              GetLastError (KERNEL.148)
612  *              GetLastError (KERNEL32.@)
613  */
614 /* DWORD WINAPI GetLastError(void); */
615 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
616
617 /***********************************************************************
618  *              GetCurrentProcessId (KERNEL.471)
619  *              GetCurrentProcessId (KERNEL32.@)
620  */
621 /* DWORD WINAPI GetCurrentProcessId(void) */
622 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
623
624 /***********************************************************************
625  *              GetCurrentThreadId (KERNEL.462)
626  *              GetCurrentThreadId (KERNEL32.@)
627  */
628 /* DWORD WINAPI GetCurrentThreadId(void) */
629 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
630
631 #else  /* __i386__ */
632
633 /**********************************************************************
634  *              SetLastError (KERNEL.147)
635  *              SetLastError (KERNEL32.@)
636  *
637  * Sets the last-error code.
638  *
639  * RETURNS
640  * Nothing.
641  */
642 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
643 {
644     NtCurrentTeb()->LastErrorValue = error;
645 }
646
647 /**********************************************************************
648  *              GetLastError (KERNEL.148)
649  *              GetLastError (KERNEL32.@)
650  *
651  * Get the last-error code.
652  *
653  * RETURNS
654  *  last-error code.
655  */
656 DWORD WINAPI GetLastError(void)
657 {
658     return NtCurrentTeb()->LastErrorValue;
659 }
660
661 /***********************************************************************
662  *              GetCurrentProcessId (KERNEL.471)
663  *              GetCurrentProcessId (KERNEL32.@)
664  *
665  * Get the current process identifier.
666  *
667  * RETURNS
668  *  current process identifier
669  */
670 DWORD WINAPI GetCurrentProcessId(void)
671 {
672     return (DWORD)NtCurrentTeb()->ClientId.UniqueProcess;
673 }
674
675 /***********************************************************************
676  *              GetCurrentThreadId (KERNEL.462)
677  *              GetCurrentThreadId (KERNEL32.@)
678  *
679  * Get the current thread identifier.
680  *
681  * RETURNS
682  *  current thread identifier
683  */
684 DWORD WINAPI GetCurrentThreadId(void)
685 {
686     return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
687 }
688
689 #endif  /* __i386__ */