INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[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 <signal.h>
28 #include <sys/types.h>
29 #ifdef HAVE_SYS_TIMES_H
30 #include <sys/times.h>
31 #endif
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35
36 #include "ntstatus.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "winnls.h"
41 #include "module.h"
42 #include "thread.h"
43 #include "wine/winbase16.h"
44 #include "wine/library.h"
45 #include "wine/pthread.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(thread);
50 WINE_DECLARE_DEBUG_CHANNEL(relay);
51
52
53 /***********************************************************************
54  *           THREAD_InitStack
55  *
56  * Allocate the stack of a thread.
57  */
58 TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
59 {
60     DWORD old_prot;
61     DWORD page_size = getpagesize();
62     void *base;
63
64     stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
65     if (stack_size < 1024 * 1024) stack_size = 1024 * 1024;  /* Xlib needs a large stack */
66
67     if (!(base = VirtualAlloc( NULL, stack_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
68         return NULL;
69
70     teb->DeallocationStack = base;
71     teb->Tib.StackBase     = (char *)base + stack_size;
72     teb->Tib.StackLimit    = base;  /* note: limit is lower than base since the stack grows down */
73
74     /* Setup guard pages */
75
76     VirtualProtect( base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
77     return teb;
78 }
79
80
81 struct new_thread_info
82 {
83     LPTHREAD_START_ROUTINE func;
84     void                  *arg;
85 };
86
87 /***********************************************************************
88  *           THREAD_Start
89  *
90  * Start execution of a newly created thread. Does not return.
91  */
92 static void CALLBACK THREAD_Start( void *ptr )
93 {
94     struct new_thread_info *info = ptr;
95     LPTHREAD_START_ROUTINE func = info->func;
96     void *arg = info->arg;
97
98     RtlFreeHeap( GetProcessHeap(), 0, info );
99
100     if (TRACE_ON(relay))
101         DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
102
103     __TRY
104     {
105         MODULE_DllThreadAttach( NULL );
106         ExitThread( func( arg ) );
107     }
108     __EXCEPT(UnhandledExceptionFilter)
109     {
110         TerminateThread( GetCurrentThread(), GetExceptionCode() );
111     }
112     __ENDTRY
113 }
114
115
116 /***********************************************************************
117  *           CreateThread   (KERNEL32.@)
118  */
119 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
120                             LPTHREAD_START_ROUTINE start, LPVOID param,
121                             DWORD flags, LPDWORD id )
122 {
123     HANDLE handle;
124     CLIENT_ID client_id;
125     NTSTATUS status;
126     SIZE_T stack_reserve = 0, stack_commit = 0;
127     struct new_thread_info *info;
128
129     if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
130     {
131         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
132         return 0;
133     }
134     info->func = start;
135     info->arg  = param;
136
137     if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
138     else stack_commit = stack;
139
140     status = RtlCreateUserThread( GetCurrentProcess(), NULL, (flags & CREATE_SUSPENDED) != 0,
141                                   NULL, stack_reserve, stack_commit,
142                                   THREAD_Start, info, &handle, &client_id );
143     if (status == STATUS_SUCCESS)
144     {
145         if (id) *id = (DWORD)client_id.UniqueThread;
146         if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
147             SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
148     }
149     else
150     {
151         RtlFreeHeap( GetProcessHeap(), 0, info );
152         SetLastError( RtlNtStatusToDosError(status) );
153         handle = 0;
154     }
155     return handle;
156 }
157
158
159 /***********************************************************************
160  * OpenThread  [KERNEL32.@]   Retrieves a handle to a thread from its thread id
161  */
162 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
163 {
164     HANDLE ret = 0;
165     SERVER_START_REQ( open_thread )
166     {
167         req->tid     = dwThreadId;
168         req->access  = dwDesiredAccess;
169         req->inherit = bInheritHandle;
170         if (!wine_server_call_err( req )) ret = reply->handle;
171     }
172     SERVER_END_REQ;
173     return ret;
174 }
175
176
177 /***********************************************************************
178  * ExitThread [KERNEL32.@]  Ends a thread
179  *
180  * RETURNS
181  *    None
182  */
183 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
184 {
185     BOOL last;
186     SERVER_START_REQ( terminate_thread )
187     {
188         /* send the exit code to the server */
189         req->handle    = GetCurrentThread();
190         req->exit_code = code;
191         wine_server_call( req );
192         last = reply->last;
193     }
194     SERVER_END_REQ;
195
196     if (last)
197     {
198         LdrShutdownProcess();
199         exit( code );
200     }
201     else
202     {
203         struct wine_pthread_thread_info info;
204         sigset_t block_set;
205         ULONG size;
206
207         LdrShutdownThread();
208         RtlAcquirePebLock();
209         RemoveEntryList( &NtCurrentTeb()->TlsLinks );
210         RtlReleasePebLock();
211
212         info.stack_base  = NtCurrentTeb()->DeallocationStack;
213         info.teb_base    = NtCurrentTeb();
214         info.teb_sel     = wine_get_fs();
215         info.exit_status = code;
216
217         size = 0;
218         NtFreeVirtualMemory( GetCurrentProcess(), &info.stack_base, &size, MEM_RELEASE | MEM_SYSTEM );
219         info.stack_size = size;
220
221         size = 0;
222         NtFreeVirtualMemory( GetCurrentProcess(), &info.teb_base, &size, MEM_RELEASE | MEM_SYSTEM );
223         info.teb_size = size;
224
225         /* block the async signals */
226         sigemptyset( &block_set );
227         sigaddset( &block_set, SIGALRM );
228         sigaddset( &block_set, SIGIO );
229         sigaddset( &block_set, SIGINT );
230         sigaddset( &block_set, SIGHUP );
231         sigaddset( &block_set, SIGUSR1 );
232         sigaddset( &block_set, SIGUSR2 );
233         sigaddset( &block_set, SIGTERM );
234         sigprocmask( SIG_BLOCK, &block_set, NULL );
235
236         close( NtCurrentTeb()->wait_fd[0] );
237         close( NtCurrentTeb()->wait_fd[1] );
238         close( NtCurrentTeb()->reply_fd );
239         close( NtCurrentTeb()->request_fd );
240
241         wine_pthread_exit_thread( &info );
242     }
243 }
244
245
246 /**********************************************************************
247  * TerminateThread [KERNEL32.@]  Terminates a thread
248  *
249  * RETURNS
250  *    Success: TRUE
251  *    Failure: FALSE
252  */
253 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
254                              DWORD exit_code)  /* [in] Exit code for thread */
255 {
256     NTSTATUS status = NtTerminateThread( handle, exit_code );
257     if (status) SetLastError( RtlNtStatusToDosError(status) );
258     return !status;
259 }
260
261
262 /***********************************************************************
263  *           FreeLibraryAndExitThread (KERNEL32.@)
264  */
265 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
266 {
267     FreeLibrary(hLibModule);
268     ExitThread(dwExitCode);
269 }
270
271
272 /**********************************************************************
273  *              GetExitCodeThread (KERNEL32.@)
274  *
275  * Gets termination status of thread.
276  *
277  * RETURNS
278  *    Success: TRUE
279  *    Failure: FALSE
280  */
281 BOOL WINAPI GetExitCodeThread(
282     HANDLE hthread, /* [in]  Handle to thread */
283     LPDWORD exitcode) /* [out] Address to receive termination status */
284 {
285     THREAD_BASIC_INFORMATION info;
286     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
287                                                 &info, sizeof(info), NULL );
288
289     if (status)
290     {
291         SetLastError( RtlNtStatusToDosError(status) );
292         return FALSE;
293     }
294     if (exitcode) *exitcode = info.ExitStatus;
295     return TRUE;
296 }
297
298
299 /***********************************************************************
300  * SetThreadContext [KERNEL32.@]  Sets context of thread.
301  *
302  * RETURNS
303  *    Success: TRUE
304  *    Failure: FALSE
305  */
306 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
307                               const CONTEXT *context ) /* [in] Address of context structure */
308 {
309     NTSTATUS status = NtSetContextThread( handle, context );
310     if (status) SetLastError( RtlNtStatusToDosError(status) );
311     return !status;
312 }
313
314
315 /***********************************************************************
316  * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
317  *
318  * RETURNS
319  *    Success: TRUE
320  *    Failure: FALSE
321  */
322 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
323                               CONTEXT *context ) /* [out] Address of context structure */
324 {
325     NTSTATUS status = NtGetContextThread( handle, context );
326     if (status) SetLastError( RtlNtStatusToDosError(status) );
327     return !status;
328 }
329
330
331 /**********************************************************************
332  * SuspendThread [KERNEL32.@]  Suspends a thread.
333  *
334  * RETURNS
335  *    Success: Previous suspend count
336  *    Failure: 0xFFFFFFFF
337  */
338 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
339 {
340     DWORD ret;
341     NTSTATUS status = NtSuspendThread( hthread, &ret );
342
343     if (status)
344     {
345         ret = ~0U;
346         SetLastError( RtlNtStatusToDosError(status) );
347     }
348     return ret;
349 }
350
351
352 /**********************************************************************
353  * ResumeThread [KERNEL32.@]  Resumes a thread.
354  *
355  * Decrements a thread's suspend count.  When count is zero, the
356  * execution of the thread is resumed.
357  *
358  * RETURNS
359  *    Success: Previous suspend count
360  *    Failure: 0xFFFFFFFF
361  *    Already running: 0
362  */
363 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
364 {
365     DWORD ret;
366     NTSTATUS status = NtResumeThread( hthread, &ret );
367
368     if (status)
369     {
370         ret = ~0U;
371         SetLastError( RtlNtStatusToDosError(status) );
372     }
373     return ret;
374 }
375
376
377 /**********************************************************************
378  * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
379  *
380  * RETURNS
381  *    Success: Thread's priority level.
382  *    Failure: THREAD_PRIORITY_ERROR_RETURN
383  */
384 INT WINAPI GetThreadPriority(
385     HANDLE hthread) /* [in] Handle to thread */
386 {
387     THREAD_BASIC_INFORMATION info;
388     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
389                                                 &info, sizeof(info), NULL );
390
391     if (status)
392     {
393         SetLastError( RtlNtStatusToDosError(status) );
394         return THREAD_PRIORITY_ERROR_RETURN;
395     }
396     return info.Priority;
397 }
398
399
400 /**********************************************************************
401  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
402  *
403  * RETURNS
404  *    Success: TRUE
405  *    Failure: FALSE
406  */
407 BOOL WINAPI SetThreadPriority(
408     HANDLE hthread, /* [in] Handle to thread */
409     INT priority)   /* [in] Thread priority level */
410 {
411     BOOL ret;
412     SERVER_START_REQ( set_thread_info )
413     {
414         req->handle   = hthread;
415         req->priority = priority;
416         req->mask     = SET_THREAD_INFO_PRIORITY;
417         ret = !wine_server_call_err( req );
418     }
419     SERVER_END_REQ;
420     return ret;
421 }
422
423
424 /**********************************************************************
425  * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
426  *
427  * Always reports that priority boost is disabled.
428  *
429  * RETURNS
430  *    Success: TRUE.
431  *    Failure: FALSE
432  */
433 BOOL WINAPI GetThreadPriorityBoost(
434     HANDLE hthread, /* [in] Handle to thread */
435     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
436 {
437     if (pstate) *pstate = FALSE;
438     return NO_ERROR;
439 }
440
441
442 /**********************************************************************
443  * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
444  *
445  * Priority boost is not implemented. Thsi function always returns
446  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
447  *
448  * RETURNS
449  *    Always returns FALSE to indicate a failure
450  */
451 BOOL WINAPI SetThreadPriorityBoost(
452     HANDLE hthread, /* [in] Handle to thread */
453     BOOL disable)   /* [in] TRUE to disable priority boost */
454 {
455     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
456     return FALSE;
457 }
458
459
460 /**********************************************************************
461  *           SetThreadAffinityMask   (KERNEL32.@)
462  */
463 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
464 {
465     DWORD ret;
466     SERVER_START_REQ( set_thread_info )
467     {
468         req->handle   = hThread;
469         req->affinity = dwThreadAffinityMask;
470         req->mask     = SET_THREAD_INFO_AFFINITY;
471         ret = !wine_server_call_err( req );
472         /* FIXME: should return previous value */
473     }
474     SERVER_END_REQ;
475     return ret;
476 }
477
478
479 /**********************************************************************
480  * SetThreadIdealProcessor [KERNEL32.@]  Obtains timing information.
481  *
482  * RETURNS
483  *    Success: Value of last call to SetThreadIdealProcessor
484  *    Failure: -1
485  */
486 DWORD WINAPI SetThreadIdealProcessor(
487     HANDLE hThread,          /* [in] Specifies the thread of interest */
488     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
489 {
490     FIXME("(%p): stub\n",hThread);
491     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
492     return -1L;
493 }
494
495
496 /* callback for QueueUserAPC */
497 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
498 {
499     PAPCFUNC func = (PAPCFUNC)arg1;
500     func( arg2 );
501 }
502
503 /***********************************************************************
504  *              QueueUserAPC  (KERNEL32.@)
505  */
506 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
507 {
508     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
509
510     if (status) SetLastError( RtlNtStatusToDosError(status) );
511     return !status;
512 }
513
514
515 /**********************************************************************
516  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
517  *
518  * RETURNS
519  *    Success: TRUE
520  *    Failure: FALSE
521  */
522 BOOL WINAPI GetThreadTimes(
523     HANDLE thread,         /* [in]  Specifies the thread of interest */
524     LPFILETIME creationtime, /* [out] When the thread was created */
525     LPFILETIME exittime,     /* [out] When the thread was destroyed */
526     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
527     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
528 {
529     BOOL ret = TRUE;
530
531     if (creationtime || exittime)
532     {
533         /* We need to do a server call to get the creation time or exit time */
534         /* This works on any thread */
535
536         SERVER_START_REQ( get_thread_info )
537         {
538             req->handle = thread;
539             req->tid_in = 0;
540             if ((ret = !wine_server_call_err( req )))
541             {
542                 if (creationtime)
543                     RtlSecondsSince1970ToTime( reply->creation_time, (LARGE_INTEGER*)creationtime );
544                 if (exittime)
545                     RtlSecondsSince1970ToTime( reply->exit_time, (LARGE_INTEGER*)exittime );
546             }
547         }
548         SERVER_END_REQ;
549     }
550     if (ret && (kerneltime || usertime))
551     {
552         /* We call times(2) for kernel time or user time */
553         /* We can only (portably) do this for the current thread */
554         if (thread == GetCurrentThread())
555         {
556             ULONGLONG time;
557             struct tms time_buf;
558             long clocks_per_sec = sysconf(_SC_CLK_TCK);
559
560             times(&time_buf);
561             if (kerneltime)
562             {
563                 time = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
564                 kerneltime->dwHighDateTime = time >> 32;
565                 kerneltime->dwLowDateTime = (DWORD)time;
566             }
567             if (usertime)
568             {
569                 time = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
570                 usertime->dwHighDateTime = time >> 32;
571                 usertime->dwLowDateTime = (DWORD)time;
572             }
573         }
574         else
575         {
576             if (kerneltime) kerneltime->dwHighDateTime = kerneltime->dwLowDateTime = 0;
577             if (usertime) usertime->dwHighDateTime = usertime->dwLowDateTime = 0;
578             FIXME("Cannot get kerneltime or usertime of other threads\n");
579         }
580     }
581     return ret;
582 }
583
584
585 /**********************************************************************
586  * VWin32_BoostThreadGroup [KERNEL.535]
587  */
588 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
589 {
590     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
591 }
592
593
594 /**********************************************************************
595  * VWin32_BoostThreadStatic [KERNEL.536]
596  */
597 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
598 {
599     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
600 }
601
602
603 /***********************************************************************
604  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
605  *
606  * RETURNS
607  *    Pseudohandle for the current thread
608  */
609 #undef GetCurrentThread
610 HANDLE WINAPI GetCurrentThread(void)
611 {
612     return (HANDLE)0xfffffffe;
613 }
614
615
616 #ifdef __i386__
617
618 /***********************************************************************
619  *              SetLastError (KERNEL.147)
620  *              SetLastError (KERNEL32.@)
621  */
622 /* void WINAPI SetLastError( DWORD error ); */
623 __ASM_GLOBAL_FUNC( SetLastError,
624                    "movl 4(%esp),%eax\n\t"
625                    ".byte 0x64\n\t"
626                    "movl %eax,0x34\n\t"
627                    "ret $4" );
628
629 /***********************************************************************
630  *              GetLastError (KERNEL.148)
631  *              GetLastError (KERNEL32.@)
632  */
633 /* DWORD WINAPI GetLastError(void); */
634 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" );
635
636 /***********************************************************************
637  *              GetCurrentProcessId (KERNEL.471)
638  *              GetCurrentProcessId (KERNEL32.@)
639  */
640 /* DWORD WINAPI GetCurrentProcessId(void) */
641 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
642
643 /***********************************************************************
644  *              GetCurrentThreadId (KERNEL.462)
645  *              GetCurrentThreadId (KERNEL32.@)
646  */
647 /* DWORD WINAPI GetCurrentThreadId(void) */
648 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
649
650 #else  /* __i386__ */
651
652 /**********************************************************************
653  *              SetLastError (KERNEL.147)
654  *              SetLastError (KERNEL32.@)
655  *
656  * Sets the last-error code.
657  */
658 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
659 {
660     NtCurrentTeb()->LastErrorValue = error;
661 }
662
663 /**********************************************************************
664  *              GetLastError (KERNEL.148)
665  *              GetLastError (KERNEL32.@)
666  *
667  * Returns last-error code.
668  */
669 DWORD WINAPI GetLastError(void)
670 {
671     return NtCurrentTeb()->LastErrorValue;
672 }
673
674 /***********************************************************************
675  *              GetCurrentProcessId (KERNEL.471)
676  *              GetCurrentProcessId (KERNEL32.@)
677  *
678  * Returns process identifier.
679  */
680 DWORD WINAPI GetCurrentProcessId(void)
681 {
682     return (DWORD)NtCurrentTeb()->ClientId.UniqueProcess;
683 }
684
685 /***********************************************************************
686  *              GetCurrentThreadId (KERNEL.462)
687  *              GetCurrentThreadId (KERNEL32.@)
688  *
689  * Returns thread identifier.
690  */
691 DWORD WINAPI GetCurrentThreadId(void)
692 {
693     return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
694 }
695
696 #endif  /* __i386__ */