From 3ef9322915ab5a5d42576166a2a8dd6933f6f93e Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 13 Apr 2000 17:03:22 +0000 Subject: [PATCH] Cleanup thread stack allocation. Use a single VirtualAlloc for TEB and the various stacks. --- include/thread.h | 2 +- scheduler/process.c | 3 +- scheduler/thread.c | 219 ++++++++++++++++++++++++++-------------------------- 3 files changed, 112 insertions(+), 112 deletions(-) diff --git a/include/thread.h b/include/thread.h index 4471906a6ea..222f068d9f3 100644 --- a/include/thread.h +++ b/include/thread.h @@ -119,7 +119,7 @@ typedef struct _TEB /* scheduler/thread.c */ extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd ); -extern TEB *THREAD_Create( struct _PDB *pdb, void *pid, void *tid, int fd, DWORD flags, +extern TEB *THREAD_Create( struct _PDB *pdb, void *pid, void *tid, int fd, DWORD stack_size, BOOL alloc_stack16 ); extern BOOL THREAD_IsWin16( TEB *thdb ); extern TEB *THREAD_IdToTEB( DWORD id ); diff --git a/scheduler/process.c b/scheduler/process.c index 9a314bf8d8c..72a5b73b39d 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -557,8 +557,7 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en /* Create the main thread */ - if (!(teb = THREAD_Create( pdb, req->pid, req->tid, fd, flags & CREATE_SUSPENDED, - size, alloc_stack16 ))) goto error; + if (!(teb = THREAD_Create( pdb, req->pid, req->tid, fd, size, alloc_stack16 ))) goto error; teb->startup = PROCESS_Start; fd = -1; /* don't close it */ diff --git a/scheduler/thread.c b/scheduler/thread.c index d1f47bbb59e..16ede628fe3 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -18,6 +18,7 @@ #include "process.h" #include "task.h" #include "module.h" +#include "global.h" #include "user.h" #include "winerror.h" #include "heap.h" @@ -74,57 +75,20 @@ TEB *THREAD_IdToTEB( DWORD id ) * * Initialization of a newly created TEB. */ -static BOOL THREAD_InitTEB( TEB *teb, DWORD stack_size, BOOL alloc_stack16 ) +static BOOL THREAD_InitTEB( TEB *teb, PDB *pdb ) { - DWORD old_prot; - - /* Allocate the stack */ - - /* FIXME: - * If stacksize smaller than 1 MB, allocate 1MB - * (one program wanted only 10 kB, which is recommendable, but some WINE - * functions, noteably in the files subdir, push HUGE structures and - * arrays on the stack. They probably shouldn't.) - * If stacksize larger than 16 MB, warn the user. (We could shrink the stack - * but this could give more or less unexplainable crashes.) - */ - if (stack_size<1024*1024) - stack_size = 1024 * 1024; - if (stack_size >= 16*1024*1024) - WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024); - teb->stack_base = VirtualAlloc(NULL, stack_size + SIGNAL_STACK_SIZE + - (alloc_stack16 ? 0x10000 : 0), - MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - if (!teb->stack_base) goto error; - /* Set a guard page at the bottom of the stack */ - VirtualProtect( teb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot ); - teb->stack_top = (char *)teb->stack_base + stack_size; - teb->stack_low = teb->stack_base; - teb->signal_stack = teb->stack_top; /* start of signal stack */ - - /* Allocate the 16-bit stack selector */ - - if (alloc_stack16) - { - teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, SEGMENT_DATA, - FALSE, FALSE ); - if (!teb->stack_sel) goto error; - teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( teb->stack_sel, - 0x10000 - sizeof(STACK16FRAME) ); - teb->signal_stack = (char *)teb->signal_stack + 0x10000; - } - - /* StaticUnicodeString */ - + teb->except = (void *)~0UL; + teb->htask16 = pdb->task; + teb->self = teb; + teb->tibflags = (pdb->flags & PDB32_WIN16_PROC) ? 0 : TEBF_WIN32; + teb->tls_ptr = teb->tls_array; + teb->process = pdb; + teb->exit_code = STILL_ACTIVE; + teb->socket = -1; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer; - - return TRUE; - -error: - if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 ); - if (teb->stack_base) VirtualFree( teb->stack_base, 0, MEM_RELEASE ); - return FALSE; + teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE ); + return (teb->teb_sel != 0); } @@ -134,12 +98,10 @@ error: * Free data structures associated with a thread. * Must be called from the context of another thread. */ -void CALLBACK THREAD_FreeTEB( ULONG_PTR arg ) +static void CALLBACK THREAD_FreeTEB( TEB *teb ) { - TEB *teb = (TEB *)arg; - TRACE("(%p) called\n", teb ); - SERVICE_Delete( teb->cleanup ); + if (teb->cleanup) SERVICE_Delete( teb->cleanup ); /* Free the associated memory */ @@ -149,85 +111,124 @@ void CALLBACK THREAD_FreeTEB( ULONG_PTR arg ) if (teb->buffer) munmap( teb->buffer, teb->buffer_size ); if (teb->debug_info) HeapFree( GetProcessHeap(), 0, teb->debug_info ); VirtualFree( teb->stack_base, 0, MEM_RELEASE ); - VirtualFree( teb, 0, MEM_RELEASE ); } /*********************************************************************** - * THREAD_CreateInitialThread + * THREAD_InitStack * - * Create the initial thread. + * Allocate the stack of a thread. */ -TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd ) +static TEB *THREAD_InitStack( TEB *teb, PDB *pdb, DWORD stack_size, BOOL alloc_stack16 ) { - initial_teb.except = (void *)-1; - initial_teb.self = &initial_teb; - initial_teb.tibflags = (pdb->flags & PDB32_WIN16_PROC)? 0 : TEBF_WIN32; - initial_teb.tls_ptr = initial_teb.tls_array; - initial_teb.process = pdb; - initial_teb.exit_code = STILL_ACTIVE; - initial_teb.socket = server_fd; + DWORD old_prot, total_size; + DWORD page_size = VIRTUAL_GetPageSize(); + void *base; - /* Allocate the TEB selector (%fs register) */ + /* Allocate the stack */ - if (!(initial_teb.teb_sel = SELECTOR_AllocBlock( &initial_teb, 0x1000, - SEGMENT_DATA, TRUE, FALSE ))) - { - MESSAGE("Could not allocate fs register for initial thread\n" ); + if (stack_size >= 16*1024*1024) + WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024); + + /* FIXME: some Wine functions use a lot of stack, so we add 64Kb here */ + stack_size += 64 * 1024; + + /* Memory layout in allocated block: + * + * size contents + * 1 page NOACCESS guard page + * SIGNAL_STACK_SIZE signal stack + * 1 page NOACCESS guard page + * 1 page PAGE_GUARD guard page + * stack_size normal stack + * 64Kb 16-bit stack (optional) + * 1 page TEB (except for initial thread) + */ + + stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1); + total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size; + if (alloc_stack16) total_size += 0x10000; + if (!teb) total_size += page_size; + + if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE ))) return NULL; + + if (!teb) + { + teb = (TEB *)((char *)base + total_size - page_size); + if (!THREAD_InitTEB( teb, pdb )) + { + VirtualFree( base, 0, MEM_RELEASE ); + return NULL; + } } - SYSDEPS_SetCurThread( &initial_teb ); - /* Now proceed with normal initialization */ + teb->stack_low = base; + teb->stack_base = base; + teb->signal_stack = (char *)base + page_size; + teb->stack_top = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size; - if (CLIENT_InitThread()) return NULL; - if (!THREAD_InitTEB( &initial_teb, 0, TRUE )) return NULL; - return &initial_teb; + /* Setup guard pages */ + + VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot ); + VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot ); + VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1, + PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot ); + + /* Allocate the 16-bit stack selector */ + + if (alloc_stack16) + { + teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, SEGMENT_DATA, + FALSE, FALSE ); + if (!teb->stack_sel) goto error; + teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( teb->stack_sel, + 0x10000 - sizeof(STACK16FRAME) ); + } + return teb; + +error: + THREAD_FreeTEB( teb ); + return NULL; } /*********************************************************************** - * THREAD_Create + * THREAD_CreateInitialThread + * + * Create the initial thread. * - * NOTES: - * Native NT dlls are using the space left on the allocated page - * the first allocated TEB on NT is at 0x7ffde000, since we can't - * allocate in this area and don't support a granularity of 4kb - * yet we leave it to VirtualAlloc to choose an address. + * NOTES: The first allocated TEB on NT is at 0x7ffde000. */ -TEB *THREAD_Create( PDB *pdb, void *pid, void *tid, int fd, DWORD flags, - DWORD stack_size, BOOL alloc_stack16 ) +TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd ) { - TEB *teb = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (!teb) return NULL; - teb->except = (void *)-1; - teb->htask16 = pdb->task; - teb->self = teb; - teb->tibflags = (pdb->flags & PDB32_WIN16_PROC)? 0 : TEBF_WIN32; - teb->tls_ptr = teb->tls_array; - teb->process = pdb; - teb->exit_code = STILL_ACTIVE; - teb->socket = fd; - teb->pid = pid; - teb->tid = tid; - fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ - - /* Allocate the TEB selector (%fs register) */ + if (!THREAD_InitTEB( &initial_teb, pdb )) return NULL; + SYSDEPS_SetCurThread( &initial_teb ); + initial_teb.socket = server_fd; - teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE ); - if (!teb->teb_sel) goto error; + if (CLIENT_InitThread()) return NULL; + return THREAD_InitStack( &initial_teb, pdb, 0, TRUE ); +} - /* Do the rest of the initialization */ - if (!THREAD_InitTEB( teb, stack_size, alloc_stack16 )) goto error; +/*********************************************************************** + * THREAD_Create + * + */ +TEB *THREAD_Create( PDB *pdb, void *pid, void *tid, int fd, + DWORD stack_size, BOOL alloc_stack16 ) +{ + TEB *teb; - TRACE("(%p) succeeded\n", teb); + if ((teb = THREAD_InitStack( NULL, pdb, stack_size, alloc_stack16 ))) + { + teb->pid = pid; + teb->tid = tid; + teb->socket = fd; + fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ + TRACE("(%p) succeeded\n", teb); + } return teb; - -error: - if (teb->teb_sel) SELECTOR_FreeBlock( teb->teb_sel, 1 ); - VirtualFree( teb, 0, MEM_RELEASE ); - return NULL; } @@ -245,7 +246,7 @@ static void THREAD_Start(void) if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &cleanup_object, 0, FALSE, DUPLICATE_SAME_ACCESS )) - NtCurrentTeb()->cleanup = SERVICE_AddObject( cleanup_object, THREAD_FreeTEB, + NtCurrentTeb()->cleanup = SERVICE_AddObject( cleanup_object, (PAPCFUNC)THREAD_FreeTEB, (ULONG_PTR)NtCurrentTeb() ); PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 ); @@ -272,7 +273,7 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack, handle = req->handle; if (!(teb = THREAD_Create( PROCESS_Current(), (void *)GetCurrentProcessId(), - req->tid, socket, flags, stack, TRUE ))) + req->tid, socket, stack, TRUE ))) { close( socket ); return 0; @@ -281,12 +282,12 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack, teb->entry_point = start; teb->entry_arg = param; teb->startup = THREAD_Start; + if (id) *id = (DWORD)teb->tid; if (SYSDEPS_SpawnThread( teb ) == -1) { CloseHandle( handle ); return 0; } - if (id) *id = (DWORD)teb->tid; return handle; } -- 2.11.4.GIT