Sync to trunk head (r42241)
[reactos.git] / rostests / winetests / kernel32 / thread.c
1 /*
2 * Unit test suite for directory 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 0x0500
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "wine/test.h"
28 #include <windef.h>
29 #include <winbase.h>
30 #include <winnt.h>
31 #include <winerror.h>
32
33 /* Specify the number of simultaneous threads to test */
34 #define NUM_THREADS 4
35 /* Specify whether to test the extended priorities for Win2k/XP */
36 #define USE_EXTENDED_PRIORITIES 0
37 /* Specify whether to test the stack allocation in CreateThread */
38 #define CHECK_STACK 0
39
40 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
41 CreateThread. So far I have been unable to make this work, and
42 I am in doubt as to how portable it is. Also, according to MSDN,
43 you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
44 Anyhow, the check is currently commented out
45 */
46 #if CHECK_STACK
47 # ifdef __try
48 # define __TRY __try
49 # define __EXCEPT __except
50 # define __ENDTRY
51 # else
52 # include "wine/exception.h"
53 # endif
54 #endif
55
56 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
57 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
58
59 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
60 static OpenThread_t pOpenThread=NULL;
61
62 typedef BOOL (WINAPI *QueueUserWorkItem_t)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
63 static QueueUserWorkItem_t pQueueUserWorkItem=NULL;
64
65 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
66 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
67
68 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
69 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
70
71 typedef BOOL (WINAPI *RegisterWaitForSingleObject_t)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
72 static RegisterWaitForSingleObject_t pRegisterWaitForSingleObject=NULL;
73
74 typedef BOOL (WINAPI *UnregisterWait_t)(HANDLE);
75 static UnregisterWait_t pUnregisterWait=NULL;
76
77 static HANDLE create_target_process(const char *arg)
78 {
79 char **argv;
80 char cmdline[MAX_PATH];
81 PROCESS_INFORMATION pi;
82 STARTUPINFO si = { 0 };
83 si.cb = sizeof(si);
84
85 winetest_get_mainargs( &argv );
86 sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
87 ok(CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
88 &si, &pi) != 0, "error: %u\n", GetLastError());
89 ok(CloseHandle(pi.hThread) != 0, "error %u\n", GetLastError());
90 return pi.hProcess;
91 }
92
93 /* Functions not tested yet:
94 AttachThreadInput
95 SetThreadContext
96 SwitchToThread
97
98 In addition there are no checks that the inheritance works properly in
99 CreateThread
100 */
101
102 DWORD tlsIndex;
103
104 typedef struct {
105 int threadnum;
106 HANDLE *event;
107 DWORD *threadmem;
108 } t1Struct;
109
110 /* WinME supports OpenThread but doesn't know about access restrictions so
111 we require them to be either completely ignored or always obeyed.
112 */
113 INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
114 #define obey_ar(x) \
115 (obeying_ars == 0 \
116 ? ((x) \
117 ? (obeying_ars = +1) \
118 : ((obeying_ars = -1), \
119 trace("not restricted, assuming consistent behaviour\n"))) \
120 : (obeying_ars < 0) \
121 ? ok(!(x), "access restrictions obeyed\n") \
122 : ok( (x), "access restrictions not obeyed\n"))
123
124 /* Basic test that simultaneous threads can access shared memory,
125 that the thread local storage routines work correctly, and that
126 threads actually run concurrently
127 */
128 static DWORD WINAPI threadFunc1(LPVOID p)
129 {
130 t1Struct *tstruct = (t1Struct *)p;
131 int i;
132 /* write our thread # into shared memory */
133 tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
134 ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
135 "TlsSetValue failed\n");
136 /* The threads synchronize before terminating. This is done by
137 Signaling an event, and waiting for all events to occur
138 */
139 SetEvent(tstruct->event[tstruct->threadnum]);
140 WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
141 /* Double check that all threads really did run by validating that
142 they have all written to the shared memory. There should be no race
143 here, since all threads were synchronized after the write.*/
144 for(i=0;i<NUM_THREADS;i++) {
145 while(tstruct->threadmem[i]==0) ;
146 }
147
148 /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
149 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
150
151 /* Check that no one changed our tls memory */
152 ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
153 "TlsGetValue failed\n");
154 return NUM_THREADS+tstruct->threadnum;
155 }
156
157 static DWORD WINAPI threadFunc2(LPVOID p)
158 {
159 return 99;
160 }
161
162 static DWORD WINAPI threadFunc3(LPVOID p)
163 {
164 HANDLE thread;
165 thread=GetCurrentThread();
166 SuspendThread(thread);
167 return 99;
168 }
169
170 static DWORD WINAPI threadFunc4(LPVOID p)
171 {
172 HANDLE event = (HANDLE)p;
173 if(event != NULL) {
174 SetEvent(event);
175 }
176 Sleep(99000);
177 return 0;
178 }
179
180 #if CHECK_STACK
181 static DWORD WINAPI threadFunc5(LPVOID p)
182 {
183 DWORD *exitCode = (DWORD *)p;
184 SYSTEM_INFO sysInfo;
185 sysInfo.dwPageSize=0;
186 GetSystemInfo(&sysInfo);
187 *exitCode=0;
188 __TRY
189 {
190 alloca(2*sysInfo.dwPageSize);
191 }
192 __EXCEPT(1) {
193 *exitCode=1;
194 }
195 __ENDTRY
196 return 0;
197 }
198 #endif
199
200 static DWORD WINAPI threadFunc_SetEvent(LPVOID p)
201 {
202 SetEvent((HANDLE) p);
203 return 0;
204 }
205
206 static DWORD WINAPI threadFunc_CloseHandle(LPVOID p)
207 {
208 CloseHandle((HANDLE) p);
209 return 0;
210 }
211
212 static void create_function_addr_events(HANDLE events[2])
213 {
214 char buffer[256];
215
216 sprintf(buffer, "threadFunc_SetEvent %p", threadFunc_SetEvent);
217 events[0] = CreateEvent(NULL, FALSE, FALSE, buffer);
218
219 sprintf(buffer, "threadFunc_CloseHandle %p", threadFunc_CloseHandle);
220 events[1] = CreateEvent(NULL, FALSE, FALSE, buffer);
221 }
222
223 /* check CreateRemoteThread */
224 static VOID test_CreateRemoteThread(void)
225 {
226 HANDLE hProcess, hThread, hEvent, hRemoteEvent;
227 DWORD tid, ret, exitcode;
228 HANDLE hAddrEvents[2];
229
230 hProcess = create_target_process("sleep");
231 ok(hProcess != NULL, "Can't start process\n");
232
233 /* ensure threadFunc_SetEvent & threadFunc_CloseHandle are the same
234 * address as in the child process */
235 create_function_addr_events(hAddrEvents);
236 ret = WaitForMultipleObjects(2, hAddrEvents, TRUE, 5000);
237 if (ret == WAIT_TIMEOUT)
238 {
239 skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n");
240 return;
241 }
242
243 hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
244 ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError());
245 ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent,
246 0, FALSE, DUPLICATE_SAME_ACCESS);
247 ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError());
248
249 /* create suspended remote thread with entry point SetEvent() */
250 SetLastError(0xdeadbeef);
251 hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent,
252 hRemoteEvent, CREATE_SUSPENDED, &tid);
253 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
254 {
255 skip("CreateRemoteThread is not implemented\n");
256 goto cleanup;
257 }
258 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
259 ok(tid != 0, "null tid\n");
260 ret = SuspendThread(hThread);
261 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
262 ret = ResumeThread(hThread);
263 ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError());
264
265 /* thread still suspended, so wait times out */
266 ret = WaitForSingleObject(hEvent, 100);
267 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
268
269 ret = ResumeThread(hThread);
270 ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError());
271
272 /* wait that doesn't time out */
273 ret = WaitForSingleObject(hEvent, 100);
274 ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret);
275
276 /* wait for thread end */
277 ret = WaitForSingleObject(hThread, 100);
278 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
279 CloseHandle(hThread);
280
281 /* create and wait for remote thread with entry point CloseHandle() */
282 hThread = CreateRemoteThread(hProcess, NULL, 0,
283 threadFunc_CloseHandle,
284 hRemoteEvent, 0, &tid);
285 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
286 ret = WaitForSingleObject(hThread, 100);
287 ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret);
288 CloseHandle(hThread);
289
290 /* create remote thread with entry point SetEvent() */
291 hThread = CreateRemoteThread(hProcess, NULL, 0,
292 threadFunc_SetEvent,
293 hRemoteEvent, 0, &tid);
294 ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError());
295
296 /* closed handle, so wait times out */
297 ret = WaitForSingleObject(hEvent, 100);
298 ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret);
299
300 /* check that remote SetEvent() failed */
301 ret = GetExitCodeThread(hThread, &exitcode);
302 ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError());
303 if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n");
304 CloseHandle(hThread);
305
306 cleanup:
307 TerminateProcess(hProcess, 0);
308 CloseHandle(hEvent);
309 CloseHandle(hProcess);
310 }
311
312 /* Check basic functionality of CreateThread and Tls* functions */
313 static VOID test_CreateThread_basic(void)
314 {
315 HANDLE thread[NUM_THREADS],event[NUM_THREADS];
316 DWORD threadid[NUM_THREADS],curthreadId;
317 DWORD threadmem[NUM_THREADS];
318 DWORD exitCode;
319 t1Struct tstruct[NUM_THREADS];
320 int error;
321 DWORD i,j;
322 DWORD GLE, ret;
323
324 /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
325 ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
326
327 /* Retrieve current Thread ID for later comparisons */
328 curthreadId=GetCurrentThreadId();
329 /* Allocate some local storage */
330 ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
331 /* Create events for thread synchronization */
332 for(i=0;i<NUM_THREADS;i++) {
333 threadmem[i]=0;
334 /* Note that it doesn't matter what type of event we choose here. This
335 test isn't trying to thoroughly test events
336 */
337 event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
338 tstruct[i].threadnum=i;
339 tstruct[i].threadmem=threadmem;
340 tstruct[i].event=event;
341 }
342
343 /* Test that passing arguments to threads works okay */
344 for(i=0;i<NUM_THREADS;i++) {
345 thread[i] = CreateThread(NULL,0,threadFunc1,
346 &tstruct[i],0,&threadid[i]);
347 ok(thread[i]!=NULL,"Create Thread failed\n");
348 }
349 /* Test that the threads actually complete */
350 for(i=0;i<NUM_THREADS;i++) {
351 error=WaitForSingleObject(thread[i],5000);
352 ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
353 if(error!=WAIT_OBJECT_0) {
354 TerminateThread(thread[i],i+NUM_THREADS);
355 }
356 ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
357 ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
358 }
359 /* Test that each thread executed in its parent's address space
360 (it was able to change threadmem and pass that change back to its parent)
361 and that each thread id was independent). Note that we prove that the
362 threads actually execute concurrently by having them block on each other
363 in threadFunc1
364 */
365 for(i=0;i<NUM_THREADS;i++) {
366 error=0;
367 for(j=i+1;j<NUM_THREADS;j++) {
368 if (threadmem[i]==threadmem[j]) {
369 error=1;
370 }
371 }
372 ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
373 "Thread did not execute successfully\n");
374 ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
375 }
376 ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
377
378 /* Test how passing NULL as a pointer to threadid works */
379 SetLastError(0xFACEaBAD);
380 thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL);
381 GLE = GetLastError();
382 if (thread[0]) { /* NT */
383 ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE);
384 ret = WaitForSingleObject(thread[0],100);
385 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
386 ret = GetExitCodeThread(thread[0],&exitCode);
387 ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret);
388 ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode);
389 ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
390 }
391 else { /* 9x */
392 ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE);
393 }
394 }
395
396 /* Check that using the CREATE_SUSPENDED flag works */
397 static VOID test_CreateThread_suspended(void)
398 {
399 HANDLE thread;
400 DWORD threadId;
401 int error;
402
403 thread = CreateThread(NULL,0,threadFunc2,NULL,
404 CREATE_SUSPENDED,&threadId);
405 ok(thread!=NULL,"Create Thread failed\n");
406 /* Check that the thread is suspended */
407 ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
408 ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
409 /* Check that resume thread didn't actually start the thread. I can't think
410 of a better way of checking this than just waiting. I am not sure if this
411 will work on slow computers.
412 */
413 ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
414 "ResumeThread should not have actually started the thread\n");
415 /* Now actually resume the thread and make sure that it actually completes*/
416 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
417 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
418 "Thread did not resume\n");
419 if(error!=WAIT_OBJECT_0) {
420 TerminateThread(thread,1);
421 }
422 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
423 }
424
425 /* Check that SuspendThread and ResumeThread work */
426 static VOID test_SuspendThread(void)
427 {
428 HANDLE thread,access_thread;
429 DWORD threadId,exitCode,error;
430 int i;
431
432 thread = CreateThread(NULL,0,threadFunc3,NULL,
433 0,&threadId);
434 ok(thread!=NULL,"Create Thread failed\n");
435 /* Check that the thread is suspended */
436 /* Note that this is a polling method, and there is a race between
437 SuspendThread being called (in the child, and the loop below timing out,
438 so the test could fail on a heavily loaded or slow computer.
439 */
440 error=0;
441 for(i=0;error==0 && i<100;i++) {
442 error=SuspendThread(thread);
443 ResumeThread(thread);
444 if(error==0) {
445 Sleep(50);
446 i++;
447 }
448 }
449 ok(error==1,"SuspendThread did not work\n");
450 /* check that access restrictions are obeyed */
451 if (pOpenThread) {
452 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
453 0,threadId);
454 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
455 if (access_thread!=NULL) {
456 obey_ar(SuspendThread(access_thread)==~0U);
457 obey_ar(ResumeThread(access_thread)==~0U);
458 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
459 }
460 }
461 /* Double check that the thread really is suspended */
462 ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
463 "Thread did not really suspend\n");
464 /* Resume the thread, and make sure it actually completes */
465 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
466 ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
467 "Thread did not resume\n");
468 if(error!=WAIT_OBJECT_0) {
469 TerminateThread(thread,1);
470 }
471 /* Trying to suspend a terminated thread should fail */
472 error=SuspendThread(thread);
473 ok(error==~0U, "wrong return code: %d\n", error);
474 ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError());
475
476 ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
477 }
478
479 /* Check that TerminateThread works properly
480 */
481 static VOID test_TerminateThread(void)
482 {
483 HANDLE thread,access_thread,event;
484 DWORD threadId,exitCode;
485 event=CreateEventA(NULL,TRUE,FALSE,NULL);
486 thread = CreateThread(NULL,0,threadFunc4,
487 (LPVOID)event, 0,&threadId);
488 ok(thread!=NULL,"Create Thread failed\n");
489 /* TerminateThread has a race condition in Wine. If the thread is terminated
490 before it starts, it leaves a process behind. Therefore, we wait for the
491 thread to signal that it has started. There is no easy way to force the
492 race to occur, so we don't try to find it.
493 */
494 ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
495 "TerminateThread didn't work\n");
496 /* check that access restrictions are obeyed */
497 if (pOpenThread) {
498 access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
499 0,threadId);
500 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
501 if (access_thread!=NULL) {
502 obey_ar(TerminateThread(access_thread,99)==0);
503 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
504 }
505 }
506 /* terminate a job and make sure it terminates */
507 ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
508 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
509 "TerminateThread didn't work\n");
510 ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
511 "TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
512 ok(exitCode==99, "TerminateThread returned invalid exit code\n");
513 ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
514 }
515
516 /* Check if CreateThread obeys the specified stack size. This code does
517 not work properly, and is currently disabled
518 */
519 static VOID test_CreateThread_stack(void)
520 {
521 #if CHECK_STACK
522 /* The only way I know of to test the stack size is to use alloca
523 and __try/__except. However, this is probably not portable,
524 and I couldn't get it to work under Wine anyhow. However, here
525 is the code which should allow for testing that CreateThread
526 respects the stack-size limit
527 */
528 HANDLE thread;
529 DWORD threadId,exitCode;
530
531 SYSTEM_INFO sysInfo;
532 sysInfo.dwPageSize=0;
533 GetSystemInfo(&sysInfo);
534 ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
535 thread = CreateThread(NULL,sysInfo.dwPageSize,
536 threadFunc5,&exitCode,
537 0,&threadId);
538 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
539 "TerminateThread didn't work\n");
540 ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
541 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
542 #endif
543 }
544
545 /* Check whether setting/retrieving thread priorities works */
546 static VOID test_thread_priority(void)
547 {
548 HANDLE curthread,access_thread;
549 DWORD curthreadId,exitCode;
550 int min_priority=-2,max_priority=2;
551 BOOL disabled,rc;
552 int i;
553
554 curthread=GetCurrentThread();
555 curthreadId=GetCurrentThreadId();
556 /* Check thread priority */
557 /* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
558 is -2 to 2. However, even on a real Win2k system, using thread
559 priorities beyond the -2 to 2 range does not work. If you want to try
560 anyway, enable USE_EXTENDED_PRIORITIES
561 */
562 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
563 "GetThreadPriority Failed\n");
564
565 if (pOpenThread) {
566 /* check that access control is obeyed */
567 access_thread=pOpenThread(THREAD_ALL_ACCESS &
568 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
569 0,curthreadId);
570 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
571 if (access_thread!=NULL) {
572 obey_ar(SetThreadPriority(access_thread,1)==0);
573 obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
574 obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
575 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
576 }
577 }
578 #if USE_EXTENDED_PRIORITIES
579 min_priority=-7; max_priority=6;
580 #endif
581 for(i=min_priority;i<=max_priority;i++) {
582 ok(SetThreadPriority(curthread,i)!=0,
583 "SetThreadPriority Failed for priority: %d\n",i);
584 ok(GetThreadPriority(curthread)==i,
585 "GetThreadPriority Failed for priority: %d\n",i);
586 }
587 ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
588 "SetThreadPriority Failed\n");
589 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
590 "GetThreadPriority Failed\n");
591 ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
592 "SetThreadPriority Failed\n");
593 ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
594 "GetThreadPriority Failed\n");
595 ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
596
597 /* Check that the thread priority is not changed if SetThreadPriority
598 is called with a value outside of the max/min range */
599 SetThreadPriority(curthread,min_priority);
600 SetLastError(0xdeadbeef);
601 rc = SetThreadPriority(curthread,min_priority-1);
602
603 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
604 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
605 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
606 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
607 GetLastError());
608 ok(GetThreadPriority(curthread)==min_priority,
609 "GetThreadPriority didn't return min_priority\n");
610
611 SetThreadPriority(curthread,max_priority);
612 SetLastError(0xdeadbeef);
613 rc = SetThreadPriority(curthread,max_priority+1);
614
615 ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n");
616 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
617 GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */,
618 "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n",
619 GetLastError());
620 ok(GetThreadPriority(curthread)==max_priority,
621 "GetThreadPriority didn't return max_priority\n");
622
623 /* Check thread priority boost */
624 if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
625 return; /* Win9x */
626
627 SetLastError(0xdeadbeef);
628 rc=pGetThreadPriorityBoost(curthread,&disabled);
629 if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
630 return; /* WinME */
631
632 todo_wine
633 ok(rc!=0,"error=%d\n",GetLastError());
634
635 if (pOpenThread) {
636 /* check that access control is obeyed */
637 access_thread=pOpenThread(THREAD_ALL_ACCESS &
638 (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
639 0,curthreadId);
640 ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
641 if (access_thread!=NULL) {
642 obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
643 obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
644 ok(CloseHandle(access_thread),"Error Closing thread handle\n");
645 }
646 }
647
648 todo_wine {
649 rc = pSetThreadPriorityBoost(curthread,1);
650 ok( rc != 0, "error=%d\n",GetLastError());
651 rc=pGetThreadPriorityBoost(curthread,&disabled);
652 ok(rc!=0 && disabled==1,
653 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
654
655 rc = pSetThreadPriorityBoost(curthread,0);
656 ok( rc != 0, "error=%d\n",GetLastError());
657 rc=pGetThreadPriorityBoost(curthread,&disabled);
658 ok(rc!=0 && disabled==0,
659 "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled);
660 }
661 }
662
663 /* check the GetThreadTimes function */
664 static VOID test_GetThreadTimes(void)
665 {
666 HANDLE thread,access_thread=NULL;
667 FILETIME creationTime,exitTime,kernelTime,userTime;
668 DWORD threadId;
669 int error;
670
671 thread = CreateThread(NULL,0,threadFunc2,NULL,
672 CREATE_SUSPENDED,&threadId);
673
674 ok(thread!=NULL,"Create Thread failed\n");
675 /* check that access control is obeyed */
676 if (pOpenThread) {
677 access_thread=pOpenThread(THREAD_ALL_ACCESS &
678 (~THREAD_QUERY_INFORMATION), 0,threadId);
679 ok(access_thread!=NULL,
680 "OpenThread returned an invalid handle\n");
681 }
682 ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
683 ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
684 "ResumeThread didn't work\n");
685 creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
686 exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
687 kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
688 userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
689 /* GetThreadTimes should set all of the parameters passed to it */
690 error=GetThreadTimes(thread,&creationTime,&exitTime,
691 &kernelTime,&userTime);
692 if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
693 ok(error!=0,"GetThreadTimes failed\n");
694 ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
695 "creationTime was invalid\n");
696 ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
697 "exitTime was invalid\n");
698 ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
699 "kernelTimewas invalid\n");
700 ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
701 "userTime was invalid\n");
702 ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
703 if(access_thread!=NULL)
704 {
705 error=GetThreadTimes(access_thread,&creationTime,&exitTime,
706 &kernelTime,&userTime);
707 obey_ar(error==0);
708 }
709 }
710 if(access_thread!=NULL) {
711 ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
712 }
713 }
714
715 /* Check the processor affinity functions */
716 /* NOTE: These functions should also be checked that they obey access control
717 */
718 static VOID test_thread_processor(void)
719 {
720 HANDLE curthread,curproc;
721 DWORD_PTR processMask,systemMask;
722 SYSTEM_INFO sysInfo;
723 int error=0;
724
725 sysInfo.dwNumberOfProcessors=0;
726 GetSystemInfo(&sysInfo);
727 ok(sysInfo.dwNumberOfProcessors>0,
728 "GetSystemInfo failed to return a valid # of processors\n");
729 /* Use the current Thread/process for all tests */
730 curthread=GetCurrentThread();
731 ok(curthread!=NULL,"GetCurrentThread failed\n");
732 curproc=GetCurrentProcess();
733 ok(curproc!=NULL,"GetCurrentProcess failed\n");
734 /* Check the Affinity Mask functions */
735 ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
736 "GetProcessAffinityMask failed\n");
737 ok(SetThreadAffinityMask(curthread,processMask)==processMask,
738 "SetThreadAffinityMask failed\n");
739 ok(SetThreadAffinityMask(curthread,processMask+1)==0,
740 "SetThreadAffinityMask passed for an illegal processor\n");
741 /* NOTE: This only works on WinNT/2000/XP) */
742 if (pSetThreadIdealProcessor) {
743 todo_wine {
744 SetLastError(0);
745 error=pSetThreadIdealProcessor(curthread,0);
746 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
747 ok(error!=-1, "SetThreadIdealProcessor failed\n");
748 }
749 }
750 if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
751 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
752 ok(error==-1,
753 "SetThreadIdealProcessor succeeded with an illegal processor #\n");
754 todo_wine {
755 error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
756 ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
757 }
758 }
759 }
760 }
761
762 static VOID test_GetThreadExitCode(void)
763 {
764 DWORD exitCode, threadid;
765 DWORD GLE, ret;
766 HANDLE thread;
767
768 ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
769 ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret);
770 GLE = GetLastError();
771 ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE);
772
773 thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
774 ret = WaitForSingleObject(thread,100);
775 ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
776 ret = GetExitCodeThread(thread,&exitCode);
777 ok(ret==exitCode || ret==1,
778 "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode);
779 ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode);
780 ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
781 }
782
783 #ifdef __i386__
784
785 static int test_value = 0;
786 static HANDLE event;
787
788 static void WINAPI set_test_val( int val )
789 {
790 test_value += val;
791 }
792
793 static DWORD WINAPI threadFunc6(LPVOID p)
794 {
795 SetEvent( event );
796 Sleep( 1000 );
797 test_value *= (int)p;
798 return 0;
799 }
800
801 static void test_SetThreadContext(void)
802 {
803 CONTEXT ctx;
804 int *stack;
805 HANDLE thread;
806 DWORD threadid;
807 DWORD prevcount;
808 BOOL ret;
809
810 SetLastError(0xdeadbeef);
811 event = CreateEvent( NULL, TRUE, FALSE, NULL );
812 thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
813 ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() );
814 if (!thread)
815 {
816 trace("Thread creation failed, skipping rest of test\n");
817 return;
818 }
819 WaitForSingleObject( event, INFINITE );
820 SuspendThread( thread );
821 CloseHandle( event );
822
823 ctx.ContextFlags = CONTEXT_FULL;
824 SetLastError(0xdeadbeef);
825 ret = GetThreadContext( thread, &ctx );
826 ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() );
827
828 if (ret)
829 {
830 /* simulate a call to set_test_val(10) */
831 stack = (int *)ctx.Esp;
832 stack[-1] = 10;
833 stack[-2] = ctx.Eip;
834 ctx.Esp -= 2 * sizeof(int *);
835 ctx.Eip = (DWORD)set_test_val;
836 SetLastError(0xdeadbeef);
837 ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%d)\n", GetLastError() );
838 }
839
840 SetLastError(0xdeadbeef);
841 prevcount = ResumeThread( thread );
842 ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n",
843 prevcount, GetLastError() );
844
845 WaitForSingleObject( thread, INFINITE );
846 ok( test_value == 20, "test_value %d instead of 20\n", test_value );
847 }
848
849 #endif /* __i386__ */
850
851 static HANDLE finish_event;
852 static LONG times_executed;
853
854 static DWORD CALLBACK work_function(void *p)
855 {
856 LONG executed = InterlockedIncrement(&times_executed);
857
858 if (executed == 100)
859 SetEvent(finish_event);
860 return 0;
861 }
862
863 static void test_QueueUserWorkItem(void)
864 {
865 int i;
866 DWORD wait_result;
867 DWORD before, after;
868
869 /* QueueUserWorkItem not present on win9x */
870 if (!pQueueUserWorkItem) return;
871
872 finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
873
874 before = GetTickCount();
875
876 for (i = 0; i < 100; i++)
877 {
878 BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
879 ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError());
880 }
881
882 wait_result = WaitForSingleObject(finish_event, 10000);
883
884 after = GetTickCount();
885 trace("100 QueueUserWorkItem calls took %dms\n", after - before);
886 ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result);
887
888 ok(times_executed == 100, "didn't execute all of the work items\n");
889 }
890
891 static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired)
892 {
893 HANDLE event = p;
894 SetEvent(event);
895 ok(!TimerOrWaitFired, "wait shouldn't have timed out\n");
896 }
897
898 static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired)
899 {
900 HANDLE event = p;
901 SetEvent(event);
902 ok(TimerOrWaitFired, "wait should have timed out\n");
903 }
904
905 static void test_RegisterWaitForSingleObject(void)
906 {
907 BOOL ret;
908 HANDLE wait_handle;
909 HANDLE handle;
910 HANDLE complete_event;
911
912 if (!pRegisterWaitForSingleObject || !pUnregisterWait)
913 {
914 skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n");
915 return;
916 }
917
918 /* test signaled case */
919
920 handle = CreateEvent(NULL, TRUE, TRUE, NULL);
921 complete_event = CreateEvent(NULL, FALSE, FALSE, NULL);
922
923 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
924 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
925
926 WaitForSingleObject(complete_event, INFINITE);
927 /* give worker thread chance to complete */
928 Sleep(100);
929
930 ret = pUnregisterWait(wait_handle);
931 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
932
933 /* test cancel case */
934
935 ResetEvent(handle);
936
937 ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
938 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
939
940 ret = pUnregisterWait(wait_handle);
941 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
942
943 /* test timeout case */
944
945 ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE);
946 ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError());
947
948 WaitForSingleObject(complete_event, INFINITE);
949 /* give worker thread chance to complete */
950 Sleep(100);
951
952 ret = pUnregisterWait(wait_handle);
953 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
954 }
955
956 START_TEST(thread)
957 {
958 HINSTANCE lib;
959 int argc;
960 char **argv;
961 argc = winetest_get_mainargs( &argv );
962 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
963 so that the compile passes
964 */
965 lib=GetModuleHandleA("kernel32.dll");
966 ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
967 pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
968 pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
969 pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
970 pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
971 pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
972 pRegisterWaitForSingleObject=(RegisterWaitForSingleObject_t)GetProcAddress(lib,"RegisterWaitForSingleObject");
973 pUnregisterWait=(UnregisterWait_t)GetProcAddress(lib,"UnregisterWait");
974
975 if (argc >= 3)
976 {
977 if (!strcmp(argv[2], "sleep"))
978 {
979 HANDLE hAddrEvents[2];
980 create_function_addr_events(hAddrEvents);
981 SetEvent(hAddrEvents[0]);
982 SetEvent(hAddrEvents[1]);
983 Sleep(5000); /* spawned process runs for at most 5 seconds */
984 return;
985 }
986 while (1)
987 {
988 HANDLE hThread;
989 hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, NULL);
990 ok(hThread != NULL, "CreateThread failed, error %u\n",
991 GetLastError());
992 ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0,
993 "Thread did not exit in time\n");
994 if (hThread == NULL) break;
995 CloseHandle(hThread);
996 }
997 return;
998 }
999
1000 test_CreateRemoteThread();
1001 test_CreateThread_basic();
1002 test_CreateThread_suspended();
1003 test_SuspendThread();
1004 test_TerminateThread();
1005 test_CreateThread_stack();
1006 test_thread_priority();
1007 test_GetThreadTimes();
1008 test_thread_processor();
1009 test_GetThreadExitCode();
1010 #ifdef __i386__
1011 test_SetThreadContext();
1012 #endif
1013 test_QueueUserWorkItem();
1014 test_RegisterWaitForSingleObject();
1015 }