Allocate the TEB and signal stack separately from the main stack.
[wine/gsoc_dplay.git] / dlls / ntdll / thread.c
blob9a13a943d5ceac937063ad263c3a171d88af972e
1 /*
2 * NT threads support
4 * Copyright 1996, 2003 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <sys/types.h>
25 #ifdef HAVE_SYS_MMAN_H
26 #include <sys/mman.h>
27 #endif
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/debug.h"
35 #include "ntdll_misc.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(thread);
39 static PEB peb;
40 static PEB_LDR_DATA ldr;
41 static RTL_USER_PROCESS_PARAMETERS params; /* default parameters if no parent */
42 static RTL_BITMAP tls_bitmap;
43 static LIST_ENTRY tls_links;
44 static struct debug_info info; /* debug info for initial thread */
47 /***********************************************************************
48 * alloc_teb
50 static TEB *alloc_teb( ULONG *size )
52 TEB *teb;
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()))
59 munmap( teb, *size );
60 return NULL;
62 teb->Tib.ExceptionList = (void *)~0UL;
63 teb->Tib.Self = &teb->Tib;
64 teb->Peb = &peb;
65 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
66 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
67 return teb;
71 /***********************************************************************
72 * free_teb
74 static inline void free_teb( TEB *teb )
76 ULONG size = 0;
77 void *addr = teb;
79 if (teb->DeallocationStack)
80 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
81 NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
82 wine_ldt_free_fs( teb->teb_sel );
83 munmap( teb, SIGNAL_STACK_SIZE + sizeof(TEB) );
87 /***********************************************************************
88 * thread_init
90 * Setup the initial thread.
92 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
94 void thread_init(void)
96 TEB *teb;
97 void *addr;
98 ULONG size;
100 info.str_pos = info.strings;
101 info.out_pos = info.output;
103 peb.ProcessParameters = &params;
104 peb.TlsBitmap = &tls_bitmap;
105 peb.LdrData = &ldr;
106 RtlInitializeBitMap( &tls_bitmap, (BYTE *)peb.TlsBitmapBits, sizeof(peb.TlsBitmapBits) * 8 );
107 InitializeListHead( &ldr.InLoadOrderModuleList );
108 InitializeListHead( &ldr.InMemoryOrderModuleList );
109 InitializeListHead( &ldr.InInitializationOrderModuleList );
110 InitializeListHead( &tls_links );
112 teb = alloc_teb( &size );
113 teb->Tib.StackBase = (void *)~0UL;
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 = &info;
120 InsertHeadList( &tls_links, &teb->TlsLinks );
122 SYSDEPS_SetCurThread( teb );
124 /* setup the server connection */
125 wine_server_init_process();
126 wine_server_init_thread();
128 /* create a memory view for the TEB */
129 NtAllocateVirtualMemory( GetCurrentProcess(), &addr, teb, &size,
130 MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
132 /* create the process heap */
133 if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
135 MESSAGE( "wine: failed to create the process heap\n" );
136 exit(1);
141 /***********************************************************************
142 * start_thread
144 * Startup routine for a newly created thread.
146 static void start_thread( TEB *teb )
148 LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
149 struct debug_info info;
151 info.str_pos = info.strings;
152 info.out_pos = info.output;
153 teb->debug_info = &info;
155 SYSDEPS_SetCurThread( teb );
156 SIGNAL_Init();
157 wine_server_init_thread();
159 RtlAcquirePebLock();
160 InsertHeadList( &tls_links, &teb->TlsLinks );
161 RtlReleasePebLock();
163 NtTerminateThread( GetCurrentThread(), func( NtCurrentTeb()->entry_arg ) );
167 /***********************************************************************
168 * RtlCreateUserThread (NTDLL.@)
170 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
171 BOOLEAN suspended, PVOID stack_addr,
172 SIZE_T stack_reserve, SIZE_T stack_commit,
173 PRTL_THREAD_START_ROUTINE start, void *param,
174 HANDLE *handle_ptr, CLIENT_ID *id )
176 HANDLE handle = 0;
177 TEB *teb = NULL;
178 DWORD tid = 0;
179 ULONG size;
180 void *base;
181 int request_pipe[2];
182 NTSTATUS status;
184 if (pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
185 fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
186 wine_server_send_fd( request_pipe[0] );
188 SERVER_START_REQ( new_thread )
190 req->suspend = suspended;
191 req->inherit = 0; /* FIXME */
192 req->request_fd = request_pipe[0];
193 if (!(status = wine_server_call( req )))
195 handle = reply->handle;
196 tid = reply->tid;
198 close( request_pipe[0] );
200 SERVER_END_REQ;
202 if (status) goto error;
204 if (!(teb = alloc_teb( &size )))
206 status = STATUS_NO_MEMORY;
207 goto error;
209 teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
210 teb->ClientId.UniqueThread = (HANDLE)tid;
212 teb->tibflags = TEBF_WIN32;
213 teb->exit_code = STILL_ACTIVE;
214 teb->request_fd = request_pipe[1];
215 teb->reply_fd = -1;
216 teb->wait_fd[0] = -1;
217 teb->wait_fd[1] = -1;
218 teb->entry_point = start;
219 teb->entry_arg = param;
220 teb->htask16 = NtCurrentTeb()->htask16;
222 NtAllocateVirtualMemory( GetCurrentProcess(), &base, teb, &size,
223 MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
225 if (!stack_reserve || !stack_commit)
227 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
228 if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
229 if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
231 if (stack_reserve < stack_commit) stack_reserve = stack_commit;
232 stack_reserve = (stack_reserve + 0xffff) & ~0xffff; /* round to 64K boundary */
234 status = NtAllocateVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, NULL,
235 &stack_reserve, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
236 if (status != STATUS_SUCCESS) goto error;
238 /* limit is lower than base since the stack grows down */
239 teb->Tib.StackBase = (char *)teb->DeallocationStack + stack_reserve;
240 teb->Tib.StackLimit = teb->DeallocationStack;
242 /* setup the guard page */
243 size = 1;
244 NtProtectVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size,
245 PAGE_EXECUTE_READWRITE | PAGE_GUARD, NULL );
247 if (SYSDEPS_SpawnThread( start_thread, teb ) == -1)
249 status = STATUS_TOO_MANY_THREADS;
250 goto error;
253 if (id) id->UniqueThread = (HANDLE)tid;
254 if (handle_ptr) *handle_ptr = handle;
255 else NtClose( handle );
257 return STATUS_SUCCESS;
259 error:
260 if (teb) free_teb( teb );
261 if (handle) NtClose( handle );
262 close( request_pipe[1] );
263 return status;
267 /***********************************************************************
268 * NtOpenThread (NTDLL.@)
269 * ZwOpenThread (NTDLL.@)
271 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
272 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
274 NTSTATUS ret;
276 SERVER_START_REQ( open_thread )
278 req->tid = (thread_id_t)id->UniqueThread;
279 req->access = access;
280 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
281 ret = wine_server_call( req );
282 *handle = reply->handle;
284 SERVER_END_REQ;
285 return ret;
289 /******************************************************************************
290 * NtSuspendThread (NTDLL.@)
291 * ZwSuspendThread (NTDLL.@)
293 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
295 NTSTATUS ret;
297 SERVER_START_REQ( suspend_thread )
299 req->handle = handle;
300 if (!(ret = wine_server_call( req ))) *count = reply->count;
302 SERVER_END_REQ;
303 return ret;
307 /******************************************************************************
308 * NtResumeThread (NTDLL.@)
309 * ZwResumeThread (NTDLL.@)
311 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
313 NTSTATUS ret;
315 SERVER_START_REQ( resume_thread )
317 req->handle = handle;
318 if (!(ret = wine_server_call( req ))) *count = reply->count;
320 SERVER_END_REQ;
321 return ret;
325 /******************************************************************************
326 * NtTerminateThread (NTDLL.@)
327 * ZwTerminateThread (NTDLL.@)
329 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
331 NTSTATUS ret;
332 BOOL self, last;
334 SERVER_START_REQ( terminate_thread )
336 req->handle = handle;
337 req->exit_code = exit_code;
338 ret = wine_server_call( req );
339 self = !ret && reply->self;
340 last = reply->last;
342 SERVER_END_REQ;
344 if (self)
346 if (last) exit( exit_code );
347 else SYSDEPS_AbortThread( exit_code );
349 return ret;
353 /******************************************************************************
354 * NtQueueApcThread (NTDLL.@)
356 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
357 ULONG_PTR arg2, ULONG_PTR arg3 )
359 NTSTATUS ret;
360 SERVER_START_REQ( queue_apc )
362 req->handle = handle;
363 req->user = 1;
364 req->func = func;
365 req->arg1 = (void *)arg1;
366 req->arg2 = (void *)arg2;
367 req->arg3 = (void *)arg3;
368 ret = wine_server_call( req );
370 SERVER_END_REQ;
371 return ret;
375 /***********************************************************************
376 * NtSetContextThread (NTDLL.@)
377 * ZwSetContextThread (NTDLL.@)
379 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
381 NTSTATUS ret;
383 SERVER_START_REQ( set_thread_context )
385 req->handle = handle;
386 req->flags = context->ContextFlags;
387 wine_server_add_data( req, context, sizeof(*context) );
388 ret = wine_server_call( req );
390 SERVER_END_REQ;
391 return ret;
395 /***********************************************************************
396 * NtGetContextThread (NTDLL.@)
397 * ZwGetContextThread (NTDLL.@)
399 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
401 NTSTATUS ret;
403 SERVER_START_REQ( get_thread_context )
405 req->handle = handle;
406 req->flags = context->ContextFlags;
407 wine_server_add_data( req, context, sizeof(*context) );
408 wine_server_set_reply( req, context, sizeof(*context) );
409 ret = wine_server_call( req );
411 SERVER_END_REQ;
412 return ret;
416 /******************************************************************************
417 * NtQueryInformationThread (NTDLL.@)
418 * ZwQueryInformationThread (NTDLL.@)
420 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
421 void *data, ULONG length, ULONG *ret_len )
423 NTSTATUS status;
425 switch(class)
427 case ThreadBasicInformation:
429 THREAD_BASIC_INFORMATION info;
431 SERVER_START_REQ( get_thread_info )
433 req->handle = handle;
434 req->tid_in = 0;
435 if (!(status = wine_server_call( req )))
437 info.ExitStatus = reply->exit_code;
438 info.TebBaseAddress = reply->teb;
439 info.ClientId.UniqueProcess = (HANDLE)reply->pid;
440 info.ClientId.UniqueThread = (HANDLE)reply->tid;
441 info.AffinityMask = reply->affinity;
442 info.Priority = reply->priority;
443 info.BasePriority = reply->priority; /* FIXME */
446 SERVER_END_REQ;
447 if (status == STATUS_SUCCESS)
449 if (data) memcpy( data, &info, min( length, sizeof(info) ));
450 if (ret_len) *ret_len = min( length, sizeof(info) );
453 return status;
454 case ThreadTimes:
455 case ThreadPriority:
456 case ThreadBasePriority:
457 case ThreadAffinityMask:
458 case ThreadImpersonationToken:
459 case ThreadDescriptorTableEntry:
460 case ThreadEnableAlignmentFaultFixup:
461 case ThreadEventPair_Reusable:
462 case ThreadQuerySetWin32StartAddress:
463 case ThreadZeroTlsCell:
464 case ThreadPerformanceCount:
465 case ThreadAmILastThread:
466 case ThreadIdealProcessor:
467 case ThreadPriorityBoost:
468 case ThreadSetTlsArrayAddress:
469 case ThreadIsIoPending:
470 default:
471 FIXME( "info class %d not supported yet\n", class );
472 return STATUS_NOT_IMPLEMENTED;
477 /******************************************************************************
478 * NtSetInformationThread (NTDLL.@)
479 * ZwSetInformationThread (NTDLL.@)
481 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
482 LPCVOID data, ULONG length )
484 switch(class)
486 case ThreadZeroTlsCell:
487 if (handle == GetCurrentThread())
489 LIST_ENTRY *entry;
490 DWORD index;
492 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
493 index = *(DWORD *)data;
494 if (index >= 64) return STATUS_INVALID_PARAMETER;
495 RtlAcquirePebLock();
496 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
498 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
499 teb->TlsSlots[index] = 0;
501 RtlReleasePebLock();
502 return STATUS_SUCCESS;
504 FIXME( "ZeroTlsCell not supported on other threads\n" );
505 return STATUS_NOT_IMPLEMENTED;
507 case ThreadBasicInformation:
508 case ThreadTimes:
509 case ThreadPriority:
510 case ThreadBasePriority:
511 case ThreadAffinityMask:
512 case ThreadImpersonationToken:
513 case ThreadDescriptorTableEntry:
514 case ThreadEnableAlignmentFaultFixup:
515 case ThreadEventPair_Reusable:
516 case ThreadQuerySetWin32StartAddress:
517 case ThreadPerformanceCount:
518 case ThreadAmILastThread:
519 case ThreadIdealProcessor:
520 case ThreadPriorityBoost:
521 case ThreadSetTlsArrayAddress:
522 case ThreadIsIoPending:
523 default:
524 FIXME( "info class %d not supported yet\n", class );
525 return STATUS_NOT_IMPLEMENTED;