Module: wine Branch: master Commit: 772a5c7c09a2568cd0ad2358f307c3eaa5fe4912 URL: http://source.winehq.org/git/wine.git/?a=commit;h=772a5c7c09a2568cd0ad2358f3...
Author: Henri Verbeet hverbeet@codeweavers.com Date: Thu Jun 17 10:17:15 2010 +0200
ntdll: The FPU control word for newly created threads is 0x27f.
This fixes a regression introduced by e6611e22fb037a879205f1330d1a3485f9f18705.
---
dlls/kernel32/tests/thread.c | 84 ++++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/signal_i386.c | 10 +++++ dlls/ntdll/signal_x86_64.c | 10 +++++ 3 files changed, 104 insertions(+), 0 deletions(-)
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index 4c4e764..df87ae0 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -1329,6 +1329,87 @@ static void test_ThreadErrorMode(void) pSetThreadErrorMode(oldmode, NULL); }
+static inline void set_fpu_cw(WORD cw) +{ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ volatile ("fnclex; fldcw %0" : : "m" (cw)); +#endif +} + +static inline WORD get_fpu_cw(void) +{ + WORD cw = 0; +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ volatile ("fnstcw %0" : "=m" (cw)); +#endif + return cw; +} + +struct fpu_thread_ctx +{ + WORD cw; + HANDLE finished; +}; + +static DWORD WINAPI fpu_thread(void *param) +{ + struct fpu_thread_ctx *ctx = param; + BOOL ret; + + ctx->cw = get_fpu_cw(); + + ret = SetEvent(ctx->finished); + ok(ret, "SetEvent failed, last error %#x.\n", GetLastError()); + + return 0; +} + +static WORD get_thread_fpu_cw(void) +{ + struct fpu_thread_ctx ctx; + DWORD tid, res; + HANDLE thread; + + ctx.finished = CreateEvent(NULL, FALSE, FALSE, NULL); + ok(!!ctx.finished, "Failed to create event, last error %#x.\n", GetLastError()); + + thread = CreateThread(NULL, 0, fpu_thread, &ctx, 0, &tid); + ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError()); + + res = WaitForSingleObject(ctx.finished, INFINITE); + ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); + + res = CloseHandle(ctx.finished); + ok(!!res, "Failed to close event handle, last error %#x.\n", GetLastError()); + + return ctx.cw; +} + +static void test_thread_fpu_cw(void) +{ + WORD initial_cw, cw; + + initial_cw = get_fpu_cw(); + ok(initial_cw == 0x37f, "Expected FPU control word 0x37f, got %#x.\n", initial_cw); + + cw = get_thread_fpu_cw(); + ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw); + + set_fpu_cw(0xf60); + cw = get_fpu_cw(); + ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw); + + cw = get_thread_fpu_cw(); + ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw); + + cw = get_fpu_cw(); + ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw); + + set_fpu_cw(initial_cw); + cw = get_fpu_cw(); + ok(cw == initial_cw, "Expected FPU control word %#x, got %#x.\n", initial_cw, cw); +} + START_TEST(thread) { HINSTANCE lib; @@ -1401,4 +1482,7 @@ START_TEST(thread) test_RegisterWaitForSingleObject(); test_TLS(); test_ThreadErrorMode(); +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + test_thread_fpu_cw(); +#endif } diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 7a60c2a..b003436 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -2177,6 +2177,16 @@ void signal_init_thread( TEB *teb ) wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT ); wine_ldt_init_fs( thread_data->fs, &fs_entry ); thread_data->gs = wine_get_gs(); + + if (teb->Peb->ProcessHeap) /* Not for the inital thread. */ + { + const WORD fpu_cw = 0x27f; +#ifdef __GNUC__ + __asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw)); +#else + FIXME("FPU setup not implemented for this platform.\n"); +#endif + } }
/********************************************************************** diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index f509006..188224d 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -2344,6 +2344,16 @@ void signal_init_thread( TEB *teb ) ss.ss_size = signal_stack_size; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" ); + + if (teb->Peb->ProcessHeap) /* Not for the inital thread. */ + { + const WORD fpu_cw = 0x27f; +#ifdef __GNUC__ + __asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw)); +#else + FIXME("FPU setup not implemented for this platform.\n"); +#endif + } }
/**********************************************************************