If using the default values, also set dwType to REG_SZ as our default
[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     if (stack_reserve < 1024 * 1024) stack_reserve = 1024 * 1024;  /* Xlib needs a large stack */
263
264     info->stack_base = NULL;
265     info->stack_size = stack_reserve;
266     info->entry      = start_thread;
267
268     if (wine_pthread_create_thread( info ) == -1)
269     {
270         status = STATUS_NO_MEMORY;
271         goto error;
272     }
273
274     if (id) id->UniqueThread = (HANDLE)tid;
275     if (handle_ptr) *handle_ptr = handle;
276     else NtClose( handle );
277
278     return STATUS_SUCCESS;
279
280 error:
281     if (teb) free_teb( teb );
282     if (info) RtlFreeHeap( GetProcessHeap(), 0, info );
283     if (handle) NtClose( handle );
284     close( request_pipe[1] );
285     return status;
286 }
287
288
289 /***********************************************************************
290  *              NtOpenThread   (NTDLL.@)
291  *              ZwOpenThread   (NTDLL.@)
292  */
293 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
294                               const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
295 {
296     NTSTATUS ret;
297
298     SERVER_START_REQ( open_thread )
299     {
300         req->tid     = (thread_id_t)id->UniqueThread;
301         req->access  = access;
302         req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
303         ret = wine_server_call( req );
304         *handle = reply->handle;
305     }
306     SERVER_END_REQ;
307     return ret;
308 }
309
310
311 /******************************************************************************
312  *              NtSuspendThread   (NTDLL.@)
313  *              ZwSuspendThread   (NTDLL.@)
314  */
315 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
316 {
317     NTSTATUS ret;
318
319     SERVER_START_REQ( suspend_thread )
320     {
321         req->handle = handle;
322         if (!(ret = wine_server_call( req ))) *count = reply->count;
323     }
324     SERVER_END_REQ;
325     return ret;
326 }
327
328
329 /******************************************************************************
330  *              NtResumeThread   (NTDLL.@)
331  *              ZwResumeThread   (NTDLL.@)
332  */
333 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
334 {
335     NTSTATUS ret;
336
337     SERVER_START_REQ( resume_thread )
338     {
339         req->handle = handle;
340         if (!(ret = wine_server_call( req ))) *count = reply->count;
341     }
342     SERVER_END_REQ;
343     return ret;
344 }
345
346
347 /******************************************************************************
348  *              NtTerminateThread  (NTDLL.@)
349  *              ZwTerminateThread  (NTDLL.@)
350  */
351 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
352 {
353     NTSTATUS ret;
354     BOOL self, last;
355
356     SERVER_START_REQ( terminate_thread )
357     {
358         req->handle    = handle;
359         req->exit_code = exit_code;
360         ret = wine_server_call( req );
361         self = !ret && reply->self;
362         last = reply->last;
363     }
364     SERVER_END_REQ;
365
366     if (self)
367     {
368         if (last) exit( exit_code );
369         else server_abort_thread( exit_code );
370     }
371     return ret;
372 }
373
374
375 /******************************************************************************
376  *              NtQueueApcThread  (NTDLL.@)
377  */
378 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
379                                   ULONG_PTR arg2, ULONG_PTR arg3 )
380 {
381     NTSTATUS ret;
382     SERVER_START_REQ( queue_apc )
383     {
384         req->handle = handle;
385         req->user   = 1;
386         req->func   = func;
387         req->arg1   = (void *)arg1;
388         req->arg2   = (void *)arg2;
389         req->arg3   = (void *)arg3;
390         ret = wine_server_call( req );
391     }
392     SERVER_END_REQ;
393     return ret;
394 }
395
396
397 /***********************************************************************
398  *              NtSetContextThread  (NTDLL.@)
399  *              ZwSetContextThread  (NTDLL.@)
400  */
401 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
402 {
403     NTSTATUS ret;
404
405     SERVER_START_REQ( set_thread_context )
406     {
407         req->handle = handle;
408         req->flags  = context->ContextFlags;
409         wine_server_add_data( req, context, sizeof(*context) );
410         ret = wine_server_call( req );
411     }
412     SERVER_END_REQ;
413     return ret;
414 }
415
416
417 /***********************************************************************
418  *              NtGetContextThread  (NTDLL.@)
419  *              ZwGetContextThread  (NTDLL.@)
420  */
421 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
422 {
423     NTSTATUS ret;
424
425     SERVER_START_REQ( get_thread_context )
426     {
427         req->handle = handle;
428         req->flags = context->ContextFlags;
429         wine_server_add_data( req, context, sizeof(*context) );
430         wine_server_set_reply( req, context, sizeof(*context) );
431         ret = wine_server_call( req );
432     }
433     SERVER_END_REQ;
434     return ret;
435 }
436
437
438 /******************************************************************************
439  *              NtQueryInformationThread  (NTDLL.@)
440  *              ZwQueryInformationThread  (NTDLL.@)
441  */
442 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
443                                           void *data, ULONG length, ULONG *ret_len )
444 {
445     NTSTATUS status;
446
447     switch(class)
448     {
449     case ThreadBasicInformation:
450         {
451             THREAD_BASIC_INFORMATION info;
452
453             SERVER_START_REQ( get_thread_info )
454             {
455                 req->handle = handle;
456                 req->tid_in = 0;
457                 if (!(status = wine_server_call( req )))
458                 {
459                     info.ExitStatus             = reply->exit_code;
460                     info.TebBaseAddress         = reply->teb;
461                     info.ClientId.UniqueProcess = (HANDLE)reply->pid;
462                     info.ClientId.UniqueThread  = (HANDLE)reply->tid;
463                     info.AffinityMask           = reply->affinity;
464                     info.Priority               = reply->priority;
465                     info.BasePriority           = reply->priority;  /* FIXME */
466                 }
467             }
468             SERVER_END_REQ;
469             if (status == STATUS_SUCCESS)
470             {
471                 if (data) memcpy( data, &info, min( length, sizeof(info) ));
472                 if (ret_len) *ret_len = min( length, sizeof(info) );
473             }
474         }
475         return status;
476     case ThreadTimes:
477     case ThreadPriority:
478     case ThreadBasePriority:
479     case ThreadAffinityMask:
480     case ThreadImpersonationToken:
481     case ThreadDescriptorTableEntry:
482     case ThreadEnableAlignmentFaultFixup:
483     case ThreadEventPair_Reusable:
484     case ThreadQuerySetWin32StartAddress:
485     case ThreadZeroTlsCell:
486     case ThreadPerformanceCount:
487     case ThreadAmILastThread:
488     case ThreadIdealProcessor:
489     case ThreadPriorityBoost:
490     case ThreadSetTlsArrayAddress:
491     case ThreadIsIoPending:
492     default:
493         FIXME( "info class %d not supported yet\n", class );
494         return STATUS_NOT_IMPLEMENTED;
495     }
496 }
497
498
499 /******************************************************************************
500  *              NtSetInformationThread  (NTDLL.@)
501  *              ZwSetInformationThread  (NTDLL.@)
502  */
503 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
504                                         LPCVOID data, ULONG length )
505 {
506     switch(class)
507     {
508     case ThreadZeroTlsCell:
509         if (handle == GetCurrentThread())
510         {
511             LIST_ENTRY *entry;
512             DWORD index;
513
514             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
515             index = *(DWORD *)data;
516             if (index >= 64) return STATUS_INVALID_PARAMETER;
517             RtlAcquirePebLock();
518             for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
519             {
520                 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
521                 teb->TlsSlots[index] = 0;
522             }
523             RtlReleasePebLock();
524             return STATUS_SUCCESS;
525         }
526         FIXME( "ZeroTlsCell not supported on other threads\n" );
527         return STATUS_NOT_IMPLEMENTED;
528
529     case ThreadBasicInformation:
530     case ThreadTimes:
531     case ThreadPriority:
532     case ThreadBasePriority:
533     case ThreadAffinityMask:
534     case ThreadImpersonationToken:
535     case ThreadDescriptorTableEntry:
536     case ThreadEnableAlignmentFaultFixup:
537     case ThreadEventPair_Reusable:
538     case ThreadQuerySetWin32StartAddress:
539     case ThreadPerformanceCount:
540     case ThreadAmILastThread:
541     case ThreadIdealProcessor:
542     case ThreadPriorityBoost:
543     case ThreadSetTlsArrayAddress:
544     case ThreadIsIoPending:
545     default:
546         FIXME( "info class %d not supported yet\n", class );
547         return STATUS_NOT_IMPLEMENTED;
548     }
549 }
550
551
552 /**********************************************************************
553  *           NtCurrentTeb   (NTDLL.@)
554  */
555 #if defined(__i386__) && defined(__GNUC__)
556 __ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
557 #elif defined(__i386__) && defined(_MSC_VER)
558 /* Nothing needs to be done. MS C "magically" exports the inline version from winnt.h */
559 #else
560 TEB * WINAPI NtCurrentTeb(void)
561 {
562     return wine_pthread_get_current_teb();
563 }
564 #endif  /* __i386__ */