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