/*********************************************************************** * thread_init * * Setup the initial thread. * * NOTES: The first allocated TEB on NT is at 0x7ffde000. */ HANDLE thread_init(void) { TEB *teb; void *addr; SIZE_T size, info_size; HANDLE exe_file = 0; LARGE_INTEGER now; NTSTATUS status; struct ntdll_thread_data *thread_data; static struct debug_info debug_info; /* debug info for initial thread */ virtual_init(); /* reserve space for shared user data */ addr = (void *)0x7ffe0000; size = 0x10000; status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if (status) { MESSAGE( "wine: failed to map the shared user data: %08x\n", status ); exit(1); } user_shared_data = addr; /* allocate and initialize the PEB */ addr = NULL; size = sizeof(*peb); NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 1, &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ); peb = addr; peb->ProcessParameters = ¶ms; peb->TlsBitmap = &tls_bitmap; peb->TlsExpansionBitmap = &tls_expansion_bitmap; peb->FlsBitmap = &fls_bitmap; peb->LdrData = &ldr; params.CurrentDirectory.DosPath.Buffer = current_dir; params.CurrentDirectory.DosPath.MaximumLength = sizeof(current_dir); params.wShowWindow = 1; /* SW_SHOWNORMAL */ ldr.Length = sizeof(ldr); RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 ); RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits, sizeof(peb->TlsExpansionBitmapBits) * 8 ); RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 ); InitializeListHead( &peb->FlsListHead ); InitializeListHead( &ldr.InLoadOrderModuleList ); InitializeListHead( &ldr.InMemoryOrderModuleList ); InitializeListHead( &ldr.InInitializationOrderModuleList ); #ifdef __APPLE__ peb->Reserved[0] = get_dyld_image_info_addr(); #endif /* allocate and initialize the initial TEB */ signal_alloc_thread( &teb ); teb->Peb = peb; teb->Tib.StackBase = (void *)~0UL; teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; thread_data->request_fd = -1; thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; thread_data->wait_fd[1] = -1; thread_data->debug_info = &debug_info; InsertHeadList( &tls_links, &teb->TlsLinks ); signal_init_thread( teb ); virtual_init_threading(); debug_info.str_pos = debug_info.strings; debug_info.out_pos = debug_info.output; debug_init(); /* setup the server connection */ server_init_process(); info_size = server_init_thread( peb ); /* create the process heap */ if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL ))) { MESSAGE( "wine: failed to create the process heap\n" ); exit(1); } /* allocate user parameters */ if (info_size) { init_user_process_params( info_size, &exe_file ); } else { if (isatty(0) || isatty(1) || isatty(2)) params.ConsoleHandle = (HANDLE)2; /* see kernel32/kernel_private.h */ if (!isatty(0)) wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdInput ); if (!isatty(1)) wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdOutput ); if (!isatty(2)) wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdError ); } /* initialize time values in user_shared_data */ NtQuerySystemTime( &now ); user_shared_data->SystemTime.LowPart = now.u.LowPart; user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart; user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000; user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time; user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart; user_shared_data->TickCountMultiplier = 1 << 24; fill_cpu_info(); NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 ); return exe_file; }
/*********************************************************************** * RtlCreateUserThread (NTDLL.@) */ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr, BOOLEAN suspended, PVOID stack_addr, SIZE_T stack_reserve, SIZE_T stack_commit, PRTL_THREAD_START_ROUTINE start, void *param, HANDLE *handle_ptr, CLIENT_ID *id ) { sigset_t sigset; pthread_t pthread_id; pthread_attr_t attr; struct ntdll_thread_data *thread_data; struct startup_info *info = NULL; HANDLE handle = 0, actctx = 0; TEB *teb = NULL; DWORD tid = 0; int request_pipe[2]; NTSTATUS status; if (process != NtCurrentProcess()) { apc_call_t call; apc_result_t result; memset( &call, 0, sizeof(call) ); call.create_thread.type = APC_CREATE_THREAD; call.create_thread.func = wine_server_client_ptr( start ); call.create_thread.arg = wine_server_client_ptr( param ); call.create_thread.reserve = stack_reserve; call.create_thread.commit = stack_commit; call.create_thread.suspend = suspended; status = server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.create_thread.status == STATUS_SUCCESS) { if (id) id->UniqueThread = ULongToHandle(result.create_thread.tid); if (handle_ptr) *handle_ptr = wine_server_ptr_handle( result.create_thread.handle ); else NtClose( wine_server_ptr_handle( result.create_thread.handle )); } return result.create_thread.status; } if (server_pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES; wine_server_send_fd( request_pipe[0] ); SERVER_START_REQ( new_thread ) { req->access = THREAD_ALL_ACCESS; req->attributes = 0; /* FIXME */ req->suspend = suspended; req->request_fd = request_pipe[0]; if (!(status = wine_server_call( req ))) { handle = wine_server_ptr_handle( reply->handle ); tid = reply->tid; } close( request_pipe[0] ); } SERVER_END_REQ; if (status) { close( request_pipe[1] ); return status; } pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset ); if ((status = signal_alloc_thread( &teb ))) goto error; teb->Peb = NtCurrentTeb()->Peb; teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId()); teb->ClientId.UniqueThread = ULongToHandle(tid); teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); /* create default activation context frame for new thread */ RtlGetActiveActivationContext(&actctx); if (actctx) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; frame = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*frame)); frame->Previous = NULL; frame->ActivationContext = actctx; frame->Flags = 0; teb->ActivationContextStack.ActiveFrame = frame; RtlAddRefActivationContext(actctx); } info = (struct startup_info *)(teb + 1); info->teb = teb; info->entry_point = start; info->entry_arg = param; thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; thread_data->request_fd = request_pipe[1]; thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; thread_data->wait_fd[1] = -1; if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit ))) goto error; pthread_attr_init( &attr ); pthread_attr_setstack( &attr, teb->DeallocationStack, (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack ); pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */ interlocked_xchg_add( &nb_threads, 1 ); if (pthread_create( &pthread_id, &attr, (void * (*)(void *))start_thread, info )) { interlocked_xchg_add( &nb_threads, -1 ); pthread_attr_destroy( &attr ); status = STATUS_NO_MEMORY; goto error; } pthread_attr_destroy( &attr ); pthread_sigmask( SIG_SETMASK, &sigset, NULL ); if (id) id->UniqueThread = ULongToHandle(tid); if (handle_ptr) *handle_ptr = handle; else NtClose( handle ); return STATUS_SUCCESS; error: if (teb) signal_free_thread( teb ); if (handle) NtClose( handle ); pthread_sigmask( SIG_SETMASK, &sigset, NULL ); close( request_pipe[1] ); return status; }
/*********************************************************************** * thread_init * * Setup the initial thread. * * NOTES: The first allocated TEB on NT is at 0x7ffde000. */ HANDLE thread_init(void) { TEB *teb; void *addr; SIZE_T size, info_size; HANDLE exe_file = 0; NTSTATUS status; struct ntdll_thread_data *thread_data; static struct debug_info debug_info; /* debug info for initial thread */ #ifdef __APPLE__ ULONG64 dyld_image_info; #endif virtual_init(); signal_init_early(); /* reserve space for shared user data */ addr = (void *)0x7ffe0000; size = 0x10000; status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if (status) { MESSAGE( "wine: failed to map the shared user data: %08x\n", status ); exit(1); } user_shared_data = addr; /* allocate and initialize the PEB */ addr = NULL; size = sizeof(*peb); NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 1, &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ); peb = addr; peb->ProcessParameters = ¶ms; peb->TlsBitmap = &tls_bitmap; peb->TlsExpansionBitmap = &tls_expansion_bitmap; peb->FlsBitmap = &fls_bitmap; peb->LdrData = &ldr; peb->OSMajorVersion = 5; peb->OSMinorVersion = 1; peb->OSBuildNumber = 0xA28; peb->OSPlatformId = VER_PLATFORM_WIN32_NT; params.CurrentDirectory.DosPath.Buffer = current_dir; params.CurrentDirectory.DosPath.MaximumLength = sizeof(current_dir); params.wShowWindow = 1; /* SW_SHOWNORMAL */ ldr.Length = sizeof(ldr); RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 ); RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits, sizeof(peb->TlsExpansionBitmapBits) * 8 ); RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 ); RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */ RtlSetBits( peb->FlsBitmap, 0, 1 ); InitializeListHead( &peb->FlsListHead ); InitializeListHead( &ldr.InLoadOrderModuleList ); InitializeListHead( &ldr.InMemoryOrderModuleList ); InitializeListHead( &ldr.InInitializationOrderModuleList ); #ifdef __APPLE__ dyld_image_info = get_dyld_image_info_addr(); #ifdef __LP64__ #ifdef WORDS_BIGENDIAN peb->Reserved[1] = dyld_image_info & 0xFFFFFFFF; peb->Reserved[0] = dyld_image_info >> 32; #else peb->Reserved[0] = dyld_image_info & 0xFFFFFFFF; peb->Reserved[1] = dyld_image_info >> 32; #endif #else peb->Reserved[0] = dyld_image_info & 0xFFFFFFFF; #endif #endif /* * Starting with Vista, the first user to log on has session id 1. * Session id 0 is for processes that don't interact with the user (like services). */ peb->SessionId = 1; /* allocate and initialize the initial TEB */ signal_alloc_thread( &teb ); teb->Peb = peb; teb->Tib.StackBase = (void *)~0UL; teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; thread_data->request_fd = -1; thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; thread_data->wait_fd[1] = -1; thread_data->debug_info = &debug_info; InsertHeadList( &tls_links, &teb->TlsLinks ); signal_init_thread( teb ); virtual_init_threading(); debug_info.str_pos = debug_info.strings; debug_info.out_pos = debug_info.output; debug_init(); /* setup the server connection */ server_init_process(); info_size = server_init_thread( peb ); /* create the process heap */ if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL ))) { MESSAGE( "wine: failed to create the process heap\n" ); exit(1); } /* allocate user parameters */ if (info_size) { init_user_process_params( info_size, &exe_file ); } else { if (isatty(0) || isatty(1) || isatty(2)) params.ConsoleHandle = (HANDLE)2; /* see kernel32/kernel_private.h */ if (!isatty(0)) wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdInput ); if (!isatty(1)) wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdOutput ); if (!isatty(2)) wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdError ); } /* initialize user_shared_data */ __wine_user_shared_data(); fill_cpu_info(); NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 ); return exe_file; }