Reactos
at master 2707 lines 100 kB view raw
1/* 2 * Unit test suite for thread functions. 3 * 4 * Copyright 2002 Geoffrey Hausheer 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21#include <assert.h> 22#include <stdarg.h> 23#include <stdio.h> 24#include <float.h> 25#include <math.h> 26 27/* the tests intentionally pass invalid pointers and need an exception handler */ 28#define WINE_NO_INLINE_STRING 29 30#include <ntstatus.h> 31#define WIN32_NO_STATUS 32#include <windef.h> 33#include <winbase.h> 34#include <winnt.h> 35#include <winerror.h> 36#include <winnls.h> 37#include <winternl.h> 38#include "wine/test.h" 39 40/* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ 41#define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff) 42 43/* Specify the number of simultaneous threads to test */ 44#define NUM_THREADS 4 45/* Specify whether to test the extended priorities for Win2k/XP */ 46#define USE_EXTENDED_PRIORITIES 0 47/* Specify whether to test the stack allocation in CreateThread */ 48#define CHECK_STACK 0 49 50/* Set CHECK_STACK to 1 if you want to try to test the stack-limit from 51 CreateThread. So far I have been unable to make this work, and 52 I am in doubt as to how portable it is. Also, according to MSDN, 53 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread. 54 Anyhow, the check is currently commented out 55*/ 56#if CHECK_STACK 57# ifdef __try 58# define __TRY __try 59# define __EXCEPT __except 60# define __ENDTRY 61# else 62# include "wine/exception.h" 63# endif 64#endif 65 66#ifdef __i386__ 67#define ARCH "x86" 68#elif defined __x86_64__ 69#define ARCH "amd64" 70#elif defined __arm__ 71#define ARCH "arm" 72#elif defined __aarch64__ 73#define ARCH "arm64" 74#else 75#define ARCH "none" 76#endif 77 78static void (WINAPI *pGetCurrentThreadStackLimits)(PULONG_PTR,PULONG_PTR); 79static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL); 80static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD); 81static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG); 82static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL); 83static BOOL (WINAPI *pSetThreadStackGuarantee)(ULONG*); 84static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG); 85static BOOL (WINAPI *pUnregisterWait)(HANDLE); 86static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); 87static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD); 88static DWORD (WINAPI *pGetThreadErrorMode)(void); 89static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); 90static PTP_POOL (WINAPI *pCreateThreadpool)(PVOID); 91static void (WINAPI *pCloseThreadpool)(PTP_POOL); 92static PTP_WORK (WINAPI *pCreateThreadpoolWork)(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON); 93static void (WINAPI *pSubmitThreadpoolWork)(PTP_WORK); 94static void (WINAPI *pWaitForThreadpoolWorkCallbacks)(PTP_WORK,BOOL); 95static void (WINAPI *pCloseThreadpoolWork)(PTP_WORK); 96static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG); 97static BOOL (WINAPI *pGetThreadGroupAffinity)(HANDLE,GROUP_AFFINITY*); 98static BOOL (WINAPI *pSetThreadGroupAffinity)(HANDLE,const GROUP_AFFINITY*,GROUP_AFFINITY*); 99static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG); 100static HRESULT (WINAPI *pSetThreadDescription)(HANDLE,const WCHAR *); 101static HRESULT (WINAPI *pGetThreadDescription)(HANDLE,WCHAR **); 102static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG,PVECTORED_EXCEPTION_HANDLER); 103static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID); 104 105static HANDLE create_target_process(const char *arg) 106{ 107 char **argv; 108 char cmdline[MAX_PATH]; 109 PROCESS_INFORMATION pi; 110 BOOL ret; 111 STARTUPINFOA si = { 0 }; 112 si.cb = sizeof(si); 113 114 winetest_get_mainargs( &argv ); 115 sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg); 116 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 117 ok(ret, "error: %lu\n", GetLastError()); 118 ret = CloseHandle(pi.hThread); 119 ok(ret, "error %lu\n", GetLastError()); 120 return pi.hProcess; 121} 122 123/* Functions not tested yet: 124 AttachThreadInput 125 SetThreadContext 126 SwitchToThread 127 128In addition there are no checks that the inheritance works properly in 129CreateThread 130*/ 131 132/* Functions to ensure that from a group of threads, only one executes 133 certain chunks of code at a time, and we know which one is executing 134 it. It basically makes multithreaded execution linear, which defeats 135 the purpose of multiple threads, but makes testing easy. */ 136static HANDLE start_event, stop_event; 137static LONG num_synced; 138 139static void init_thread_sync_helpers(void) 140{ 141 start_event = CreateEventW(NULL, TRUE, FALSE, NULL); 142 ok(start_event != NULL, "CreateEvent failed\n"); 143 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL); 144 ok(stop_event != NULL, "CreateEvent failed\n"); 145 num_synced = -1; 146} 147 148static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id) 149{ 150 LONG num = InterlockedIncrement(&num_synced); 151 assert(-1 <= num && num <= 1); 152 if (num == 1) 153 { 154 ResetEvent( stop_event ); 155 SetEvent( start_event ); 156 } 157 else 158 { 159 DWORD ret = WaitForSingleObject(start_event, 10000); 160 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %lx\n",ret); 161 } 162 return sync_id == my_id; 163} 164 165static void resync_after_run(void) 166{ 167 LONG num = InterlockedDecrement(&num_synced); 168 assert(-1 <= num && num <= 1); 169 if (num == -1) 170 { 171 ResetEvent( start_event ); 172 SetEvent( stop_event ); 173 } 174 else 175 { 176 DWORD ret = WaitForSingleObject(stop_event, 10000); 177 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); 178 } 179} 180 181static void cleanup_thread_sync_helpers(void) 182{ 183 CloseHandle(start_event); 184 CloseHandle(stop_event); 185} 186 187static DWORD tlsIndex; 188 189typedef struct { 190 int threadnum; 191 HANDLE *event; 192 DWORD *threadmem; 193} t1Struct; 194 195/* WinME supports OpenThread but doesn't know about access restrictions so 196 we require them to be either completely ignored or always obeyed. 197*/ 198static INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */ 199#define obey_ar(x) \ 200 (obeying_ars == 0 \ 201 ? ((x) \ 202 ? (obeying_ars = +1) \ 203 : ((obeying_ars = -1), \ 204 trace("not restricted, assuming consistent behaviour\n"))) \ 205 : (obeying_ars < 0) \ 206 ? ok(!(x), "access restrictions obeyed\n") \ 207 : ok( (x), "access restrictions not obeyed\n")) 208 209/* Basic test that simultaneous threads can access shared memory, 210 that the thread local storage routines work correctly, and that 211 threads actually run concurrently 212*/ 213static DWORD WINAPI threadFunc1(LPVOID p) 214{ 215 t1Struct *tstruct = p; 216 int i; 217/* write our thread # into shared memory */ 218 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId(); 219 ok(TlsSetValue(tlsIndex,(LPVOID)(INT_PTR)(tstruct->threadnum+1))!=0, 220 "TlsSetValue failed\n"); 221/* The threads synchronize before terminating. This is done by 222 Signaling an event, and waiting for all events to occur 223*/ 224 SetEvent(tstruct->event[tstruct->threadnum]); 225 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE); 226/* Double check that all threads really did run by validating that 227 they have all written to the shared memory. There should be no race 228 here, since all threads were synchronized after the write.*/ 229 for (i = 0; i < NUM_THREADS; i++) 230 ok(tstruct->threadmem[i] != 0, "expected threadmem[%d] != 0\n", i); 231 232 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */ 233 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" ); 234 235/* Check that no one changed our tls memory */ 236 ok((INT_PTR)TlsGetValue(tlsIndex)-1==tstruct->threadnum, 237 "TlsGetValue failed\n"); 238 return NUM_THREADS+tstruct->threadnum; 239} 240 241static DWORD WINAPI threadFunc2(LPVOID p) 242{ 243 return 99; 244} 245 246static DWORD WINAPI threadFunc3(LPVOID p) 247{ 248 HANDLE thread; 249 thread=GetCurrentThread(); 250 SuspendThread(thread); 251 return 99; 252} 253 254static DWORD WINAPI threadFunc4(LPVOID p) 255{ 256 HANDLE event = p; 257 if(event != NULL) { 258 SetEvent(event); 259 } 260 Sleep(99000); 261 return 0; 262} 263 264#if CHECK_STACK 265static DWORD WINAPI threadFunc5(LPVOID p) 266{ 267 DWORD *exitCode = p; 268 SYSTEM_INFO sysInfo; 269 sysInfo.dwPageSize=0; 270 GetSystemInfo(&sysInfo); 271 *exitCode=0; 272 __TRY 273 { 274 alloca(2*sysInfo.dwPageSize); 275 } 276 __EXCEPT(1) { 277 *exitCode=1; 278 } 279 __ENDTRY 280 return 0; 281} 282#endif 283 284static DWORD WINAPI threadFunc_SetEvent(LPVOID p) 285{ 286 SetEvent(p); 287 return 0; 288} 289 290static DWORD WINAPI threadFunc_CloseHandle(LPVOID p) 291{ 292 CloseHandle(p); 293 return 0; 294} 295 296struct thread_actctx_param 297{ 298 HANDLE thread_context; 299 HANDLE handle; 300}; 301 302static DWORD WINAPI thread_actctx_func(void *p) 303{ 304 struct thread_actctx_param *param = (struct thread_actctx_param*)p; 305 HANDLE cur; 306 BOOL ret; 307 308 cur = (void*)0xdeadbeef; 309 ret = GetCurrentActCtx(&cur); 310 ok(ret, "thread GetCurrentActCtx failed, %lu\n", GetLastError()); 311 ok(cur == param->handle, "got %p, expected %p\n", cur, param->handle); 312 param->thread_context = cur; 313 314 return 0; 315} 316 317static void create_function_addr_events(HANDLE events[2]) 318{ 319 char buffer[256]; 320 321 sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent); 322 events[0] = CreateEventA(NULL, FALSE, FALSE, buffer); 323 324 sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle); 325 events[1] = CreateEventA(NULL, FALSE, FALSE, buffer); 326} 327 328/* check CreateRemoteThread */ 329static VOID test_CreateRemoteThread(void) 330{ 331 HANDLE hProcess, hThread, hEvent, hRemoteEvent; 332 DWORD tid, ret, exitcode; 333 HANDLE hAddrEvents[2]; 334 335 hProcess = create_target_process("sleep"); 336 ok(hProcess != NULL, "Can't start process\n"); 337 338 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same 339 * address as in the child process */ 340 create_function_addr_events(hAddrEvents); 341 ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000); 342 if (ret == WAIT_TIMEOUT) 343 { 344 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n"); 345 return; 346 } 347 ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 events %ld\n", ret); 348 349 hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 350 ok(hEvent != NULL, "Can't create event, err=%lu\n", GetLastError()); 351 ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent, 352 0, FALSE, DUPLICATE_SAME_ACCESS); 353 ok(ret != 0, "DuplicateHandle failed, err=%lu\n", GetLastError()); 354 355 /* create suspended remote thread with entry point SetEvent() */ 356 SetLastError(0xdeadbeef); 357 hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent, 358 hRemoteEvent, CREATE_SUSPENDED, &tid); 359 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 360 { 361 win_skip("CreateRemoteThread is not implemented\n"); 362 goto cleanup; 363 } 364 ok(hThread != NULL, "CreateRemoteThread failed, err=%lu\n", GetLastError()); 365 ok(tid != 0, "null tid\n"); 366 ret = SuspendThread(hThread); 367 ok(ret == 1, "ret=%lu, err=%lu\n", ret, GetLastError()); 368 ret = ResumeThread(hThread); 369 ok(ret == 2, "ret=%lu, err=%lu\n", ret, GetLastError()); 370 371 /* thread still suspended, so wait times out */ 372 ret = WaitForSingleObject(hEvent, 1000); 373 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%lu\n", ret); 374 375 ret = ResumeThread(hThread); 376 ok(ret == 1, "ret=%lu, err=%lu\n", ret, GetLastError()); 377 378 /* wait that doesn't time out */ 379 ret = WaitForSingleObject(hEvent, 1000); 380 ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%lu\n", ret); 381 382 /* wait for thread end */ 383 ret = WaitForSingleObject(hThread, 1000); 384 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%lu\n", ret); 385 CloseHandle(hThread); 386 387 /* create and wait for remote thread with entry point CloseHandle() */ 388 hThread = CreateRemoteThread(hProcess, NULL, 0, 389 threadFunc_CloseHandle, 390 hRemoteEvent, 0, &tid); 391 ok(hThread != NULL, "CreateRemoteThread failed, err=%lu\n", GetLastError()); 392 ret = WaitForSingleObject(hThread, 1000); 393 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%lu\n", ret); 394 CloseHandle(hThread); 395 396 /* create remote thread with entry point SetEvent() */ 397 hThread = CreateRemoteThread(hProcess, NULL, 0, 398 threadFunc_SetEvent, 399 hRemoteEvent, 0, &tid); 400 ok(hThread != NULL, "CreateRemoteThread failed, err=%lu\n", GetLastError()); 401 402 /* closed handle, so wait times out */ 403 ret = WaitForSingleObject(hEvent, 1000); 404 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%lu\n", ret); 405 406 /* check that remote SetEvent() failed */ 407 ret = GetExitCodeThread(hThread, &exitcode); 408 ok(ret != 0, "GetExitCodeThread failed, err=%lu\n", GetLastError()); 409 if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n"); 410 CloseHandle(hThread); 411 412cleanup: 413 TerminateProcess(hProcess, 0); 414 CloseHandle(hEvent); 415 CloseHandle(hProcess); 416} 417 418/* Check basic functionality of CreateThread and Tls* functions */ 419static VOID test_CreateThread_basic(void) 420{ 421 HANDLE thread[NUM_THREADS],event[NUM_THREADS]; 422 DWORD threadid[NUM_THREADS],curthreadId; 423 DWORD threadmem[NUM_THREADS]; 424 DWORD exitCode; 425 t1Struct tstruct[NUM_THREADS]; 426 int error; 427 DWORD i,j; 428 DWORD GLE, ret; 429 DWORD tid; 430 BOOL bRet; 431 432 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */ 433 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" ); 434 435/* Retrieve current Thread ID for later comparisons */ 436 curthreadId=GetCurrentThreadId(); 437/* Allocate some local storage */ 438 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n"); 439/* Create events for thread synchronization */ 440 for(i=0;i<NUM_THREADS;i++) { 441 threadmem[i]=0; 442/* Note that it doesn't matter what type of event we choose here. This 443 test isn't trying to thoroughly test events 444*/ 445 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL); 446 tstruct[i].threadnum=i; 447 tstruct[i].threadmem=threadmem; 448 tstruct[i].event=event; 449 } 450 451/* Test that passing arguments to threads works okay */ 452 for(i=0;i<NUM_THREADS;i++) { 453 thread[i] = CreateThread(NULL,0,threadFunc1, 454 &tstruct[i],0,&threadid[i]); 455 ok(thread[i]!=NULL,"Create Thread failed\n"); 456 } 457/* Test that the threads actually complete */ 458 for(i=0;i<NUM_THREADS;i++) { 459 error=WaitForSingleObject(thread[i],5000); 460 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n"); 461 if(error!=WAIT_OBJECT_0) { 462 TerminateThread(thread[i],i+NUM_THREADS); 463 } 464 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n"); 465 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n"); 466 } 467/* Test that each thread executed in its parent's address space 468 (it was able to change threadmem and pass that change back to its parent) 469 and that each thread id was independent). Note that we prove that the 470 threads actually execute concurrently by having them block on each other 471 in threadFunc1 472*/ 473 for(i=0;i<NUM_THREADS;i++) { 474 error=0; 475 for(j=i+1;j<NUM_THREADS;j++) { 476 if (threadmem[i]==threadmem[j]) { 477 error=1; 478 } 479 } 480 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId, 481 "Thread did not execute successfully\n"); 482 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n"); 483 } 484 485 SetLastError(0xCAFEF00D); 486 bRet = TlsFree(tlsIndex); 487 ok(bRet, "TlsFree failed: %08lx\n", GetLastError()); 488 ok(GetLastError()==0xCAFEF00D, 489 "GetLastError: expected 0xCAFEF00D, got %08lx\n", GetLastError()); 490 491 /* Test freeing an already freed TLS index */ 492 SetLastError(0xCAFEF00D); 493 ok(TlsFree(tlsIndex)==0,"TlsFree succeeded\n"); 494 ok(GetLastError()==ERROR_INVALID_PARAMETER, 495 "GetLastError: expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); 496 497 /* Test how passing NULL as a pointer to threadid works */ 498 SetLastError(0xFACEaBAD); 499 thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid); 500 GLE = GetLastError(); 501 if (thread[0]) { /* NT */ 502 ok(GLE==0xFACEaBAD, "CreateThread set last error to %ld, expected 4207848365\n", GLE); 503 ret = WaitForSingleObject(thread[0],100); 504 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n"); 505 ret = GetExitCodeThread(thread[0],&exitCode); 506 ok(ret!=0, "GetExitCodeThread returned %ld (expected nonzero)\n", ret); 507 ok(exitCode==99, "threadFunc2 exited with code: %ld (expected 99)\n", exitCode); 508 ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n"); 509 } 510 else { /* 9x */ 511 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %ld, expected 87\n", GLE); 512 } 513} 514 515/* Check that using the CREATE_SUSPENDED flag works */ 516static VOID test_CreateThread_suspended(void) 517{ 518 HANDLE thread; 519 DWORD threadId; 520 DWORD suspend_count; 521 int error; 522 523 thread = CreateThread(NULL,0,threadFunc2,NULL, 524 CREATE_SUSPENDED,&threadId); 525 ok(thread!=NULL,"Create Thread failed\n"); 526/* Check that the thread is suspended */ 527 ok(SuspendThread(thread)==1,"Thread did not start suspended\n"); 528 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n"); 529/* Check that resume thread didn't actually start the thread. I can't think 530 of a better way of checking this than just waiting. I am not sure if this 531 will work on slow computers. 532*/ 533 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT, 534 "ResumeThread should not have actually started the thread\n"); 535/* Now actually resume the thread and make sure that it actually completes*/ 536 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n"); 537 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0, 538 "Thread did not resume\n"); 539 if(error!=WAIT_OBJECT_0) { 540 TerminateThread(thread,1); 541 } 542 543 suspend_count = SuspendThread(thread); 544 ok(suspend_count == -1, "SuspendThread returned %ld, expected -1\n", suspend_count); 545 546 suspend_count = ResumeThread(thread); 547 ok(suspend_count == 0 || 548 broken(suspend_count == -1), /* win9x */ 549 "ResumeThread returned %ld, expected 0\n", suspend_count); 550 551 ok(CloseHandle(thread)!=0,"CloseHandle failed\n"); 552} 553 554/* Check that SuspendThread and ResumeThread work */ 555static VOID test_SuspendThread(void) 556{ 557 HANDLE thread,access_thread; 558 DWORD threadId,exitCode,error; 559 int i; 560 561 thread = CreateThread(NULL,0,threadFunc3,NULL, 562 0,&threadId); 563 ok(thread!=NULL,"Create Thread failed\n"); 564/* Check that the thread is suspended */ 565/* Note that this is a polling method, and there is a race between 566 SuspendThread being called (in the child, and the loop below timing out, 567 so the test could fail on a heavily loaded or slow computer. 568*/ 569 error=0; 570 for(i=0;error==0 && i<100;i++) { 571 error=SuspendThread(thread); 572 ResumeThread(thread); 573 if(error==0) { 574 Sleep(50); 575 i++; 576 } 577 } 578 ok(error==1,"SuspendThread did not work\n"); 579/* check that access restrictions are obeyed */ 580 if (pOpenThread) { 581 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_SUSPEND_RESUME), 582 0,threadId); 583 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n"); 584 if (access_thread!=NULL) { 585 obey_ar(SuspendThread(access_thread)==~0U); 586 obey_ar(ResumeThread(access_thread)==~0U); 587 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n"); 588 } 589 } 590/* Double check that the thread really is suspended */ 591 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE, 592 "Thread did not really suspend\n"); 593/* Resume the thread, and make sure it actually completes */ 594 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n"); 595 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0, 596 "Thread did not resume\n"); 597 if(error!=WAIT_OBJECT_0) { 598 TerminateThread(thread,1); 599 } 600 /* Trying to suspend a terminated thread should fail */ 601 error=SuspendThread(thread); 602 ok(error==~0U, "wrong return code: %ld\n", error); 603 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld\n", GetLastError()); 604 605 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n"); 606} 607 608/* Check that TerminateThread works properly 609*/ 610static VOID test_TerminateThread(void) 611{ 612 HANDLE thread,access_thread,event; 613 DWORD threadId,exitCode; 614 event=CreateEventA(NULL,TRUE,FALSE,NULL); 615 thread = CreateThread(NULL,0,threadFunc4,event,0,&threadId); 616 ok(thread!=NULL,"Create Thread failed\n"); 617/* TerminateThread has a race condition in Wine. If the thread is terminated 618 before it starts, it leaves a process behind. Therefore, we wait for the 619 thread to signal that it has started. There is no easy way to force the 620 race to occur, so we don't try to find it. 621*/ 622 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0, 623 "TerminateThread didn't work\n"); 624/* check that access restrictions are obeyed */ 625 if (pOpenThread) { 626 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & (~THREAD_TERMINATE), 627 0,threadId); 628 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n"); 629 if (access_thread!=NULL) { 630 obey_ar(TerminateThread(access_thread,99)==0); 631 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n"); 632 } 633 } 634/* terminate a job and make sure it terminates */ 635 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n"); 636 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0, 637 "TerminateThread didn't work\n"); 638 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE, 639 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n"); 640 ok(exitCode==99, "TerminateThread returned invalid exit code\n"); 641 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n"); 642} 643 644/* Check if CreateThread obeys the specified stack size. This code does 645 not work properly, and is currently disabled 646*/ 647static VOID test_CreateThread_stack(void) 648{ 649#if CHECK_STACK 650/* The only way I know of to test the stack size is to use alloca 651 and __try/__except. However, this is probably not portable, 652 and I couldn't get it to work under Wine anyhow. However, here 653 is the code which should allow for testing that CreateThread 654 respects the stack-size limit 655*/ 656 HANDLE thread; 657 DWORD threadId,exitCode; 658 659 SYSTEM_INFO sysInfo; 660 sysInfo.dwPageSize=0; 661 GetSystemInfo(&sysInfo); 662 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n"); 663 thread = CreateThread(NULL,sysInfo.dwPageSize, 664 threadFunc5,&exitCode, 665 0,&threadId); 666 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0, 667 "TerminateThread didn't work\n"); 668 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n"); 669 ok(CloseHandle(thread)!=0,"CloseHandle failed\n"); 670#endif 671} 672 673/* Check whether setting/retrieving thread priorities works */ 674static VOID test_thread_priority(void) 675{ 676 HANDLE curthread,access_thread; 677 DWORD curthreadId,exitCode; 678 int min_priority=-2,max_priority=2; 679 BOOL disabled,rc; 680 int i; 681 682 curthread=GetCurrentThread(); 683 curthreadId=GetCurrentThreadId(); 684/* Check thread priority */ 685/* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it 686 is -2 to 2. However, even on a real Win2k system, using thread 687 priorities beyond the -2 to 2 range does not work. If you want to try 688 anyway, enable USE_EXTENDED_PRIORITIES 689*/ 690 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL, 691 "GetThreadPriority Failed\n"); 692 693 if (pOpenThread) { 694/* check that access control is obeyed */ 695 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & 696 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION), 697 0,curthreadId); 698 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n"); 699 if (access_thread!=NULL) { 700 obey_ar(SetThreadPriority(access_thread,1)==0); 701 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN); 702 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0); 703 ok(CloseHandle(access_thread),"Error Closing thread handle\n"); 704 } 705 } 706#if USE_EXTENDED_PRIORITIES 707 min_priority=-7; max_priority=6; 708#endif 709 for(i=min_priority;i<=max_priority;i++) { 710 ok(SetThreadPriority(curthread,i)!=0, 711 "SetThreadPriority Failed for priority: %d\n",i); 712 ok(GetThreadPriority(curthread)==i, 713 "GetThreadPriority Failed for priority: %d\n",i); 714 } 715 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0, 716 "SetThreadPriority Failed\n"); 717 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL, 718 "GetThreadPriority Failed\n"); 719 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0, 720 "SetThreadPriority Failed\n"); 721 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE, 722 "GetThreadPriority Failed\n"); 723 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n"); 724 725/* Check that the thread priority is not changed if SetThreadPriority 726 is called with a value outside of the max/min range */ 727 SetThreadPriority(curthread,min_priority); 728 SetLastError(0xdeadbeef); 729 rc = SetThreadPriority(curthread,min_priority-1); 730 731 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n"); 732 ok(GetLastError() == ERROR_INVALID_PARAMETER || 733 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */, 734 "SetThreadPriority error %ld, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n", 735 GetLastError()); 736 ok(GetThreadPriority(curthread)==min_priority, 737 "GetThreadPriority didn't return min_priority\n"); 738 739 SetThreadPriority(curthread,max_priority); 740 SetLastError(0xdeadbeef); 741 rc = SetThreadPriority(curthread,max_priority+1); 742 743 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n"); 744 ok(GetLastError() == ERROR_INVALID_PARAMETER || 745 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */, 746 "SetThreadPriority error %ld, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n", 747 GetLastError()); 748 ok(GetThreadPriority(curthread)==max_priority, 749 "GetThreadPriority didn't return max_priority\n"); 750 751/* Check thread priority boost */ 752 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost) 753 return; /* Win9x */ 754 755 SetLastError(0xdeadbeef); 756 rc=pGetThreadPriorityBoost(curthread,&disabled); 757 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) 758 { 759 win_skip("GetThreadPriorityBoost is not implemented on WinME\n"); 760 return; 761 } 762 763 ok(rc!=0,"error=%ld\n",GetLastError()); 764 765 if (pOpenThread) { 766/* check that access control is obeyed */ 767 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & 768 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION), 769 0,curthreadId); 770 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n"); 771 if (access_thread!=NULL) { 772 todo_wine obey_ar(pSetThreadPriorityBoost(access_thread,1)==0); 773 todo_wine obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0); 774 ok(CloseHandle(access_thread),"Error Closing thread handle\n"); 775 } 776 } 777 778 rc = pSetThreadPriorityBoost(curthread,1); 779 ok( rc != 0, "error=%ld\n",GetLastError()); 780 todo_wine { 781 rc=pGetThreadPriorityBoost(curthread,&disabled); 782 ok(rc!=0 && disabled==1, 783 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); 784 } 785 786 rc = pSetThreadPriorityBoost(curthread,0); 787 ok( rc != 0, "error=%ld\n",GetLastError()); 788 rc=pGetThreadPriorityBoost(curthread,&disabled); 789 ok(rc!=0 && disabled==0, 790 "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); 791} 792 793/* check the GetThreadTimes function */ 794static VOID test_GetThreadTimes(void) 795{ 796 HANDLE thread,access_thread=NULL; 797 FILETIME creationTime,exitTime,kernelTime,userTime; 798 DWORD threadId; 799 int error; 800 801 thread = CreateThread(NULL,0,threadFunc2,NULL, 802 CREATE_SUSPENDED,&threadId); 803 804 ok(thread!=NULL,"Create Thread failed\n"); 805/* check that access control is obeyed */ 806 if (pOpenThread) { 807 access_thread=pOpenThread(THREAD_ALL_ACCESS_NT4 & 808 (~THREAD_QUERY_INFORMATION), 0,threadId); 809 ok(access_thread!=NULL, 810 "OpenThread returned an invalid handle\n"); 811 } 812 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n"); 813 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0, 814 "ResumeThread didn't work\n"); 815 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99; 816 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99; 817 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99; 818 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99; 819/* GetThreadTimes should set all of the parameters passed to it */ 820 error=GetThreadTimes(thread,&creationTime,&exitTime, 821 &kernelTime,&userTime); 822 823 if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 824 win_skip("GetThreadTimes is not implemented\n"); 825 else { 826 ok(error!=0,"GetThreadTimes failed\n"); 827 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99, 828 "creationTime was invalid\n"); 829 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99, 830 "exitTime was invalid\n"); 831 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99, 832 "kernelTimewas invalid\n"); 833 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99, 834 "userTime was invalid\n"); 835 ok(CloseHandle(thread)!=0,"CloseHandle failed\n"); 836 if(access_thread!=NULL) 837 { 838 error=GetThreadTimes(access_thread,&creationTime,&exitTime, 839 &kernelTime,&userTime); 840 obey_ar(error==0); 841 } 842 } 843 if(access_thread!=NULL) { 844 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n"); 845 } 846} 847 848/* Check the processor affinity functions */ 849/* NOTE: These functions should also be checked that they obey access control 850*/ 851static VOID test_thread_processor(void) 852{ 853 HANDLE curthread,curproc; 854 DWORD_PTR processMask,systemMask,retMask; 855 SYSTEM_INFO sysInfo; 856 BOOL is_wow64, old_wow64 = FALSE; 857 DWORD ret; 858 859 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; 860 861 if (is_wow64) 862 { 863 TEB64 *teb64 = ULongToPtr(NtCurrentTeb()->GdiBatchCount); 864 if (teb64) 865 { 866 PEB64 *peb64 = ULongToPtr(teb64->Peb); 867 old_wow64 = !peb64->LdrData; 868 } 869 } 870 871 sysInfo.dwNumberOfProcessors=0; 872 GetSystemInfo(&sysInfo); 873 ok(sysInfo.dwNumberOfProcessors>0, 874 "GetSystemInfo failed to return a valid # of processors\n"); 875/* Use the current Thread/process for all tests */ 876 curthread=GetCurrentThread(); 877 ok(curthread!=NULL,"GetCurrentThread failed\n"); 878 curproc=GetCurrentProcess(); 879 ok(curproc!=NULL,"GetCurrentProcess failed\n"); 880/* Check the Affinity Mask functions */ 881 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0, 882 "GetProcessAffinityMask failed\n"); 883 ok(SetThreadAffinityMask(curthread,processMask)==processMask, 884 "SetThreadAffinityMask failed\n"); 885 ok(SetThreadAffinityMask(curthread,processMask+1)==0, 886 "SetThreadAffinityMask passed for an illegal processor\n"); 887/* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */ 888 retMask = SetThreadAffinityMask(curthread,~0); 889 ok(broken(retMask==0) || retMask==processMask, 890 "SetThreadAffinityMask(thread,-1) failed to request all processors.\n"); 891 892 if (retMask == processMask) 893 { 894 /* Show that the "all processors" flag is handled in ntdll */ 895 DWORD_PTR mask = ~0u; 896 NTSTATUS status = pNtSetInformationThread(curthread, ThreadAffinityMask, &mask, sizeof(mask)); 897 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS in NtSetInformationThread, got %lx\n", status); 898 } 899 900 if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG)) 901 { 902 /* only the low 32-bits matter */ 903 retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0); 904 ok(retMask == processMask, "SetThreadAffinityMask failed\n"); 905 retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0 >> 3); 906 ok(retMask == processMask, "SetThreadAffinityMask failed\n"); 907 } 908 909 SetLastError(0xdeadbeef); 910 ret = SetThreadIdealProcessor(GetCurrentThread(), 0); 911 ok(ret != ~0u, "Unexpected return value %lu.\n", ret); 912 913 if (is_wow64) 914 { 915 SetLastError(0xdeadbeef); 916 ret = SetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS + 1); 917 todo_wine_if(old_wow64) 918 ok(ret != ~0u, "Unexpected return value %lu.\n", ret); 919 920 SetLastError(0xdeadbeef); 921 ret = SetThreadIdealProcessor(GetCurrentThread(), 65); 922 ok(ret == ~0u, "Unexpected return value %lu.\n", ret); 923 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected error %ld.\n", GetLastError()); 924 } 925 else 926 { 927 SetLastError(0xdeadbeef); 928 ret = SetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS+1); 929#if defined(__REACTOS__) && defined(_WIN64) 930 ok(ret == ~0u || broken(ret == 0) /* x86_64 */, "Unexpected return value %lu.\n", ret); 931 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* x86_64 */, "Unexpected error %ld.\n", GetLastError()); 932#else 933 ok(ret == ~0u, "Unexpected return value %lu.\n", ret); 934 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected error %ld.\n", GetLastError()); 935#endif 936 } 937 938 ret = SetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS); 939 ok(ret != ~0u, "Unexpected return value %lu.\n", ret); 940 941 if (pGetThreadGroupAffinity && pSetThreadGroupAffinity) 942 { 943 GROUP_AFFINITY affinity, affinity_new; 944 NTSTATUS status; 945 946 memset(&affinity, 0, sizeof(affinity)); 947 ok(pGetThreadGroupAffinity(curthread, &affinity), "GetThreadGroupAffinity failed\n"); 948 949 SetLastError(0xdeadbeef); 950 ok(!pGetThreadGroupAffinity(curthread, NULL), "GetThreadGroupAffinity succeeded\n"); 951 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_NOACCESS), /* Win 7 and 8 */ 952 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); 953 ok(affinity.Group == 0, "Expected group 0 got %u\n", affinity.Group); 954 955 memset(&affinity_new, 0, sizeof(affinity_new)); 956 affinity_new.Group = 0; 957 affinity_new.Mask = affinity.Mask; 958 ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n"); 959 ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %Ix, got %Ix\n", 960 affinity_new.Mask, affinity.Mask); 961 962 /* show that the "all processors" flag is not supported for SetThreadGroupAffinity */ 963 if (sysInfo.dwNumberOfProcessors < 8 * sizeof(DWORD_PTR)) 964 { 965 affinity_new.Group = 0; 966 affinity_new.Mask = ~(DWORD_PTR)0; 967 SetLastError(0xdeadbeef); 968 ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n"); 969 ok(GetLastError() == ERROR_INVALID_PARAMETER, 970 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); 971 } 972 973 affinity_new.Group = 1; /* assumes that you have less than 64 logical processors */ 974 affinity_new.Mask = 0x1; 975 SetLastError(0xdeadbeef); 976 ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n"); 977 ok(GetLastError() == ERROR_INVALID_PARAMETER, 978 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); 979 980 SetLastError(0xdeadbeef); 981 ok(!pSetThreadGroupAffinity(curthread, NULL, NULL), "SetThreadGroupAffinity succeeded\n"); 982 ok(GetLastError() == ERROR_NOACCESS, 983 "Expected ERROR_NOACCESS, got %ld\n", GetLastError()); 984 985 /* show that the access violation was detected in ntdll */ 986 status = pNtSetInformationThread(curthread, ThreadGroupInformation, NULL, sizeof(affinity_new)); 987 ok(status == STATUS_ACCESS_VIOLATION, 988 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", status); 989 990 /* restore original mask */ 991 affinity_new.Group = 0; 992 affinity_new.Mask = affinity.Mask; 993 SetLastError(0xdeadbeef); 994 ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n"); 995 ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %Ix, got %Ix\n", 996 affinity_new.Mask, affinity.Mask); 997 } 998 else 999 win_skip("Get/SetThreadGroupAffinity not available\n"); 1000} 1001 1002static VOID test_GetCurrentThreadStackLimits(void) 1003{ 1004 ULONG_PTR low = 0, high = 0; 1005 1006 if (!pGetCurrentThreadStackLimits) 1007 { 1008 win_skip("GetCurrentThreadStackLimits not available.\n"); 1009 return; 1010 } 1011 1012 if (0) 1013 { 1014 /* crashes on native */ 1015 pGetCurrentThreadStackLimits(NULL, NULL); 1016 pGetCurrentThreadStackLimits(NULL, &high); 1017 pGetCurrentThreadStackLimits(&low, NULL); 1018 } 1019 1020 pGetCurrentThreadStackLimits(&low, &high); 1021 ok(low == (ULONG_PTR)NtCurrentTeb()->DeallocationStack, "expected %p, got %Ix\n", NtCurrentTeb()->DeallocationStack, low); 1022 ok(high == (ULONG_PTR)NtCurrentTeb()->Tib.StackBase, "expected %p, got %Ix\n", NtCurrentTeb()->Tib.StackBase, high); 1023} 1024 1025static void test_SetThreadStackGuarantee(void) 1026{ 1027 ULONG size; 1028 BOOL ret; 1029 1030 if (!pSetThreadStackGuarantee) 1031 { 1032 win_skip("SetThreadStackGuarantee not available.\n"); 1033 return; 1034 } 1035 size = 0; 1036 ret = pSetThreadStackGuarantee( &size ); 1037 ok( ret, "failed err %lu\n", GetLastError() ); 1038 ok( size == 0, "wrong size %lu\n", size ); 1039 ok( NtCurrentTeb()->GuaranteedStackBytes == 0, "wrong teb %lu\n", 1040 NtCurrentTeb()->GuaranteedStackBytes ); 1041 size = 0xdeadbef; 1042 ret = pSetThreadStackGuarantee( &size ); 1043 ok( !ret, "succeeded\n" ); 1044 ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_ADDRESS, 1045 "wrong error %lu\n", GetLastError()); 1046 ok( size == 0, "wrong size %lu\n", size ); 1047 ok( NtCurrentTeb()->GuaranteedStackBytes == 0, "wrong teb %lu\n", 1048 NtCurrentTeb()->GuaranteedStackBytes ); 1049 size = 200; 1050 ret = pSetThreadStackGuarantee( &size ); 1051 ok( ret, "failed err %lu\n", GetLastError() ); 1052 ok( size == 0, "wrong size %lu\n", size ); 1053 ok( NtCurrentTeb()->GuaranteedStackBytes == 4096 * sizeof(void *) / 4, "wrong teb %lu\n", 1054 NtCurrentTeb()->GuaranteedStackBytes ); 1055 size = 5000; 1056 ret = pSetThreadStackGuarantee( &size ); 1057 ok( ret, "failed err %lu\n", GetLastError() ); 1058 ok( size == 4096 * sizeof(void *) / 4, "wrong size %lu\n", size ); 1059 ok( NtCurrentTeb()->GuaranteedStackBytes == 8192, "wrong teb %lu\n", 1060 NtCurrentTeb()->GuaranteedStackBytes ); 1061 size = 2000; 1062 ret = pSetThreadStackGuarantee( &size ); 1063 ok( ret, "failed err %lu\n", GetLastError() ); 1064 ok( size == 8192, "wrong size %lu\n", size ); 1065 ok( NtCurrentTeb()->GuaranteedStackBytes == 8192, "wrong teb %lu\n", 1066 NtCurrentTeb()->GuaranteedStackBytes ); 1067 size = 10000; 1068 ret = pSetThreadStackGuarantee( &size ); 1069 ok( ret, "failed err %lu\n", GetLastError() ); 1070 ok( size == 8192, "wrong size %lu\n", size ); 1071 ok( NtCurrentTeb()->GuaranteedStackBytes == 12288, "wrong teb %lu\n", 1072 NtCurrentTeb()->GuaranteedStackBytes ); 1073 ret = pSetThreadStackGuarantee( &size ); 1074 ok( ret, "failed err %lu\n", GetLastError() ); 1075 ok( size == 12288, "wrong size %lu\n", size ); 1076 ok( NtCurrentTeb()->GuaranteedStackBytes == 12288, "wrong teb %lu\n", 1077 NtCurrentTeb()->GuaranteedStackBytes ); 1078} 1079 1080static VOID test_GetThreadExitCode(void) 1081{ 1082 DWORD exitCode, threadid; 1083 DWORD GLE, ret; 1084 HANDLE thread; 1085 1086 ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode); 1087 ok(ret==0, "GetExitCodeThread returned non zero value: %ld\n", ret); 1088 GLE = GetLastError(); 1089 ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %ld (expected 6)\n", GLE); 1090 1091 thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid); 1092 ret = WaitForSingleObject(thread,100); 1093 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n"); 1094 ret = GetExitCodeThread(thread,&exitCode); 1095 ok(ret==exitCode || ret==1, 1096 "GetExitCodeThread returned %ld (expected 1 or %ld)\n", ret, exitCode); 1097 ok(exitCode==99, "threadFunc2 exited with code %ld (expected 99)\n", exitCode); 1098 ok(CloseHandle(thread)!=0,"Error closing thread handle\n"); 1099} 1100 1101#ifdef __i386__ 1102 1103static int test_value = 0; 1104static HANDLE event; 1105 1106static void WINAPI set_test_val( int val ) 1107{ 1108 test_value += val; 1109 ExitThread(0); 1110} 1111 1112static DWORD WINAPI threadFunc6(LPVOID p) 1113{ 1114 SetEvent( event ); 1115 Sleep( 1000 ); 1116 test_value *= (int)p; 1117 return 0; 1118} 1119 1120static void test_SetThreadContext(void) 1121{ 1122 CONTEXT ctx; 1123 int *stack; 1124 HANDLE thread; 1125 DWORD threadid; 1126 DWORD prevcount; 1127 BOOL ret; 1128 1129 SetLastError(0xdeadbeef); 1130 event = CreateEventW( NULL, TRUE, FALSE, NULL ); 1131 thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid ); 1132 ok( thread != NULL, "CreateThread failed : (%ld)\n", GetLastError() ); 1133 if (!thread) 1134 { 1135 trace("Thread creation failed, skipping rest of test\n"); 1136 return; 1137 } 1138 WaitForSingleObject( event, INFINITE ); 1139 SuspendThread( thread ); 1140 CloseHandle( event ); 1141 1142 ctx.ContextFlags = CONTEXT_FULL; 1143 SetLastError(0xdeadbeef); 1144 ret = GetThreadContext( thread, &ctx ); 1145 ok( ret, "GetThreadContext failed : (%lu)\n", GetLastError() ); 1146 1147 if (ret) 1148 { 1149 /* simulate a call to set_test_val(10) */ 1150 stack = (int *)ctx.Esp; 1151 stack[-1] = 10; 1152 stack[-2] = ctx.Eip; 1153 ctx.Esp -= 2 * sizeof(int *); 1154 ctx.Eip = (DWORD)set_test_val; 1155 SetLastError(0xdeadbeef); 1156 ret = SetThreadContext( thread, &ctx ); 1157 ok( ret, "SetThreadContext failed : (%ld)\n", GetLastError() ); 1158 } 1159 1160 SetLastError(0xdeadbeef); 1161 prevcount = ResumeThread( thread ); 1162 ok ( prevcount == 1, "Previous suspend count (%ld) instead of 1, last error : (%ld)\n", 1163 prevcount, GetLastError() ); 1164 1165 WaitForSingleObject( thread, INFINITE ); 1166 ok( test_value == 10, "test_value %d\n", test_value ); 1167 1168 ctx.ContextFlags = CONTEXT_FULL; 1169 SetLastError(0xdeadbeef); 1170 ret = GetThreadContext( thread, &ctx ); 1171 ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) || 1172 (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */ 1173 broken(ret), /* 32bit application on NT 5.x 64bit */ 1174 "got %d with %lu (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n", 1175 ret, GetLastError() ); 1176 1177 SetLastError(0xdeadbeef); 1178 ret = SetThreadContext( thread, &ctx ); 1179 ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) || 1180 (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */ 1181 broken(ret), /* 32bit application on NT 5.x 64bit */ 1182 "got %d with %lu (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n", 1183 ret, GetLastError() ); 1184 1185 CloseHandle( thread ); 1186} 1187 1188static DWORD WINAPI test_stack( void *arg ) 1189{ 1190 DWORD *stack = (DWORD *)(((DWORD)&arg & ~0xfff) + 0x1000); 1191 1192 ok( stack == NtCurrentTeb()->Tib.StackBase, "wrong stack %p/%p\n", 1193 stack, NtCurrentTeb()->Tib.StackBase ); 1194 ok( !stack[-1], "wrong data %p = %08lx\n", stack - 1, stack[-1] ); 1195 return 0; 1196} 1197 1198static void test_GetThreadContext(void) 1199{ 1200 CONTEXT ctx; 1201 BOOL ret; 1202 HANDLE thread; 1203 1204 memset(&ctx, 0xcc, sizeof(ctx)); 1205 ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 1206 ret = GetThreadContext(GetCurrentThread(), &ctx); 1207 ok(ret, "GetThreadContext failed: %lu\n", GetLastError()); 1208 ok(ctx.ContextFlags == CONTEXT_DEBUG_REGISTERS, "ContextFlags = %lx\n", ctx.ContextFlags); 1209 ok(!ctx.Dr0, "Dr0 = %lx\n", ctx.Dr0); 1210 ok(!ctx.Dr1, "Dr0 = %lx\n", ctx.Dr0); 1211 1212 thread = CreateThread( NULL, 0, test_stack, (void *)0x1234, 0, NULL ); 1213 WaitForSingleObject( thread, 1000 ); 1214 CloseHandle( thread ); 1215} 1216 1217static void test_GetThreadSelectorEntry(void) 1218{ 1219 LDT_ENTRY entry; 1220 CONTEXT ctx; 1221 DWORD limit; 1222 void *base; 1223 BOOL ret; 1224 1225 memset(&ctx, 0x11, sizeof(ctx)); 1226 ctx.ContextFlags = CONTEXT_SEGMENTS | CONTEXT_CONTROL; 1227 ret = GetThreadContext(GetCurrentThread(), &ctx); 1228 ok(ret, "GetThreadContext error %lu\n", GetLastError()); 1229 ok(!HIWORD(ctx.SegCs), "expected HIWORD(SegCs) == 0, got %lu\n", ctx.SegCs); 1230 ok(!HIWORD(ctx.SegDs), "expected HIWORD(SegDs) == 0, got %lu\n", ctx.SegDs); 1231 ok(!HIWORD(ctx.SegFs), "expected HIWORD(SegFs) == 0, got %lu\n", ctx.SegFs); 1232 1233 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegCs, &entry); 1234 ok(ret, "GetThreadSelectorEntry(SegCs) error %lu\n", GetLastError()); 1235 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &entry); 1236 ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); 1237 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs & ~3, &entry); 1238 ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); 1239 ret = GetThreadSelectorEntry(GetCurrentThread(), 0, &entry); 1240 ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); 1241 ret = GetThreadSelectorEntry(GetCurrentThread(), 3, &entry); 1242 ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); 1243 SetLastError( 0xdeadbeef ); 1244 ret = GetThreadSelectorEntry(GetCurrentThread(), 0xdeadbeef, &entry); 1245 ok(!ret, "GetThreadSelectorEntry(invalid) succeeded\n"); 1246 ok( GetLastError() == ERROR_GEN_FAILURE 1247 || GetLastError() == ERROR_INVALID_THREAD_ID /* 32-bit */, "wrong error %lu\n", GetLastError() ); 1248 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs + 0x100, &entry); 1249 ok(!ret, "GetThreadSelectorEntry(invalid) succeeded\n"); 1250 ok( GetLastError() == ERROR_GEN_FAILURE 1251 || GetLastError() == ERROR_NOACCESS /* 32-bit */, "wrong error %lu\n", GetLastError() ); 1252 1253 memset(&entry, 0x11, sizeof(entry)); 1254 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegFs, &entry); 1255 ok(ret, "GetThreadSelectorEntry(SegFs) error %lu\n", GetLastError()); 1256 entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */ 1257 1258 base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow); 1259 limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow; 1260 1261 ok(base == NtCurrentTeb(), "expected %p, got %p\n", NtCurrentTeb(), base); 1262 ok(limit == 0x0fff || limit == 0x4000, "expected 0x0fff or 0x4000, got %#lx\n", limit); 1263 ok(entry.HighWord.Bits.Type == 0x12, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type); 1264 ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl); 1265 ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres); 1266 ok(entry.HighWord.Bits.Sys == 0, "expected 0, got %u\n", entry.HighWord.Bits.Sys); 1267 ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0); 1268 ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big); 1269 ok(entry.HighWord.Bits.Granularity == 0, "expected 0, got %u\n", entry.HighWord.Bits.Granularity); 1270 1271 memset(&entry, 0x11, sizeof(entry)); 1272 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegCs, &entry); 1273 ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); 1274 entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */ 1275 base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow); 1276 limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow; 1277 1278 ok(base == 0, "got base %p\n", base); 1279 ok(limit == ~0u >> 12, "got limit %#lx\n", limit); 1280 ok(entry.HighWord.Bits.Type == 0x1a, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type); 1281 ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl); 1282 ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres); 1283 ok(entry.HighWord.Bits.Sys == 0, "expected 0, got %u\n", entry.HighWord.Bits.Sys); 1284 ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0); 1285 ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big); 1286 ok(entry.HighWord.Bits.Granularity == 1, "expected 1, got %u\n", entry.HighWord.Bits.Granularity); 1287 1288 memset(&entry, 0x11, sizeof(entry)); 1289 ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &entry); 1290 ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); 1291 entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */ 1292 base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow); 1293 limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow; 1294 1295 ok(base == 0, "got base %p\n", base); 1296 ok(limit == ~0u >> 12, "got limit %#lx\n", limit); 1297 ok(entry.HighWord.Bits.Type == 0x12, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type); 1298 ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl); 1299 ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres); 1300 ok(entry.HighWord.Bits.Sys == 0, "expected 0, got %u\n", entry.HighWord.Bits.Sys); 1301 ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0); 1302 ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big); 1303 ok(entry.HighWord.Bits.Granularity == 1, "expected 1, got %u\n", entry.HighWord.Bits.Granularity); 1304} 1305 1306#endif /* __i386__ */ 1307 1308static HANDLE finish_event; 1309static LONG times_executed; 1310 1311static DWORD CALLBACK work_function(void *p) 1312{ 1313 LONG executed = InterlockedIncrement(&times_executed); 1314 1315 if (executed == 100) 1316 SetEvent(finish_event); 1317 return 0; 1318} 1319 1320static void test_QueueUserWorkItem(void) 1321{ 1322 INT_PTR i; 1323 DWORD wait_result; 1324 DWORD before, after; 1325 1326 /* QueueUserWorkItem not present on win9x */ 1327 if (!pQueueUserWorkItem) return; 1328 1329 finish_event = CreateEventW(NULL, TRUE, FALSE, NULL); 1330 1331 before = GetTickCount(); 1332 1333 for (i = 0; i < 100; i++) 1334 { 1335 BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT); 1336 ok(ret, "QueueUserWorkItem failed with error %ld\n", GetLastError()); 1337 } 1338 1339 wait_result = WaitForSingleObject(finish_event, 10000); 1340 1341 after = GetTickCount(); 1342 trace("100 QueueUserWorkItem calls took %ldms\n", after - before); 1343 ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%lx\n", wait_result); 1344 1345 ok(times_executed == 100, "didn't execute all of the work items\n"); 1346} 1347 1348static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired) 1349{ 1350 HANDLE event = p; 1351 SetEvent(event); 1352 ok(!TimerOrWaitFired, "wait shouldn't have timed out\n"); 1353} 1354 1355static void CALLBACK wait_complete_function(PVOID p, BOOLEAN TimerOrWaitFired) 1356{ 1357 HANDLE event = p; 1358 DWORD res; 1359 ok(!TimerOrWaitFired, "wait shouldn't have timed out\n"); 1360 res = WaitForSingleObject(event, INFINITE); 1361 ok(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", res); 1362} 1363 1364static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired) 1365{ 1366 HANDLE event = p; 1367 SetEvent(event); 1368 ok(TimerOrWaitFired, "wait should have timed out\n"); 1369} 1370 1371struct waitthread_test_param 1372{ 1373 HANDLE trigger_event; 1374 HANDLE wait_event; 1375 HANDLE complete_event; 1376}; 1377 1378static void CALLBACK waitthread_test_function(PVOID p, BOOLEAN TimerOrWaitFired) 1379{ 1380 struct waitthread_test_param *param = p; 1381 DWORD ret; 1382 1383 SetEvent(param->trigger_event); 1384 ret = WaitForSingleObject(param->wait_event, 100); 1385 ok(ret == WAIT_TIMEOUT, "wait should have timed out\n"); 1386 SetEvent(param->complete_event); 1387} 1388 1389struct unregister_params 1390{ 1391 HANDLE wait_handle; 1392 HANDLE complete_event; 1393}; 1394 1395static void CALLBACK unregister_function(PVOID p, BOOLEAN TimerOrWaitFired) 1396{ 1397 struct unregister_params *param = p; 1398 HANDLE wait_handle = param->wait_handle; 1399 BOOL ret; 1400 ok(wait_handle != INVALID_HANDLE_VALUE, "invalid wait handle\n"); 1401 ret = pUnregisterWait(param->wait_handle); 1402 todo_wine ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1403 SetEvent(param->complete_event); 1404} 1405 1406static void test_RegisterWaitForSingleObject(void) 1407{ 1408 BOOL ret; 1409 HANDLE wait_handle, wait_handle2; 1410 HANDLE handle; 1411 HANDLE complete_event; 1412 HANDLE waitthread_trigger_event, waitthread_wait_event; 1413 struct waitthread_test_param param; 1414 struct unregister_params unregister_param; 1415 DWORD i; 1416 1417 if (!pRegisterWaitForSingleObject || !pUnregisterWait) 1418 { 1419 win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n"); 1420 return; 1421 } 1422 1423 /* test signaled case */ 1424 1425 handle = CreateEventW(NULL, TRUE, TRUE, NULL); 1426 complete_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1427 1428 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE); 1429 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1430 1431 WaitForSingleObject(complete_event, INFINITE); 1432 /* give worker thread chance to complete */ 1433 Sleep(100); 1434 1435 ret = pUnregisterWait(wait_handle); 1436 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1437 1438 /* test cancel case */ 1439 1440 ResetEvent(handle); 1441 1442 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE); 1443 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1444 1445 ret = pUnregisterWait(wait_handle); 1446 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1447 1448 /* test unregister while running */ 1449 1450 SetEvent(handle); 1451 ret = pRegisterWaitForSingleObject(&wait_handle, handle, wait_complete_function, complete_event, INFINITE, WT_EXECUTEONLYONCE); 1452 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1453 1454 /* give worker thread chance to start */ 1455 Sleep(50); 1456 ret = pUnregisterWait(wait_handle); 1457 ok(!ret, "UnregisterWait succeeded\n"); 1458 ok(GetLastError() == ERROR_IO_PENDING, "UnregisterWait failed with error %ld\n", GetLastError()); 1459 1460 /* give worker thread chance to complete */ 1461 SetEvent(complete_event); 1462 Sleep(50); 1463 1464 /* test timeout case */ 1465 1466 ResetEvent(handle); 1467 1468 ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE); 1469 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1470 1471 WaitForSingleObject(complete_event, INFINITE); 1472 /* give worker thread chance to complete */ 1473 Sleep(100); 1474 1475 ret = pUnregisterWait(wait_handle); 1476 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1477 1478 SetLastError(0xdeadbeef); 1479 ret = pUnregisterWait(NULL); 1480 ok(!ret, "Expected UnregisterWait to fail\n"); 1481 ok(GetLastError() == ERROR_INVALID_HANDLE, 1482 "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); 1483 1484 /* test WT_EXECUTEINWAITTHREAD */ 1485 1486 SetEvent(handle); 1487 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); 1488 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1489 1490 WaitForSingleObject(complete_event, INFINITE); 1491 /* give worker thread chance to complete */ 1492 Sleep(100); 1493 1494 ret = pUnregisterWait(wait_handle); 1495 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1496 1497 /* the callback execution should be sequentially consistent with the wait handle return, 1498 even if the event is already set */ 1499 1500 for (i = 0; i < 100; ++i) 1501 { 1502 SetEvent(handle); 1503 unregister_param.complete_event = complete_event; 1504 unregister_param.wait_handle = INVALID_HANDLE_VALUE; 1505 1506 ret = pRegisterWaitForSingleObject(&unregister_param.wait_handle, handle, unregister_function, &unregister_param, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); 1507 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1508 1509 WaitForSingleObject(complete_event, INFINITE); 1510 } 1511 1512 /* test multiple waits with WT_EXECUTEINWAITTHREAD. 1513 * Windows puts multiple waits on the same wait thread, and using WT_EXECUTEINWAITTHREAD causes the callbacks to run serially. 1514 */ 1515 1516 SetEvent(handle); 1517 waitthread_trigger_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1518 waitthread_wait_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1519 1520 param.trigger_event = waitthread_trigger_event; 1521 param.wait_event = waitthread_wait_event; 1522 param.complete_event = complete_event; 1523 1524 ret = pRegisterWaitForSingleObject(&wait_handle2, waitthread_trigger_event, signaled_function, waitthread_wait_event, 1525 INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); 1526 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1527 1528 ret = pRegisterWaitForSingleObject(&wait_handle, handle, waitthread_test_function, &param, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); 1529 ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); 1530 1531 WaitForSingleObject(complete_event, INFINITE); 1532 /* give worker thread chance to complete */ 1533 Sleep(100); 1534 1535 ret = pUnregisterWait(wait_handle); 1536 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1537 1538 ret = pUnregisterWait(wait_handle2); 1539 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); 1540 1541 CloseHandle(waitthread_wait_event); 1542 CloseHandle(waitthread_trigger_event); 1543 CloseHandle(complete_event); 1544 CloseHandle(handle); 1545} 1546 1547static DWORD LS_main; 1548static DWORD LS_index0, LS_index1; 1549static DWORD LS_OutOfIndexesValue; 1550 1551/* Function pointers to the FLS/TLS functions to test in LS_ThreadProc() */ 1552static DWORD (WINAPI *LS_AllocFunc)(void); 1553static PVOID (WINAPI *LS_GetValueFunc)(DWORD); 1554static BOOL (WINAPI *LS_SetValueFunc)(DWORD, PVOID); 1555static BOOL (WINAPI *LS_FreeFunc)(DWORD); 1556 1557/* Names of the functions tested in LS_ThreadProc(), for error messages */ 1558static const char* LS_AllocFuncName = ""; 1559static const char* LS_GetValueFuncName = ""; 1560static const char* LS_SetValueFuncName = ""; 1561static const char* LS_FreeFuncName = ""; 1562 1563/* FLS entry points, dynamically loaded in platforms that support them */ 1564static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION); 1565static BOOL (WINAPI *pFlsFree)(DWORD); 1566static PVOID (WINAPI *pFlsGetValue)(DWORD); 1567static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID); 1568 1569/* A thunk function to make FlsAlloc compatible with the signature of TlsAlloc */ 1570static DWORD WINAPI FLS_AllocFuncThunk(void) 1571{ 1572 return pFlsAlloc(NULL); 1573} 1574 1575static DWORD WINAPI LS_InheritanceProc(LPVOID p) 1576{ 1577 /* We should NOT inherit the FLS/TLS values from our parent or from the 1578 main thread. */ 1579 LPVOID val; 1580 1581 val = LS_GetValueFunc(LS_main); 1582 ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName); 1583 1584 val = LS_GetValueFunc(LS_index0); 1585 ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName); 1586 1587 val = LS_GetValueFunc(LS_index1); 1588 ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName); 1589 1590 return 0; 1591} 1592 1593/* Basic FLS/TLS usage test. Make sure we can create slots and the values we 1594 store in them are separate among threads. Also test FLS/TLS value 1595 inheritance with LS_InheritanceProc. */ 1596static DWORD WINAPI LS_ThreadProc(LPVOID p) 1597{ 1598 LONG_PTR id = (LONG_PTR) p; 1599 LPVOID val; 1600 BOOL ret; 1601 1602 if (sync_threads_and_run_one(0, id)) 1603 { 1604 LS_index0 = LS_AllocFunc(); 1605 ok(LS_index0 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName); 1606 } 1607 resync_after_run(); 1608 1609 if (sync_threads_and_run_one(1, id)) 1610 { 1611 LS_index1 = LS_AllocFunc(); 1612 ok(LS_index1 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName); 1613 1614 /* Slot indices should be different even if created in different 1615 threads. */ 1616 ok(LS_index0 != LS_index1, "%s failed\n", LS_AllocFuncName); 1617 1618 /* Both slots should be initialized to NULL */ 1619 SetLastError(0xdeadbeef); 1620 val = LS_GetValueFunc(LS_index0); 1621 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1622 ok(val == NULL, "Slot not initialized correctly\n"); 1623 1624 SetLastError(0xdeadbeef); 1625 val = LS_GetValueFunc(LS_index1); 1626 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1627 ok(val == NULL, "Slot not initialized correctly\n"); 1628 } 1629 resync_after_run(); 1630 1631 if (sync_threads_and_run_one(0, id)) 1632 { 1633 SetLastError(0xdeadbeef); 1634 val = LS_GetValueFunc(LS_index0); 1635 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1636 ok(val == NULL, "Slot not initialized correctly\n"); 1637 1638 SetLastError(0xdeadbeef); 1639 val = LS_GetValueFunc(LS_index1); 1640 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1641 ok(val == NULL, "Slot not initialized correctly\n"); 1642 1643 ret = LS_SetValueFunc(LS_index0, (LPVOID) 1); 1644 ok(ret, "%s failed\n", LS_SetValueFuncName); 1645 1646 ret = LS_SetValueFunc(LS_index1, (LPVOID) 2); 1647 ok(ret, "%s failed\n", LS_SetValueFuncName); 1648 1649 SetLastError(0xdeadbeef); 1650 val = LS_GetValueFunc(LS_index0); 1651 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1652 ok(val == (LPVOID) 1, "Slot not initialized correctly\n"); 1653 1654 SetLastError(0xdeadbeef); 1655 val = LS_GetValueFunc(LS_index1); 1656 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1657 ok(val == (LPVOID) 2, "Slot not initialized correctly\n"); 1658 } 1659 resync_after_run(); 1660 1661 if (sync_threads_and_run_one(1, id)) 1662 { 1663 val = LS_GetValueFunc(LS_index0); 1664 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1665 ok(val == NULL, "Slot not initialized correctly\n"); 1666 1667 val = LS_GetValueFunc(LS_index1); 1668 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1669 ok(val == NULL, "Slot not initialized correctly\n"); 1670 1671 ret = LS_SetValueFunc(LS_index0, (LPVOID) 3); 1672 ok(ret, "%s failed\n", LS_SetValueFuncName); 1673 1674 ret = LS_SetValueFunc(LS_index1, (LPVOID) 4); 1675 ok(ret, "%s failed\n", LS_SetValueFuncName); 1676 1677 val = LS_GetValueFunc(LS_index0); 1678 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1679 ok(val == (LPVOID) 3, "Slot not initialized correctly\n"); 1680 1681 val = LS_GetValueFunc(LS_index1); 1682 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1683 ok(val == (LPVOID) 4, "Slot not initialized correctly\n"); 1684 } 1685 resync_after_run(); 1686 1687 if (sync_threads_and_run_one(0, id)) 1688 { 1689 HANDLE thread; 1690 DWORD waitret, tid; 1691 1692 val = LS_GetValueFunc(LS_index0); 1693 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1694 ok(val == (LPVOID) 1, "Slot not initialized correctly\n"); 1695 1696 val = LS_GetValueFunc(LS_index1); 1697 ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); 1698 ok(val == (LPVOID) 2, "Slot not initialized correctly\n"); 1699 1700 thread = CreateThread(NULL, 0, LS_InheritanceProc, 0, 0, &tid); 1701 ok(thread != NULL, "CreateThread failed\n"); 1702 waitret = WaitForSingleObject(thread, 60000); 1703 ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); 1704 CloseHandle(thread); 1705 1706 ret = LS_FreeFunc(LS_index0); 1707 ok(ret, "%s failed\n", LS_FreeFuncName); 1708 } 1709 resync_after_run(); 1710 1711 if (sync_threads_and_run_one(1, id)) 1712 { 1713 ret = LS_FreeFunc(LS_index1); 1714 ok(ret, "%s failed\n", LS_FreeFuncName); 1715 } 1716 resync_after_run(); 1717 1718 return 0; 1719} 1720 1721static void run_LS_tests(void) 1722{ 1723 HANDLE threads[2]; 1724 LONG_PTR i; 1725 DWORD ret; 1726 BOOL suc; 1727 1728 init_thread_sync_helpers(); 1729 1730 /* Allocate a slot in the main thread to test for inheritance. */ 1731 LS_main = LS_AllocFunc(); 1732 ok(LS_main != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName); 1733 suc = LS_SetValueFunc(LS_main, (LPVOID) 4114); 1734 ok(suc, "%s failed\n", LS_SetValueFuncName); 1735 1736 for (i = 0; i < 2; ++i) 1737 { 1738 DWORD tid; 1739 1740 threads[i] = CreateThread(NULL, 0, LS_ThreadProc, (LPVOID) i, 0, &tid); 1741 ok(threads[i] != NULL, "CreateThread failed\n"); 1742 } 1743 1744 ret = WaitForMultipleObjects(2, threads, TRUE, 60000); 1745 ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 threads %ld\n",ret); 1746 1747 for (i = 0; i < 2; ++i) 1748 CloseHandle(threads[i]); 1749 1750 suc = LS_FreeFunc(LS_main); 1751 ok(suc, "%s failed\n", LS_FreeFuncName); 1752 cleanup_thread_sync_helpers(); 1753} 1754 1755static void test_TLS(void) 1756{ 1757 LS_OutOfIndexesValue = TLS_OUT_OF_INDEXES; 1758 1759 LS_AllocFunc = &TlsAlloc; 1760 LS_GetValueFunc = &TlsGetValue; 1761 LS_SetValueFunc = &TlsSetValue; 1762 LS_FreeFunc = &TlsFree; 1763 1764 LS_AllocFuncName = "TlsAlloc"; 1765 LS_GetValueFuncName = "TlsGetValue"; 1766 LS_SetValueFuncName = "TlsSetValue"; 1767 LS_FreeFuncName = "TlsFree"; 1768 1769 run_LS_tests(); 1770} 1771 1772static void test_FLS(void) 1773{ 1774 if (!pFlsAlloc || !pFlsFree || !pFlsGetValue || !pFlsSetValue) 1775 { 1776 win_skip("Fiber Local Storage not supported\n"); 1777 return; 1778 } 1779 1780 LS_OutOfIndexesValue = FLS_OUT_OF_INDEXES; 1781 1782 LS_AllocFunc = &FLS_AllocFuncThunk; 1783 LS_GetValueFunc = pFlsGetValue; 1784 LS_SetValueFunc = pFlsSetValue; 1785 LS_FreeFunc = pFlsFree; 1786 1787 LS_AllocFuncName = "FlsAlloc"; 1788 LS_GetValueFuncName = "FlsGetValue"; 1789 LS_SetValueFuncName = "FlsSetValue"; 1790 LS_FreeFuncName = "FlsFree"; 1791 1792 run_LS_tests(); 1793} 1794 1795static void test_ThreadErrorMode(void) 1796{ 1797 DWORD oldmode; 1798 DWORD mode; 1799 DWORD rtlmode; 1800 BOOL ret; 1801 1802 if (!pSetThreadErrorMode || !pGetThreadErrorMode) 1803 { 1804 win_skip("SetThreadErrorMode and/or GetThreadErrorMode unavailable (added in Windows 7)\n"); 1805 return; 1806 } 1807 1808 if (!pRtlGetThreadErrorMode) { 1809 win_skip("RtlGetThreadErrorMode not available\n"); 1810 return; 1811 } 1812 1813 oldmode = pGetThreadErrorMode(); 1814 1815 ret = pSetThreadErrorMode(0, &mode); 1816 ok(ret, "SetThreadErrorMode failed\n"); 1817 ok(mode == oldmode, 1818 "SetThreadErrorMode returned old mode 0x%lx, expected 0x%lx\n", 1819 mode, oldmode); 1820 mode = pGetThreadErrorMode(); 1821 ok(mode == 0, "GetThreadErrorMode returned mode 0x%lx, expected 0\n", mode); 1822 rtlmode = pRtlGetThreadErrorMode(); 1823 ok(rtlmode == 0, 1824 "RtlGetThreadErrorMode returned mode 0x%lx, expected 0\n", mode); 1825 1826 ret = pSetThreadErrorMode(SEM_FAILCRITICALERRORS, &mode); 1827 ok(ret, "SetThreadErrorMode failed\n"); 1828 ok(mode == 0, 1829 "SetThreadErrorMode returned old mode 0x%lx, expected 0\n", mode); 1830 mode = pGetThreadErrorMode(); 1831 ok(mode == SEM_FAILCRITICALERRORS, 1832 "GetThreadErrorMode returned mode 0x%lx, expected SEM_FAILCRITICALERRORS\n", 1833 mode); 1834 rtlmode = pRtlGetThreadErrorMode(); 1835 ok(rtlmode == 0x10, 1836 "RtlGetThreadErrorMode returned mode 0x%lx, expected 0x10\n", mode); 1837 1838 ret = pSetThreadErrorMode(SEM_NOGPFAULTERRORBOX, &mode); 1839 ok(ret, "SetThreadErrorMode failed\n"); 1840 ok(mode == SEM_FAILCRITICALERRORS, 1841 "SetThreadErrorMode returned old mode 0x%lx, expected SEM_FAILCRITICALERRORS\n", 1842 mode); 1843 mode = pGetThreadErrorMode(); 1844 ok(mode == SEM_NOGPFAULTERRORBOX, 1845 "GetThreadErrorMode returned mode 0x%lx, expected SEM_NOGPFAULTERRORBOX\n", 1846 mode); 1847 rtlmode = pRtlGetThreadErrorMode(); 1848 ok(rtlmode == 0x20, 1849 "RtlGetThreadErrorMode returned mode 0x%lx, expected 0x20\n", mode); 1850 1851 ret = pSetThreadErrorMode(SEM_NOOPENFILEERRORBOX, NULL); 1852 ok(ret, "SetThreadErrorMode failed\n"); 1853 mode = pGetThreadErrorMode(); 1854 ok(mode == SEM_NOOPENFILEERRORBOX, 1855 "GetThreadErrorMode returned mode 0x%lx, expected SEM_NOOPENFILEERRORBOX\n", 1856 mode); 1857 rtlmode = pRtlGetThreadErrorMode(); 1858 ok(rtlmode == 0x40, 1859 "RtlGetThreadErrorMode returned mode 0x%lx, expected 0x40\n", rtlmode); 1860 1861 for (mode = 1; mode; mode <<= 1) 1862 { 1863 ret = pSetThreadErrorMode(mode, NULL); 1864 if (mode & (SEM_FAILCRITICALERRORS | 1865 SEM_NOGPFAULTERRORBOX | 1866 SEM_NOOPENFILEERRORBOX)) 1867 { 1868 ok(ret, 1869 "SetThreadErrorMode(0x%lx,NULL) failed with error %ld\n", 1870 mode, GetLastError()); 1871 } 1872 else 1873 { 1874 DWORD GLE = GetLastError(); 1875 ok(!ret, 1876 "SetThreadErrorMode(0x%lx,NULL) succeeded, expected failure\n", 1877 mode); 1878 ok(GLE == ERROR_INVALID_PARAMETER, 1879 "SetThreadErrorMode(0x%lx,NULL) failed with %ld, " 1880 "expected ERROR_INVALID_PARAMETER\n", 1881 mode, GLE); 1882 } 1883 } 1884 1885 pSetThreadErrorMode(oldmode, NULL); 1886} 1887 1888struct fpu_thread_ctx 1889{ 1890 unsigned int cw; 1891 unsigned long fpu_cw; 1892 HANDLE finished; 1893}; 1894 1895static inline unsigned long get_fpu_cw(void) 1896{ 1897#ifdef __arm64ec__ 1898 extern NTSTATUS (*__os_arm64x_get_x64_information)(ULONG,void*,void*); 1899 unsigned int cw, sse; 1900 __os_arm64x_get_x64_information( 0, &sse, NULL ); 1901 __os_arm64x_get_x64_information( 2, &cw, NULL ); 1902 return MAKELONG( cw, sse ); 1903#elif defined(__i386__) || defined(__x86_64__) 1904 WORD cw = 0; 1905 unsigned int sse = 0; 1906#ifdef _MSC_VER 1907#if defined(__REACTOS__) && defined (__x86_64__) 1908 extern void get_fpu_cw_raw(WORD *cw, unsigned int *sse); 1909 get_fpu_cw_raw(&cw, &sse); 1910#else 1911 __asm { fnstcw [cw] } 1912 __asm { stmxcsr [sse] } 1913#endif 1914#else 1915 __asm__ volatile ("fnstcw %0" : "=m" (cw)); 1916 __asm__ volatile ("stmxcsr %0" : "=m" (sse)); 1917#endif 1918 return MAKELONG( cw, sse ); 1919#elif defined(__aarch64__) 1920 ULONG_PTR cw; 1921 __asm__ __volatile__( "mrs %0, fpcr" : "=r" (cw) ); 1922 return cw; 1923#else 1924 return 0; 1925#endif 1926} 1927 1928static inline void fpu_invalid_operation(void) 1929{ 1930 double d; 1931 1932#if defined(__i386__) 1933 unsigned int sse; 1934#ifdef _MSC_VER 1935 __asm { stmxcsr [sse] } 1936 sse |= 1; /* invalid operation flag */ 1937 __asm { ldmxcsr [sse] } 1938#else 1939 __asm__ volatile ("stmxcsr %0" : "=m" (sse)); 1940 sse |= 1; 1941 __asm__ volatile ("ldmxcsr %0" : : "m" (sse)); 1942#endif 1943#endif 1944 1945 d = acos(2.0); 1946 ok(_isnan(d), "d = %lf\n", d); 1947 ok(_statusfp() & _SW_INVALID, "_statusfp() = %x\n", _statusfp()); 1948} 1949 1950static DWORD WINAPI fpu_thread(void *param) 1951{ 1952 struct fpu_thread_ctx *ctx = param; 1953 BOOL ret; 1954 1955 ctx->cw = _control87( 0, 0 ); 1956 ctx->fpu_cw = get_fpu_cw(); 1957 1958 ret = SetEvent(ctx->finished); 1959 ok(ret, "SetEvent failed, last error %#lx.\n", GetLastError()); 1960 1961 return 0; 1962} 1963 1964static unsigned int get_thread_fpu_cw( unsigned long *fpu_cw ) 1965{ 1966 struct fpu_thread_ctx ctx; 1967 DWORD tid, res; 1968 HANDLE thread; 1969 1970 ctx.finished = CreateEventW(NULL, FALSE, FALSE, NULL); 1971 ok(!!ctx.finished, "Failed to create event, last error %#lx.\n", GetLastError()); 1972 1973 thread = CreateThread(NULL, 0, fpu_thread, &ctx, 0, &tid); 1974 ok(!!thread, "Failed to create thread, last error %#lx.\n", GetLastError()); 1975 1976 res = WaitForSingleObject(ctx.finished, INFINITE); 1977 ok(res == WAIT_OBJECT_0, "Wait failed (%#lx), last error %#lx.\n", res, GetLastError()); 1978 1979 res = CloseHandle(ctx.finished); 1980 ok(!!res, "Failed to close event handle, last error %#lx.\n", GetLastError()); 1981 1982 CloseHandle(thread); 1983 *fpu_cw = ctx.fpu_cw; 1984 return ctx.cw; 1985} 1986 1987static void test_thread_fpu_cw(void) 1988{ 1989 static const struct { 1990 unsigned int cw; unsigned long fpu_cw; unsigned long fpu_cw_broken; 1991 } expected_cw[8] = 1992 { 1993#ifdef __i386__ 1994 { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, 1995 { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, 1996 { _EM_INEXACT | _RC_CHOP | _PC_24, MAKELONG( 0xc60, 0x7000 ), MAKELONG( 0xc60, 0x1f80 ) }, 1997 { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, 1998 { _EM_INEXACT | _RC_CHOP | _PC_24, MAKELONG( 0xc60, 0x7000 ), MAKELONG( 0xc60, 0x1f80 ) }, 1999 { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, 2000 { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f81 ) }, 2001 { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f81 ) } 2002#elif defined(__x86_64__) 2003 { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, 2004 { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, 2005 { _EM_INEXACT | _RC_CHOP | _PC_64, MAKELONG( 0x27f, 0x7000 ) }, 2006 { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, 2007 { _EM_INEXACT | _RC_CHOP | _PC_64, MAKELONG( 0x27f, 0x7000 ) }, 2008 { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, 2009 { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f81 ) }, 2010 { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f81 ) } 2011#elif defined(__aarch64__) 2012 { _MCW_EM | _PC_64, 0 }, 2013 { _MCW_EM | _PC_64, 0 }, 2014 { _EM_INEXACT | _RC_CHOP | _PC_64, 0xc08f00 }, 2015 { _MCW_EM | _PC_64, 0 }, 2016 { _EM_INEXACT | _RC_CHOP | _PC_64, 0xc08f00 }, 2017 { _MCW_EM | _PC_64, 0 }, 2018 { _MCW_EM | _PC_64, 0 }, 2019 { _MCW_EM | _PC_64, 0 } 2020#else 2021 { 0xdeadbeef, 0xdeadbeef } 2022#endif 2023 }; 2024 unsigned int initial_cw, cw; 2025 unsigned long fpu_cw; 2026 2027 fpu_cw = get_fpu_cw(); 2028 initial_cw = _control87( 0, 0 ); 2029 ok(initial_cw == expected_cw[0].cw, "expected %#x got %#x\n", expected_cw[0].cw, initial_cw); 2030 ok(fpu_cw == expected_cw[0].fpu_cw, "expected %#lx got %#lx\n", expected_cw[0].fpu_cw, fpu_cw); 2031 2032 cw = get_thread_fpu_cw( &fpu_cw ); 2033 ok(cw == expected_cw[1].cw, "expected %#x got %#x\n", expected_cw[1].cw, cw); 2034 ok(fpu_cw == expected_cw[1].fpu_cw, "expected %#lx got %#lx\n", expected_cw[1].fpu_cw, fpu_cw); 2035 2036 _control87( _EM_INEXACT | _RC_CHOP | _PC_24, _MCW_EM | _MCW_RC | _MCW_PC ); 2037 cw = _control87( 0, 0 ); 2038 fpu_cw = get_fpu_cw(); 2039 ok(cw == expected_cw[2].cw, "expected %#x got %#x\n", expected_cw[2].cw, cw); 2040 ok(fpu_cw == expected_cw[2].fpu_cw || 2041 broken(expected_cw[2].fpu_cw_broken && fpu_cw == expected_cw[2].fpu_cw_broken), 2042 "expected %#lx got %#lx\n", expected_cw[2].fpu_cw, fpu_cw); 2043 2044 cw = get_thread_fpu_cw( &fpu_cw ); 2045 ok(cw == expected_cw[3].cw, "expected %#x got %#x\n", expected_cw[3].cw, cw); 2046 ok(fpu_cw == expected_cw[3].fpu_cw, "expected %#lx got %#lx\n", expected_cw[3].fpu_cw, fpu_cw); 2047 2048 cw = _control87( 0, 0 ); 2049 fpu_cw = get_fpu_cw(); 2050 ok(cw == expected_cw[4].cw, "expected %#x got %#x\n", expected_cw[4].cw, cw); 2051 ok(fpu_cw == expected_cw[4].fpu_cw || 2052 broken(expected_cw[4].fpu_cw_broken && fpu_cw == expected_cw[4].fpu_cw_broken), 2053 "expected %#lx got %#lx\n", expected_cw[4].fpu_cw, fpu_cw); 2054 2055 _control87( initial_cw, _MCW_EM | _MCW_RC | _MCW_PC ); 2056 cw = _control87( 0, 0 ); 2057 fpu_cw = get_fpu_cw(); 2058 ok(cw == expected_cw[5].cw, "expected %#x got %#x\n", expected_cw[5].cw, cw); 2059 ok(fpu_cw == expected_cw[5].fpu_cw, "expected %#lx got %#lx\n", expected_cw[5].fpu_cw, fpu_cw); 2060 2061 fpu_invalid_operation(); 2062 cw = _control87( 0, 0 ); 2063 fpu_cw = get_fpu_cw(); 2064 ok(cw == expected_cw[6].cw, "expected %#x got %#x\n", expected_cw[6].cw, cw); 2065 ok(fpu_cw == expected_cw[6].fpu_cw, "expected %#lx got %#lx\n", expected_cw[6].fpu_cw, fpu_cw); 2066 2067 cw = _control87( initial_cw, _MCW_EM | _MCW_RC | _MCW_PC ); 2068 fpu_cw = get_fpu_cw(); 2069 ok(cw == expected_cw[7].cw, "expected %#x got %#x\n", expected_cw[6].cw, cw); 2070 ok(fpu_cw == expected_cw[7].fpu_cw, "expected %#lx got %#lx\n", expected_cw[6].fpu_cw, fpu_cw); 2071 _clearfp(); 2072} 2073 2074static const char manifest_dep[] = 2075"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">" 2076"<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>" 2077" <file name=\"testdep.dll\" />" 2078"</assembly>"; 2079 2080static const char manifest_main[] = 2081"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">" 2082"<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />" 2083"<dependency>" 2084" <dependentAssembly>" 2085" <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />" 2086" </dependentAssembly>" 2087"</dependency>" 2088"</assembly>"; 2089 2090static void create_manifest_file(const char *filename, const char *manifest) 2091{ 2092 WCHAR path[MAX_PATH]; 2093 HANDLE file; 2094 DWORD size; 2095 2096 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); 2097 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 2098 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); 2099 WriteFile(file, manifest, strlen(manifest), &size, NULL); 2100 CloseHandle(file); 2101} 2102 2103static HANDLE test_create(const char *file) 2104{ 2105 WCHAR path[MAX_PATH]; 2106 ACTCTXW actctx; 2107 HANDLE handle; 2108 2109 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH); 2110 memset(&actctx, 0, sizeof(ACTCTXW)); 2111 actctx.cbSize = sizeof(ACTCTXW); 2112 actctx.lpSource = path; 2113 2114 handle = CreateActCtxW(&actctx); 2115 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError()); 2116 2117 ok(actctx.cbSize == sizeof(actctx), "cbSize=%ld\n", actctx.cbSize); 2118 ok(actctx.dwFlags == 0, "dwFlags=%ld\n", actctx.dwFlags); 2119 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource); 2120 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); 2121 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId); 2122 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory); 2123 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName); 2124 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName); 2125 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule); 2126 2127 return handle; 2128} 2129 2130static void test_thread_actctx(void) 2131{ 2132 struct thread_actctx_param param; 2133 HANDLE thread, handle, context; 2134 ULONG_PTR cookie; 2135 DWORD tid, ret; 2136 BOOL b; 2137 2138 create_manifest_file("testdep1.manifest", manifest_dep); 2139 create_manifest_file("main.manifest", manifest_main); 2140 2141 context = test_create("main.manifest"); 2142 DeleteFileA("testdep1.manifest"); 2143 DeleteFileA("main.manifest"); 2144 2145 handle = (void*)0xdeadbeef; 2146 b = GetCurrentActCtx(&handle); 2147 ok(b, "GetCurrentActCtx failed: %lu\n", GetLastError()); 2148 ok(handle == 0, "active context %p\n", handle); 2149 2150 /* without active context */ 2151 param.thread_context = (void*)0xdeadbeef; 2152 param.handle = NULL; 2153 thread = CreateThread(NULL, 0, thread_actctx_func, &param, 0, &tid); 2154 ok(thread != NULL, "failed, got %lu\n", GetLastError()); 2155 2156 ret = WaitForSingleObject(thread, 1000); 2157 ok(ret == WAIT_OBJECT_0, "wait timeout\n"); 2158 ok(param.thread_context == NULL, "got wrong thread context %p\n", param.thread_context); 2159 CloseHandle(thread); 2160 2161 b = ActivateActCtx(context, &cookie); 2162 ok(b, "activation failed: %lu\n", GetLastError()); 2163 2164 handle = 0; 2165 b = GetCurrentActCtx(&handle); 2166 ok(b, "GetCurrentActCtx failed: %lu\n", GetLastError()); 2167 ok(handle != 0, "no active context\n"); 2168 ReleaseActCtx(handle); 2169 2170 param.handle = NULL; 2171 b = GetCurrentActCtx(&param.handle); 2172 ok(b && param.handle != NULL, "failed to get context, %lu\n", GetLastError()); 2173 2174 param.thread_context = (void*)0xdeadbeef; 2175 thread = CreateThread(NULL, 0, thread_actctx_func, &param, 0, &tid); 2176 ok(thread != NULL, "failed, got %lu\n", GetLastError()); 2177 2178 ret = WaitForSingleObject(thread, 1000); 2179 ok(ret == WAIT_OBJECT_0, "wait timeout\n"); 2180 ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context); 2181 ReleaseActCtx(param.thread_context); 2182 CloseHandle(thread); 2183 2184 /* similar test for CreateRemoteThread() */ 2185 param.thread_context = (void*)0xdeadbeef; 2186 thread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, thread_actctx_func, &param, 0, &tid); 2187 ok(thread != NULL, "failed, got %lu\n", GetLastError()); 2188 2189 ret = WaitForSingleObject(thread, 1000); 2190 ok(ret == WAIT_OBJECT_0, "wait timeout\n"); 2191 ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context); 2192 ReleaseActCtx(param.thread_context); 2193 CloseHandle(thread); 2194 2195 ReleaseActCtx(param.handle); 2196 2197 b = DeactivateActCtx(0, cookie); 2198 ok(b, "DeactivateActCtx failed: %lu\n", GetLastError()); 2199 ReleaseActCtx(context); 2200} 2201 2202static void WINAPI threadpool_workcallback(PTP_CALLBACK_INSTANCE instance, void *context, PTP_WORK work) { 2203 int *foo = (int*)context; 2204 2205 (*foo)++; 2206} 2207 2208 2209static void test_threadpool(void) 2210{ 2211 PTP_POOL pool; 2212 PTP_WORK work; 2213 int workcalled = 0; 2214 2215 if (!pCreateThreadpool) { 2216 win_skip("thread pool apis not supported.\n"); 2217 return; 2218 } 2219 2220 work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL); 2221 ok (work != NULL, "Error %ld in CreateThreadpoolWork\n", GetLastError()); 2222 pSubmitThreadpoolWork(work); 2223 pWaitForThreadpoolWorkCallbacks(work, FALSE); 2224 pCloseThreadpoolWork(work); 2225 2226 ok (workcalled == 1, "expected work to be called once, got %d\n", workcalled); 2227 2228 pool = pCreateThreadpool(NULL); 2229 ok (pool != NULL, "CreateThreadpool failed\n"); 2230 pCloseThreadpool(pool); 2231} 2232 2233static void test_reserved_tls(void) 2234{ 2235 void *val; 2236 DWORD tls; 2237 BOOL ret; 2238 2239 /* This seems to be a WinXP SP2+ feature. */ 2240 if(!pIsWow64Process) { 2241 win_skip("Skipping reserved TLS slot on too old Windows.\n"); 2242 return; 2243 } 2244 2245 val = TlsGetValue(0); 2246 ok(!val, "TlsGetValue(0) = %p\n", val); 2247 2248 /* Also make sure that there is a TLS allocated. */ 2249 tls = TlsAlloc(); 2250 ok(tls && tls != TLS_OUT_OF_INDEXES, "tls = %lx\n", tls); 2251 TlsSetValue(tls, (void*)1); 2252 2253 val = TlsGetValue(0); 2254 ok(!val, "TlsGetValue(0) = %p\n", val); 2255 2256 TlsFree(tls); 2257 2258 /* The following is too ugly to be run by default */ 2259 if(0) { 2260 /* Set TLS index 0 value and see that this works and doesn't cause problems 2261 * for remaining tests. */ 2262 ret = TlsSetValue(0, (void*)1); 2263 ok(ret, "TlsSetValue(0, 1) failed: %lu\n", GetLastError()); 2264 2265 val = TlsGetValue(0); 2266 ok(val == (void*)1, "TlsGetValue(0) = %p\n", val); 2267 } 2268} 2269 2270static void test_thread_info(void) 2271{ 2272 char buf[4096]; 2273 static const ULONG info_size[] = 2274 { 2275 sizeof(THREAD_BASIC_INFORMATION), /* ThreadBasicInformation */ 2276 sizeof(KERNEL_USER_TIMES), /* ThreadTimes */ 2277 sizeof(ULONG), /* ThreadPriority */ 2278 sizeof(ULONG), /* ThreadBasePriority */ 2279 sizeof(ULONG_PTR), /* ThreadAffinityMask */ 2280 sizeof(HANDLE), /* ThreadImpersonationToken */ 2281 sizeof(THREAD_DESCRIPTOR_INFORMATION), /* ThreadDescriptorTableEntry */ 2282 sizeof(BOOLEAN), /* ThreadEnableAlignmentFaultFixup */ 2283 0, /* ThreadEventPair_Reusable */ 2284 sizeof(ULONG_PTR), /* ThreadQuerySetWin32StartAddress */ 2285 sizeof(ULONG), /* ThreadZeroTlsCell */ 2286 sizeof(LARGE_INTEGER), /* ThreadPerformanceCount */ 2287 sizeof(ULONG), /* ThreadAmILastThread */ 2288 sizeof(ULONG), /* ThreadIdealProcessor */ 2289 sizeof(ULONG), /* ThreadPriorityBoost */ 2290 sizeof(ULONG_PTR), /* ThreadSetTlsArrayAddress */ 2291 sizeof(ULONG), /* ThreadIsIoPending */ 2292 sizeof(BOOLEAN), /* ThreadHideFromDebugger */ 2293 /* FIXME: Add remaining classes */ 2294 }; 2295 HANDLE thread; 2296 ULONG i, status, ret_len; 2297 2298 if (!pOpenThread) 2299 { 2300 win_skip("OpenThread is not available on this platform\n"); 2301 return; 2302 } 2303 2304 if (!pNtQueryInformationThread) 2305 { 2306 win_skip("NtQueryInformationThread is not available on this platform\n"); 2307 return; 2308 } 2309 2310 thread = pOpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentThreadId()); 2311 if (!thread) 2312 { 2313 win_skip("THREAD_QUERY_LIMITED_INFORMATION is not supported on this platform\n"); 2314 return; 2315 } 2316 2317 for (i = 0; i < ARRAY_SIZE(info_size); i++) 2318 { 2319 memset(buf, 0, sizeof(buf)); 2320 2321#ifdef __i386__ 2322 if (i == ThreadDescriptorTableEntry) 2323 { 2324 CONTEXT ctx; 2325 THREAD_DESCRIPTOR_INFORMATION *tdi = (void *)buf; 2326 2327 ctx.ContextFlags = CONTEXT_SEGMENTS; 2328 GetThreadContext(GetCurrentThread(), &ctx); 2329 tdi->Selector = ctx.SegDs; 2330 } 2331#endif 2332 ret_len = 0; 2333 status = pNtQueryInformationThread(thread, i, buf, info_size[i], &ret_len); 2334 if (status == STATUS_NOT_IMPLEMENTED) continue; 2335 if (status == STATUS_INVALID_INFO_CLASS) continue; 2336 if (status == STATUS_UNSUCCESSFUL) continue; 2337 2338 switch (i) 2339 { 2340 case ThreadBasicInformation: 2341 case ThreadAmILastThread: 2342 case ThreadPriorityBoost: 2343#ifdef __REACTOS__ 2344 ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED && (i == 0 || i == 14)) /* WS03 */, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); 2345#else 2346 ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); 2347#endif 2348 break; 2349 2350#ifdef __i386__ 2351 case ThreadDescriptorTableEntry: 2352 ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED) /* testbot VM is broken */, 2353 "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); 2354 break; 2355#endif 2356 2357 case ThreadTimes: 2358#ifdef __REACTOS__ 2359 ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED) /* WS03 */, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); 2360#else 2361 ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); 2362#endif 2363 break; 2364 2365 case ThreadIsIoPending: 2366 todo_wine 2367 ok(status == STATUS_ACCESS_DENIED, "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); 2368 break; 2369 2370 default: 2371 ok(status == STATUS_ACCESS_DENIED, "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); 2372 break; 2373 } 2374 } 2375 2376 CloseHandle(thread); 2377} 2378 2379typedef struct tagTHREADNAME_INFO 2380{ 2381 DWORD dwType; /* Must be 0x1000. */ 2382 LPCSTR szName; /* Pointer to name (in user addr space). */ 2383 DWORD dwThreadID; /* Thread ID (-1 = caller thread). */ 2384 DWORD dwFlags; /* Reserved for future use, must be zero. */ 2385} THREADNAME_INFO; 2386 2387static LONG CALLBACK msvc_threadname_vec_handler(EXCEPTION_POINTERS *ExceptionInfo) 2388{ 2389 if (ExceptionInfo->ExceptionRecord != NULL && 2390 ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_NAME_THREAD) 2391 return EXCEPTION_CONTINUE_EXECUTION; 2392 2393 return EXCEPTION_CONTINUE_SEARCH; 2394} 2395 2396static void test_thread_description(void) 2397{ 2398 THREAD_NAME_INFORMATION *thread_desc; 2399 static const WCHAR *desc = L"thread_desc"; 2400 ULONG len, len2, desc_len; 2401 NTSTATUS status; 2402 char buff[128]; 2403 WCHAR *ptr; 2404 HRESULT hr; 2405 HANDLE thread; 2406 PVOID vectored_handler; 2407 THREADNAME_INFO info; 2408 2409 if (!pGetThreadDescription) 2410 { 2411 win_skip("Thread description API is not supported.\n"); 2412 return; 2413 } 2414 2415 desc_len = lstrlenW(desc) * sizeof(*desc); 2416 thread_desc = (THREAD_NAME_INFORMATION *)buff; 2417 2418 /* Initial description. */ 2419 ptr = NULL; 2420 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2421 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2422 ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2423 LocalFree(ptr); 2424 2425 len = 0; 2426 status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, 0, &len); 2427 ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); 2428 ok(len == sizeof(*thread_desc), "Unexpected structure length %lu.\n", len); 2429 2430 len2 = 0; 2431 thread_desc->ThreadName.Length = 1; 2432 thread_desc->ThreadName.MaximumLength = 0; 2433 thread_desc->ThreadName.Buffer = (WCHAR *)thread_desc; 2434 status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, len, &len2); 2435 ok(!status, "Failed to get thread info, status %#lx.\n", status); 2436 ok(len2 == sizeof(*thread_desc), "Unexpected structure length %lu.\n", len); 2437 ok(!thread_desc->ThreadName.Length, "Unexpected description length %#x.\n", thread_desc->ThreadName.Length); 2438 ok(thread_desc->ThreadName.Buffer == (WCHAR *)(thread_desc + 1), 2439 "Unexpected description string pointer %p, %p.\n", thread_desc->ThreadName.Buffer, thread_desc); 2440 2441 hr = pSetThreadDescription(GetCurrentThread(), NULL); 2442 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2443 2444 hr = pSetThreadDescription(GetCurrentThread(), desc); 2445 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2446 2447 ptr = NULL; 2448 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2449 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2450 ok(!lstrcmpW(ptr, desc), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2451 LocalFree(ptr); 2452 2453 len = 0; 2454 status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, 0, &len); 2455 ok(status == STATUS_BUFFER_TOO_SMALL, "Failed to get thread info, status %#lx.\n", status); 2456 ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); 2457 2458 len = 0; 2459 status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, buff, sizeof(buff), &len); 2460 ok(!status, "Failed to get thread info.\n"); 2461 ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); 2462 2463 ok(thread_desc->ThreadName.Length == desc_len && thread_desc->ThreadName.MaximumLength == desc_len, 2464 "Unexpected description length %u.\n", thread_desc->ThreadName.Length); 2465 ok(thread_desc->ThreadName.Buffer == (WCHAR *)(thread_desc + 1), 2466 "Unexpected description string pointer %p, %p.\n", thread_desc->ThreadName.Buffer, thread_desc); 2467 ok(!memcmp(thread_desc->ThreadName.Buffer, desc, desc_len), "Unexpected description string.\n"); 2468 2469 /* Partial results. */ 2470 len = 0; 2471 status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, 0, &len); 2472 ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); 2473 ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); 2474 2475 status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, buff, len - sizeof(WCHAR), &len); 2476 ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); 2477 ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); 2478 2479 /* Change description. */ 2480 thread_desc->ThreadName.Length = thread_desc->ThreadName.MaximumLength = 8; 2481 lstrcpyW((WCHAR *)(thread_desc + 1), L"desc"); 2482 2483 status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); 2484 ok(status == STATUS_SUCCESS, "Failed to set thread description, status %#lx.\n", status); 2485 2486 ptr = NULL; 2487 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2488 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2489 ok(!lstrcmpW(ptr, L"desc"), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2490 LocalFree(ptr); 2491 2492 status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc) - 1); 2493 ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#lx.\n", status); 2494 2495 status = NtSetInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, sizeof(*thread_desc)); 2496 ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#lx.\n", status); 2497 2498 thread_desc->ThreadName.Buffer = NULL; 2499 status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); 2500 ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#lx.\n", status); 2501 2502 hr = pSetThreadDescription(GetCurrentThread(), NULL); 2503 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2504 2505 ptr = NULL; 2506 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2507 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2508 ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2509 LocalFree(ptr); 2510 2511 /* Set with a string from RtlInitUnicodeString. */ 2512 hr = pSetThreadDescription(GetCurrentThread(), L"123"); 2513 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2514 2515 lstrcpyW((WCHAR *)(thread_desc + 1), L"desc"); 2516 RtlInitUnicodeString(&thread_desc->ThreadName, (WCHAR *)(thread_desc + 1)); 2517 2518 status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); 2519 ok(status == STATUS_SUCCESS, "Failed to set thread description, status %#lx.\n", status); 2520 2521 ptr = NULL; 2522 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2523 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2524 ok(!lstrcmpW(ptr, L"desc"), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2525 LocalFree(ptr); 2526 2527 /* Set with 0 length/NULL pointer. */ 2528 hr = pSetThreadDescription(GetCurrentThread(), L"123"); 2529 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2530 2531 memset(thread_desc, 0, sizeof(*thread_desc)); 2532 status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); 2533 ok(!status, "Failed to set thread description, status %#lx.\n", status); 2534 2535 ptr = NULL; 2536 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2537 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2538 ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2539 LocalFree(ptr); 2540 2541 /* Get with only THREAD_QUERY_LIMITED_INFORMATION access. */ 2542 thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentThreadId()); 2543 2544 ptr = NULL; 2545 hr = pGetThreadDescription(thread, &ptr); 2546 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2547 ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2548 LocalFree(ptr); 2549 2550 len = 0; 2551 status = pNtQueryInformationThread(thread, ThreadNameInformation, NULL, 0, &len); 2552 ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); 2553 ok(len == sizeof(*thread_desc), "Unexpected structure length %lu.\n", len); 2554 2555 CloseHandle(thread); 2556 2557 /* Set with only THREAD_SET_LIMITED_INFORMATION access. */ 2558 thread = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, GetCurrentThreadId()); 2559 2560 hr = pSetThreadDescription(thread, desc); 2561 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2562 2563 ptr = NULL; 2564 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2565 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2566 ok(!lstrcmpW(ptr, desc), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2567 LocalFree(ptr); 2568 2569 CloseHandle(thread); 2570 2571 /* The old exception-based thread name method should not affect GetThreadDescription. */ 2572 hr = pSetThreadDescription(GetCurrentThread(), desc); 2573 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); 2574 2575 vectored_handler = pRtlAddVectoredExceptionHandler(FALSE, &msvc_threadname_vec_handler); 2576 ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); 2577 2578 info.dwType = 0x1000; 2579 info.szName = "123"; 2580 info.dwThreadID = -1; 2581 info.dwFlags = 0; 2582 RaiseException(EXCEPTION_WINE_NAME_THREAD, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); 2583 2584 pRtlRemoveVectoredExceptionHandler(vectored_handler); 2585 2586 ptr = NULL; 2587 hr = pGetThreadDescription(GetCurrentThread(), &ptr); 2588 ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); 2589 ok(!lstrcmpW(ptr, desc), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); 2590 LocalFree(ptr); 2591} 2592 2593static void init_funcs(void) 2594{ 2595 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); 2596 HMODULE ntdll = GetModuleHandleA("ntdll.dll"); 2597 2598/* Neither Cygwin nor mingW export OpenThread, so do a dynamic check 2599 so that the compile passes */ 2600 2601#define X(f) p##f = (void*)GetProcAddress(hKernel32, #f) 2602 X(GetCurrentThreadStackLimits); 2603 X(GetThreadPriorityBoost); 2604 X(OpenThread); 2605 X(QueueUserWorkItem); 2606 X(SetThreadPriorityBoost); 2607 X(SetThreadStackGuarantee); 2608 X(RegisterWaitForSingleObject); 2609 X(UnregisterWait); 2610 X(IsWow64Process); 2611 X(SetThreadErrorMode); 2612 X(GetThreadErrorMode); 2613 2614 X(CreateThreadpool); 2615 X(CloseThreadpool); 2616 X(CreateThreadpoolWork); 2617 X(SubmitThreadpoolWork); 2618 X(WaitForThreadpoolWorkCallbacks); 2619 X(CloseThreadpoolWork); 2620 2621 X(GetThreadGroupAffinity); 2622 X(SetThreadGroupAffinity); 2623 X(SetThreadDescription); 2624 X(GetThreadDescription); 2625 2626 X(FlsAlloc); 2627 X(FlsFree); 2628 X(FlsSetValue); 2629 X(FlsGetValue); 2630#undef X 2631 2632#define X(f) p##f = (void*)GetProcAddress(ntdll, #f) 2633 if (ntdll) 2634 { 2635 X(NtQueryInformationThread); 2636 X(RtlGetThreadErrorMode); 2637 X(NtSetInformationThread); 2638 X(RtlAddVectoredExceptionHandler); 2639 X(RtlRemoveVectoredExceptionHandler); 2640 } 2641#undef X 2642} 2643 2644START_TEST(thread) 2645{ 2646 int argc; 2647 char **argv; 2648 argc = winetest_get_mainargs( &argv ); 2649 2650 init_funcs(); 2651 2652 if (argc >= 3) 2653 { 2654 if (!strcmp(argv[2], "sleep")) 2655 { 2656 HANDLE hAddrEvents[2]; 2657 create_function_addr_events(hAddrEvents); 2658 SetEvent(hAddrEvents[0]); 2659 SetEvent(hAddrEvents[1]); 2660 Sleep(5000); /* spawned process runs for at most 5 seconds */ 2661 return; 2662 } 2663 while (1) 2664 { 2665 HANDLE hThread; 2666 DWORD tid; 2667 hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid); 2668 ok(hThread != NULL, "CreateThread failed, error %lu\n", 2669 GetLastError()); 2670 ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0, 2671 "Thread did not exit in time\n"); 2672 if (hThread == NULL) break; 2673 CloseHandle(hThread); 2674 } 2675 return; 2676 } 2677 2678 test_thread_info(); 2679 test_reserved_tls(); 2680 test_CreateRemoteThread(); 2681 test_CreateThread_basic(); 2682 test_CreateThread_suspended(); 2683 test_SuspendThread(); 2684 test_TerminateThread(); 2685 test_CreateThread_stack(); 2686 test_thread_priority(); 2687 test_GetCurrentThreadStackLimits(); 2688 test_SetThreadStackGuarantee(); 2689 test_GetThreadTimes(); 2690 test_thread_processor(); 2691 test_GetThreadExitCode(); 2692#ifdef __i386__ 2693 test_SetThreadContext(); 2694 test_GetThreadSelectorEntry(); 2695 test_GetThreadContext(); 2696#endif 2697 test_QueueUserWorkItem(); 2698 test_RegisterWaitForSingleObject(); 2699 test_TLS(); 2700 test_FLS(); 2701 test_ThreadErrorMode(); 2702 test_thread_fpu_cw(); 2703 test_thread_actctx(); 2704 test_thread_description(); 2705 2706 test_threadpool(); 2707}