Fix testing example.
[wine] / scheduler / 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 <sys/types.h>
27 #ifdef HAVE_SYS_MMAN_H
28 #include <sys/mman.h>
29 #endif
30 #ifdef HAVE_SYS_TIMES_H
31 #include <sys/times.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include "wine/winbase16.h"
37 #include "thread.h"
38 #include "module.h"
39 #include "winerror.h"
40 #include "selectors.h"
41 #include "winnt.h"
42 #include "wine/server.h"
43 #include "wine/debug.h"
44 #include "winnls.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(thread);
47 WINE_DECLARE_DEBUG_CHANNEL(relay);
48
49 /* TEB of the initial thread */
50 static TEB initial_teb;
51
52 extern struct _PDB current_process;
53
54 /***********************************************************************
55  *           THREAD_InitTEB
56  *
57  * Initialization of a newly created TEB.
58  */
59 static BOOL THREAD_InitTEB( TEB *teb )
60 {
61     teb->Tib.ExceptionList = (void *)~0UL;
62     teb->Tib.StackBase     = (void *)~0UL;
63     teb->Tib.Self          = &teb->Tib;
64     teb->tibflags  = TEBF_WIN32;
65     teb->exit_code = STILL_ACTIVE;
66     teb->request_fd = -1;
67     teb->reply_fd   = -1;
68     teb->wait_fd[0] = -1;
69     teb->wait_fd[1] = -1;
70     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
71     teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
72     teb->teb_sel = wine_ldt_alloc_fs();
73     return (teb->teb_sel != 0);
74 }
75
76
77 /***********************************************************************
78  *           THREAD_FreeTEB
79  *
80  * Free data structures associated with a thread.
81  * Must be called from the context of another thread.
82  */
83 static void THREAD_FreeTEB( TEB *teb )
84 {
85     TRACE("(%p) called\n", teb );
86     /* Free the associated memory */
87     wine_ldt_free_fs( teb->teb_sel );
88     VirtualFree( teb->DeallocationStack, 0, MEM_RELEASE );
89 }
90
91
92 /***********************************************************************
93  *           THREAD_InitStack
94  *
95  * Allocate the stack of a thread.
96  */
97 TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
98 {
99     DWORD old_prot, total_size;
100     DWORD page_size = getpagesize();
101     void *base;
102
103     /* Allocate the stack */
104
105     if (stack_size >= 16*1024*1024)
106         WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024);
107
108     /* if size is smaller than default, get stack size from parent */
109     if (stack_size < 1024 * 1024)
110     {
111         if (teb)
112             stack_size = 1024 * 1024;  /* no parent */
113         else
114             stack_size = ((char *)NtCurrentTeb()->Tib.StackBase - (char *)NtCurrentTeb()->DeallocationStack
115                           - SIGNAL_STACK_SIZE - 3 * page_size);
116     }
117
118     /* FIXME: some Wine functions use a lot of stack, so we add 64Kb here */
119     stack_size += 64 * 1024;
120
121     /* Memory layout in allocated block:
122      *
123      *   size                 contents
124      * 1 page              NOACCESS guard page
125      * SIGNAL_STACK_SIZE   signal stack
126      * 1 page              NOACCESS guard page
127      * 1 page              PAGE_GUARD guard page
128      * stack_size          normal stack
129      * 1 page              TEB (except for initial thread)
130      */
131
132     stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
133     total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
134     if (!teb) total_size += page_size;
135
136     if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
137         return NULL;
138
139     if (!teb)
140     {
141         teb = (TEB *)((char *)base + total_size - page_size);
142         if (!THREAD_InitTEB( teb ))
143         {
144             VirtualFree( base, 0, MEM_RELEASE );
145             return NULL;
146         }
147     }
148
149     teb->DeallocationStack = base;
150     teb->signal_stack      = (char *)base + page_size;
151     teb->Tib.StackBase     = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size;
152     teb->Tib.StackLimit    = base;  /* note: limit is lower than base since the stack grows down */
153
154     /* Setup guard pages */
155
156     VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot );
157     VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot );
158     VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1,
159                     PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
160     return teb;
161 }
162
163
164 /***********************************************************************
165  *           THREAD_Init
166  *
167  * Setup the initial thread.
168  *
169  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
170  */
171 void THREAD_Init(void)
172 {
173     static struct debug_info info;  /* debug info for initial thread */
174
175     if (!initial_teb.Tib.Self)  /* do it only once */
176     {
177         THREAD_InitTEB( &initial_teb );
178         assert( initial_teb.teb_sel );
179         info.str_pos = info.strings;
180         info.out_pos = info.output;
181         initial_teb.debug_info = &info;
182         initial_teb.Peb = (PEB *)&current_process;  /* FIXME */
183         SYSDEPS_SetCurThread( &initial_teb );
184     }
185 }
186
187 DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
188
189
190 /***********************************************************************
191  *           THREAD_Start
192  *
193  * Start execution of a newly created thread. Does not return.
194  */
195 static void THREAD_Start( TEB *teb )
196 {
197     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
198     struct debug_info info;
199
200     info.str_pos = info.strings;
201     info.out_pos = info.output;
202     teb->debug_info = &info;
203
204     SYSDEPS_SetCurThread( teb );
205     SIGNAL_Init();
206     CLIENT_InitThread();
207
208     if (TRACE_ON(relay))
209         DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
210
211     __TRY
212     {
213         MODULE_DllThreadAttach( NULL );
214         ExitThread( func( NtCurrentTeb()->entry_arg ) );
215     }
216     __EXCEPT(UnhandledExceptionFilter)
217     {
218         TerminateThread( GetCurrentThread(), GetExceptionCode() );
219     }
220     __ENDTRY
221 }
222
223
224 /***********************************************************************
225  *           CreateThread   (KERNEL32.@)
226  */
227 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
228                             LPTHREAD_START_ROUTINE start, LPVOID param,
229                             DWORD flags, LPDWORD id )
230 {
231     HANDLE handle = 0;
232     TEB *teb;
233     DWORD tid = 0;
234     int request_pipe[2];
235
236     if (pipe( request_pipe ) == -1)
237     {
238         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
239         return 0;
240     }
241     fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
242     wine_server_send_fd( request_pipe[0] );
243
244     SERVER_START_REQ( new_thread )
245     {
246         req->suspend    = ((flags & CREATE_SUSPENDED) != 0);
247         req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
248         req->request_fd = request_pipe[0];
249         if (!wine_server_call_err( req ))
250         {
251             handle = reply->handle;
252             tid = reply->tid;
253         }
254         close( request_pipe[0] );
255     }
256     SERVER_END_REQ;
257
258     if (!handle || !(teb = THREAD_InitStack( NULL, stack )))
259     {
260         close( request_pipe[1] );
261         return 0;
262     }
263
264     teb->Peb         = NtCurrentTeb()->Peb;
265     teb->ClientId.UniqueThread = (HANDLE)tid;
266     teb->request_fd  = request_pipe[1];
267     teb->entry_point = start;
268     teb->entry_arg   = param;
269     teb->htask16     = GetCurrentTask();
270
271     if (id) *id = tid;
272     if (SYSDEPS_SpawnThread( THREAD_Start, teb ) == -1)
273     {
274         CloseHandle( handle );
275         close( request_pipe[1] );
276         THREAD_FreeTEB( teb );
277         return 0;
278     }
279     return handle;
280 }
281
282 /***********************************************************************
283  * ExitThread [KERNEL32.@]  Ends a thread
284  *
285  * RETURNS
286  *    None
287  */
288 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
289 {
290     BOOL last;
291     SERVER_START_REQ( terminate_thread )
292     {
293         /* send the exit code to the server */
294         req->handle    = GetCurrentThread();
295         req->exit_code = code;
296         wine_server_call( req );
297         last = reply->last;
298     }
299     SERVER_END_REQ;
300
301     if (last)
302     {
303         LdrShutdownProcess();
304         exit( code );
305     }
306     else
307     {
308         LdrShutdownThread();
309         SYSDEPS_ExitThread( code );
310     }
311 }
312
313 /***********************************************************************
314  * OpenThread Retrieves a handle to a thread from its thread id
315  *
316  * RETURNS
317  *    None
318  */
319 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
320 {
321     HANDLE ret = 0;
322     SERVER_START_REQ( open_thread )
323     {
324         req->tid     = dwThreadId;
325         req->access  = dwDesiredAccess;
326         req->inherit = bInheritHandle;
327         if (!wine_server_call_err( req )) ret = reply->handle;
328     }
329     SERVER_END_REQ;
330     return ret;
331 }
332
333 /**********************************************************************
334  * TerminateThread [KERNEL32.@]  Terminates a thread
335  *
336  * RETURNS
337  *    Success: TRUE
338  *    Failure: FALSE
339  */
340 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
341                              DWORD exit_code)  /* [in] Exit code for thread */
342 {
343     NTSTATUS status = NtTerminateThread( handle, exit_code );
344     if (status) SetLastError( RtlNtStatusToDosError(status) );
345     return !status;
346 }
347
348
349 /**********************************************************************
350  *              GetExitCodeThread (KERNEL32.@)
351  *
352  * Gets termination status of thread.
353  *
354  * RETURNS
355  *    Success: TRUE
356  *    Failure: FALSE
357  */
358 BOOL WINAPI GetExitCodeThread(
359     HANDLE hthread, /* [in]  Handle to thread */
360     LPDWORD exitcode) /* [out] Address to receive termination status */
361 {
362     THREAD_BASIC_INFORMATION info;
363     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
364                                                 &info, sizeof(info), NULL );
365
366     if (status)
367     {
368         SetLastError( RtlNtStatusToDosError(status) );
369         return FALSE;
370     }
371     if (exitcode) *exitcode = info.ExitStatus;
372     return TRUE;
373 }
374
375
376 /* callback for QueueUserAPC */
377 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
378 {
379     PAPCFUNC func = (PAPCFUNC)arg1;
380     func( arg2 );
381 }
382
383 /***********************************************************************
384  *              QueueUserAPC  (KERNEL32.@)
385  */
386 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
387 {
388     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
389
390     if (status) SetLastError( RtlNtStatusToDosError(status) );
391     return !status;
392 }
393
394
395 /***********************************************************************
396  * ProcessIdToSessionId   (KERNEL32.@)
397  * This function is available on Terminal Server 4SP4 and Windows 2000
398  */
399 BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
400 {
401         /* According to MSDN, if the calling process is not in a terminal
402          * services environment, then the sessionid returned is zero.
403          */
404         *sessionid_ptr = 0;
405         return TRUE;
406 }
407
408
409 #ifdef __i386__
410
411 /***********************************************************************
412  *              SetLastError (KERNEL.147)
413  *              SetLastError (KERNEL32.@)
414  */
415 /* void WINAPI SetLastError( DWORD error ); */
416 __ASM_GLOBAL_FUNC( SetLastError,
417                    "movl 4(%esp),%eax\n\t"
418                    ".byte 0x64\n\t"
419                    "movl %eax,0x60\n\t"
420                    "ret $4" );
421
422 /***********************************************************************
423  *              GetLastError (KERNEL.148)
424  *              GetLastError (KERNEL32.@)
425  */
426 /* DWORD WINAPI GetLastError(void); */
427 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
428
429 /***********************************************************************
430  *              GetCurrentProcessId (KERNEL.471)
431  *              GetCurrentProcessId (KERNEL32.@)
432  */
433 /* DWORD WINAPI GetCurrentProcessId(void) */
434 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
435
436 /***********************************************************************
437  *              GetCurrentThreadId (KERNEL.462)
438  *              GetCurrentThreadId (KERNEL32.@)
439  */
440 /* DWORD WINAPI GetCurrentThreadId(void) */
441 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
442
443 #else  /* __i386__ */
444
445 /**********************************************************************
446  *              SetLastError (KERNEL.147)
447  *              SetLastError (KERNEL32.@)
448  *
449  * Sets the last-error code.
450  */
451 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
452 {
453     NtCurrentTeb()->last_error = error;
454 }
455
456 /**********************************************************************
457  *              GetLastError (KERNEL.148)
458  *              GetLastError (KERNEL32.@)
459  *
460  * Returns last-error code.
461  */
462 DWORD WINAPI GetLastError(void)
463 {
464     return NtCurrentTeb()->last_error;
465 }
466
467 /***********************************************************************
468  *              GetCurrentProcessId (KERNEL.471)
469  *              GetCurrentProcessId (KERNEL32.@)
470  *
471  * Returns process identifier.
472  */
473 DWORD WINAPI GetCurrentProcessId(void)
474 {
475     return (DWORD)NtCurrentTeb()->ClientId.UniqueProcess;
476 }
477
478 /***********************************************************************
479  *              GetCurrentThreadId (KERNEL.462)
480  *              GetCurrentThreadId (KERNEL32.@)
481  *
482  * Returns thread identifier.
483  */
484 DWORD WINAPI GetCurrentThreadId(void)
485 {
486     return (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
487 }
488
489 #endif  /* __i386__ */