Moved the remaining SYSDEPS_* functions to the wine_pthread interface.
[wine] / dlls / ntdll / thread.c
1 /*
2  * NT threads support
3  *
4  * Copyright 1996, 2003 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 <sys/types.h>
25 #ifdef HAVE_SYS_MMAN_H
26 #include <sys/mman.h>
27 #endif
28
29 #include "ntstatus.h"
30 #include "thread.h"
31 #include "winternl.h"
32 #include "wine/library.h"
33 #include "wine/server.h"
34 #include "wine/pthread.h"
35 #include "wine/debug.h"
36 #include "ntdll_misc.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(thread);
39
40 static PEB peb;
41 static PEB_LDR_DATA ldr;
42 static RTL_USER_PROCESS_PARAMETERS params;  /* default parameters if no parent */
43 static RTL_BITMAP tls_bitmap;
44 static LIST_ENTRY tls_links;
45
46
47 /***********************************************************************
48  *           alloc_teb
49  */
50 static TEB *alloc_teb( ULONG *size )
51 {
52     TEB *teb;
53
54     *size = SIGNAL_STACK_SIZE + sizeof(TEB);
55     teb = wine_anon_mmap( NULL, *size, PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
56     if (teb == (TEB *)-1) return NULL;
57     if (!(teb->teb_sel = wine_ldt_alloc_fs()))
58     {
59         munmap( teb, *size );
60         return NULL;
61     }
62     teb->Tib.ExceptionList = (void *)~0UL;
63     teb->Tib.StackBase     = (void *)~0UL;
64     teb->Tib.Self          = &teb->Tib;
65     teb->Peb               = &peb;
66     teb->StaticUnicodeString.Buffer        = teb->StaticUnicodeBuffer;
67     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
68     return teb;
69 }
70
71
72 /***********************************************************************
73  *           free_teb
74  */
75 static inline void free_teb( TEB *teb )
76 {
77     ULONG size = 0;
78     void *addr = teb;
79
80     NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
81     wine_ldt_free_fs( teb->teb_sel );
82     munmap( teb, SIGNAL_STACK_SIZE + sizeof(TEB) );
83 }
84
85
86 /***********************************************************************
87  *           thread_init
88  *
89  * Setup the initial thread.
90  *
91  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
92  */
93 void thread_init(void)
94 {
95     TEB *teb;
96     void *addr;
97     ULONG size;
98     struct wine_pthread_thread_info thread_info;
99     static struct debug_info debug_info;  /* debug info for initial thread */
100
101     debug_info.str_pos = debug_info.strings;
102     debug_info.out_pos = debug_info.output;
103
104     peb.ProcessParameters = &params;
105     peb.TlsBitmap         = &tls_bitmap;
106     peb.LdrData           = &ldr;
107     RtlInitializeBitMap( &tls_bitmap, (BYTE *)peb.TlsBitmapBits, sizeof(peb.TlsBitmapBits) * 8 );
108     InitializeListHead( &ldr.InLoadOrderModuleList );
109     InitializeListHead( &ldr.InMemoryOrderModuleList );
110     InitializeListHead( &ldr.InInitializationOrderModuleList );
111     InitializeListHead( &tls_links );
112
113     teb = alloc_teb( &size );
114     teb->tibflags      = TEBF_WIN32;
115     teb->request_fd    = -1;
116     teb->reply_fd      = -1;
117     teb->wait_fd[0]    = -1;
118     teb->wait_fd[1]    = -1;
119     teb->debug_info    = &debug_info;
120     InsertHeadList( &tls_links, &teb->TlsLinks );
121
122     thread_info.stack_base = NULL;
123     thread_info.stack_size = 0;
124     thread_info.teb_base   = teb;
125     thread_info.teb_size   = size;
126     thread_info.teb_sel    = teb->teb_sel;
127     wine_pthread_init_thread( &thread_info );
128
129     /* setup the server connection */
130     server_init_process();
131     server_init_thread( thread_info.pid, thread_info.tid );
132
133     /* create a memory view for the TEB */
134     NtAllocateVirtualMemory( GetCurrentProcess(), &addr, teb, &size,
135                              MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
136
137     /* create the process heap */
138     if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
139     {
140         MESSAGE( "wine: failed to create the process heap\n" );
141         exit(1);
142     }
143 }
144
145
146 /***********************************************************************
147  *           start_thread
148  *
149  * Startup routine for a newly created thread.
150  */
151 static void start_thread( struct wine_pthread_thread_info *info )
152 {
153     TEB *teb = info->teb_base;
154     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
155     struct debug_info debug_info;
156     ULONG size;
157
158     debug_info.str_pos = debug_info.strings;
159     debug_info.out_pos = debug_info.output;
160     teb->debug_info = &debug_info;
161
162     wine_pthread_init_thread( info );
163     SIGNAL_Init();
164     server_init_thread( info->pid, info->tid );
165
166     /* allocate a memory view for the stack */
167     size = info->stack_size;
168     NtAllocateVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, info->stack_base,
169                              &size, MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
170     /* limit is lower than base since the stack grows down */
171     teb->Tib.StackBase  = (char *)info->stack_base + info->stack_size;
172     teb->Tib.StackLimit = info->stack_base;
173
174     /* setup the guard page */
175     size = 1;
176     NtProtectVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size,
177                             PAGE_EXECUTE_READWRITE | PAGE_GUARD, NULL );
178     RtlFreeHeap( GetProcessHeap(), 0, info );
179
180     RtlAcquirePebLock();
181     InsertHeadList( &tls_links, &teb->TlsLinks );
182     RtlReleasePebLock();
183
184     NtTerminateThread( GetCurrentThread(), func( NtCurrentTeb()->entry_arg ) );
185 }
186
187
188 /***********************************************************************
189  *              RtlCreateUserThread   (NTDLL.@)
190  */
191 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
192                                      BOOLEAN suspended, PVOID stack_addr,
193                                      SIZE_T stack_reserve, SIZE_T stack_commit,
194                                      PRTL_THREAD_START_ROUTINE start, void *param,
195                                      HANDLE *handle_ptr, CLIENT_ID *id )
196 {
197     struct wine_pthread_thread_info *info = NULL;
198     HANDLE handle = 0;
199     TEB *teb = NULL;
200     DWORD tid = 0;
201     ULONG size;
202     int request_pipe[2];
203     NTSTATUS status;
204
205     if (pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
206     fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
207     wine_server_send_fd( request_pipe[0] );
208
209     SERVER_START_REQ( new_thread )
210     {
211         req->suspend    = suspended;
212         req->inherit    = 0;  /* FIXME */
213         req->request_fd = request_pipe[0];
214         if (!(status = wine_server_call( req )))
215         {
216             handle = reply->handle;
217             tid = reply->tid;
218         }
219         close( request_pipe[0] );
220     }
221     SERVER_END_REQ;
222
223     if (status) goto error;
224
225     if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
226     {
227         status = STATUS_NO_MEMORY;
228         goto error;
229     }
230
231     if (!(teb = alloc_teb( &size )))
232     {
233         status = STATUS_NO_MEMORY;
234         goto error;
235     }
236     teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
237     teb->ClientId.UniqueThread  = (HANDLE)tid;
238
239     teb->tibflags    = TEBF_WIN32;
240     teb->exit_code   = STILL_ACTIVE;
241     teb->request_fd  = request_pipe[1];
242     teb->reply_fd    = -1;
243     teb->wait_fd[0]  = -1;
244     teb->wait_fd[1]  = -1;
245     teb->entry_point = start;
246     teb->entry_arg   = param;
247     teb->htask16     = NtCurrentTeb()->htask16;
248
249     NtAllocateVirtualMemory( GetCurrentProcess(), &info->teb_base, teb, &size,
250                              MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
251     info->teb_size = size;
252     info->teb_sel  = teb->teb_sel;
253
254     if (!stack_reserve || !stack_commit)
255     {
256         IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
257         if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
258         if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
259     }
260     if (stack_reserve < stack_commit) stack_reserve = stack_commit;
261     stack_reserve = (stack_reserve + 0xffff) & ~0xffff;  /* round to 64K boundary */
262
263     info->stack_base = NULL;
264     info->stack_size = stack_reserve;
265     info->entry      = start_thread;
266
267     if (wine_pthread_create_thread( info ) == -1)
268     {
269         status = STATUS_NO_MEMORY;
270         goto error;
271     }
272
273     if (id) id->UniqueThread = (HANDLE)tid;
274     if (handle_ptr) *handle_ptr = handle;
275     else NtClose( handle );
276
277     return STATUS_SUCCESS;
278
279 error:
280     if (teb) free_teb( teb );
281     if (info) RtlFreeHeap( GetProcessHeap(), 0, info );
282     if (handle) NtClose( handle );
283     close( request_pipe[1] );
284     return status;
285 }
286
287
288 /***********************************************************************
289  *              NtOpenThread   (NTDLL.@)
290  *              ZwOpenThread   (NTDLL.@)
291  */
292 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
293                               const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
294 {
295     NTSTATUS ret;
296
297     SERVER_START_REQ( open_thread )
298     {
299         req->tid     = (thread_id_t)id->UniqueThread;
300         req->access  = access;
301         req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
302         ret = wine_server_call( req );
303         *handle = reply->handle;
304     }
305     SERVER_END_REQ;
306     return ret;
307 }
308
309
310 /******************************************************************************
311  *              NtSuspendThread   (NTDLL.@)
312  *              ZwSuspendThread   (NTDLL.@)
313  */
314 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
315 {
316     NTSTATUS ret;
317
318     SERVER_START_REQ( suspend_thread )
319     {
320         req->handle = handle;
321         if (!(ret = wine_server_call( req ))) *count = reply->count;
322     }
323     SERVER_END_REQ;
324     return ret;
325 }
326
327
328 /******************************************************************************
329  *              NtResumeThread   (NTDLL.@)
330  *              ZwResumeThread   (NTDLL.@)
331  */
332 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
333 {
334     NTSTATUS ret;
335
336     SERVER_START_REQ( resume_thread )
337     {
338         req->handle = handle;
339         if (!(ret = wine_server_call( req ))) *count = reply->count;
340     }
341     SERVER_END_REQ;
342     return ret;
343 }
344
345
346 /******************************************************************************
347  *              NtTerminateThread  (NTDLL.@)
348  *              ZwTerminateThread  (NTDLL.@)
349  */
350 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
351 {
352     NTSTATUS ret;
353     BOOL self, last;
354
355     SERVER_START_REQ( terminate_thread )
356     {
357         req->handle    = handle;
358         req->exit_code = exit_code;
359         ret = wine_server_call( req );
360         self = !ret && reply->self;
361         last = reply->last;
362     }
363     SERVER_END_REQ;
364
365     if (self)
366     {
367         if (last) exit( exit_code );
368         else server_abort_thread( exit_code );
369     }
370     return ret;
371 }
372
373
374 /******************************************************************************
375  *              NtQueueApcThread  (NTDLL.@)
376  */
377 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
378                                   ULONG_PTR arg2, ULONG_PTR arg3 )
379 {
380     NTSTATUS ret;
381     SERVER_START_REQ( queue_apc )
382     {
383         req->handle = handle;
384         req->user   = 1;
385         req->func   = func;
386         req->arg1   = (void *)arg1;
387         req->arg2   = (void *)arg2;
388         req->arg3   = (void *)arg3;
389         ret = wine_server_call( req );
390     }
391     SERVER_END_REQ;
392     return ret;
393 }
394
395
396 /***********************************************************************
397  *              NtSetContextThread  (NTDLL.@)
398  *              ZwSetContextThread  (NTDLL.@)
399  */
400 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
401 {
402     NTSTATUS ret;
403
404     SERVER_START_REQ( set_thread_context )
405     {
406         req->handle = handle;
407         req->flags  = context->ContextFlags;
408         wine_server_add_data( req, context, sizeof(*context) );
409         ret = wine_server_call( req );
410     }
411     SERVER_END_REQ;
412     return ret;
413 }
414
415
416 /***********************************************************************
417  *              NtGetContextThread  (NTDLL.@)
418  *              ZwGetContextThread  (NTDLL.@)
419  */
420 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
421 {
422     NTSTATUS ret;
423
424     SERVER_START_REQ( get_thread_context )
425     {
426         req->handle = handle;
427         req->flags = context->ContextFlags;
428         wine_server_add_data( req, context, sizeof(*context) );
429         wine_server_set_reply( req, context, sizeof(*context) );
430         ret = wine_server_call( req );
431     }
432     SERVER_END_REQ;
433     return ret;
434 }
435
436
437 /******************************************************************************
438  *              NtQueryInformationThread  (NTDLL.@)
439  *              ZwQueryInformationThread  (NTDLL.@)
440  */
441 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
442                                           void *data, ULONG length, ULONG *ret_len )
443 {
444     NTSTATUS status;
445
446     switch(class)
447     {
448     case ThreadBasicInformation:
449         {
450             THREAD_BASIC_INFORMATION info;
451
452             SERVER_START_REQ( get_thread_info )
453             {
454                 req->handle = handle;
455                 req->tid_in = 0;
456                 if (!(status = wine_server_call( req )))
457                 {
458                     info.ExitStatus             = reply->exit_code;
459                     info.TebBaseAddress         = reply->teb;
460                     info.ClientId.UniqueProcess = (HANDLE)reply->pid;
461                     info.ClientId.UniqueThread  = (HANDLE)reply->tid;
462                     info.AffinityMask           = reply->affinity;
463                     info.Priority               = reply->priority;
464                     info.BasePriority           = reply->priority;  /* FIXME */
465                 }
466             }
467             SERVER_END_REQ;
468             if (status == STATUS_SUCCESS)
469             {
470                 if (data) memcpy( data, &info, min( length, sizeof(info) ));
471                 if (ret_len) *ret_len = min( length, sizeof(info) );
472             }
473         }
474         return status;
475     case ThreadTimes:
476     case ThreadPriority:
477     case ThreadBasePriority:
478     case ThreadAffinityMask:
479     case ThreadImpersonationToken:
480     case ThreadDescriptorTableEntry:
481     case ThreadEnableAlignmentFaultFixup:
482     case ThreadEventPair_Reusable:
483     case ThreadQuerySetWin32StartAddress:
484     case ThreadZeroTlsCell:
485     case ThreadPerformanceCount:
486     case ThreadAmILastThread:
487     case ThreadIdealProcessor:
488     case ThreadPriorityBoost:
489     case ThreadSetTlsArrayAddress:
490     case ThreadIsIoPending:
491     default:
492         FIXME( "info class %d not supported yet\n", class );
493         return STATUS_NOT_IMPLEMENTED;
494     }
495 }
496
497
498 /******************************************************************************
499  *              NtSetInformationThread  (NTDLL.@)
500  *              ZwSetInformationThread  (NTDLL.@)
501  */
502 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
503                                         LPCVOID data, ULONG length )
504 {
505     switch(class)
506     {
507     case ThreadZeroTlsCell:
508         if (handle == GetCurrentThread())
509         {
510             LIST_ENTRY *entry;
511             DWORD index;
512
513             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
514             index = *(DWORD *)data;
515             if (index >= 64) return STATUS_INVALID_PARAMETER;
516             RtlAcquirePebLock();
517             for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
518             {
519                 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
520                 teb->TlsSlots[index] = 0;
521             }
522             RtlReleasePebLock();
523             return STATUS_SUCCESS;
524         }
525         FIXME( "ZeroTlsCell not supported on other threads\n" );
526         return STATUS_NOT_IMPLEMENTED;
527
528     case ThreadBasicInformation:
529     case ThreadTimes:
530     case ThreadPriority:
531     case ThreadBasePriority:
532     case ThreadAffinityMask:
533     case ThreadImpersonationToken:
534     case ThreadDescriptorTableEntry:
535     case ThreadEnableAlignmentFaultFixup:
536     case ThreadEventPair_Reusable:
537     case ThreadQuerySetWin32StartAddress:
538     case ThreadPerformanceCount:
539     case ThreadAmILastThread:
540     case ThreadIdealProcessor:
541     case ThreadPriorityBoost:
542     case ThreadSetTlsArrayAddress:
543     case ThreadIsIoPending:
544     default:
545         FIXME( "info class %d not supported yet\n", class );
546         return STATUS_NOT_IMPLEMENTED;
547     }
548 }
549
550
551 /**********************************************************************
552  *           NtCurrentTeb   (NTDLL.@)
553  */
554 #if defined(__i386__) && defined(__GNUC__)
555 __ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
556 #elif defined(__i386__) && defined(_MSC_VER)
557 /* Nothing needs to be done. MS C "magically" exports the inline version from winnt.h */
558 #else
559 TEB * WINAPI NtCurrentTeb(void)
560 {
561     return wine_pthread_get_current_teb();
562 }
563 #endif  /* __i386__ */