Better implementation of GetCalendarInfo{A,W}, not perfect.
[wine] / dlls / kernel / tests / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "wine/test.h"
22 #include <winbase.h>
23 #include <winnt.h>
24 #include <winerror.h>
25
26 /* Specify the number of simultaneous threads to test */
27 #define NUM_THREADS 4
28 /* Specify whether to test the extended priorities for Win2k/XP */
29 #define USE_EXTENDED_PRIORITIES 0
30 /* Specify whether to test the stack allocation in CreateThread */
31 #define CHECK_STACK 0
32
33 /* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
34    CreateThread.  So far I have been unable to make this work, and
35    I am in doubt as to how portable it is.  Also, according to MSDN,
36    you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
37    Anyhow, the check is currently commented out
38 */
39 #if CHECK_STACK
40   #ifdef __try
41     #define __TRY __try
42     #define __EXCEPT __except
43     #define __ENDTRY
44   #else
45     #include "wine/exception.h"
46   #endif
47 #endif
48 typedef HANDLE WINAPI (*OPENTHREADPTR)(DWORD,BOOL,DWORD);
49 OPENTHREADPTR OpenThreadPtr;
50 HANDLE WINAPI OpenThreadDefault(DWORD dwDesiredAccess,
51                          BOOL bInheritHandle,
52                          DWORD dwThreadId)
53 {
54   return (HANDLE)NULL;
55 }
56 /* define a check for whether we are running in Win2k or XP */
57 #define WIN2K_PLUS(version) (version < 0x80000000 && (version & 0xFF) >= 5)
58
59 /* Functions not tested yet:
60   AttachThreadInput
61   CreateRemoteThread
62   SetThreadContext
63   SwitchToThread
64
65 In addition there are no checks that the inheritance works properly in
66 CreateThread
67 */
68
69 DWORD tlsIndex;
70
71 typedef struct {
72   int threadnum;
73   HANDLE *event;
74   DWORD *threadmem;
75 } t1Struct;
76
77 /* Basic test that simulatneous threads can access shared memory,
78    that the thread local storage routines work correctly, and that
79    threads actually run concurrently
80 */
81 VOID WINAPI threadFunc1(t1Struct *tstruct)
82 {
83    int i;
84 /* write our thread # into shared memory */
85    tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
86    ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
87       "TlsSetValue failed");
88 /* The threads synchronize before terminating.  This is done by
89    Signaling an event, and waiting for all events to occur
90 */
91    SetEvent(tstruct->event[tstruct->threadnum]);
92    WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
93 /* Double check that all threads really did run by validating that
94    they have all written to the shared memory. There should be no race
95    here, since all threads were synchronized after the write.*/
96    for(i=0;i<NUM_THREADS;i++) {
97      while(tstruct->threadmem[i]==0) ;
98    }
99 /* Check that noone cahnged our tls memory */
100    ok((DWORD)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
101       "TlsGetValue failed");
102    ExitThread(NUM_THREADS+tstruct->threadnum);
103 }
104
105 VOID WINAPI threadFunc2()
106 {
107    ExitThread(99);
108 }
109
110 VOID WINAPI threadFunc3()
111 {
112    HANDLE thread;
113    thread=GetCurrentThread();
114    SuspendThread(thread);
115    ExitThread(99);
116 }
117
118 VOID WINAPI threadFunc4(HANDLE event)
119 {
120    if(event != (HANDLE)NULL) {
121      SetEvent(event);
122    }
123    Sleep(99000);
124    ExitThread(0);
125 }
126
127 #if CHECK_STACK
128 VOID WINAPI threadFunc5(DWORD *exitCode)
129 {
130   SYSTEM_INFO sysInfo;
131   sysInfo.dwPageSize=0;
132   GetSystemInfo(&sysInfo);
133   *exitCode=0;
134    __TRY
135    {
136      alloca(2*sysInfo.dwPageSize);
137    }
138     __EXCEPT(1) {
139      *exitCode=1;
140    }
141    __ENDTRY
142    ExitThread(0);
143 }
144 #endif
145
146 /* Check basic funcationality of CreateThread and Tls* functions */
147 VOID test_CreateThread_basic(DWORD version)
148 {
149    HANDLE thread[NUM_THREADS],event[NUM_THREADS];
150    DWORD threadid[NUM_THREADS],curthreadId;
151    DWORD threadmem[NUM_THREADS];
152    DWORD exitCode;
153    t1Struct tstruct[NUM_THREADS];
154    int error;
155    int i,j;
156 /* Retrieve current Thread ID for later comparisons */
157   curthreadId=GetCurrentThreadId();
158 /* Allocate some local storage */
159   ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed");
160 /* Create events for thread synchronization */
161   for(i=0;i<NUM_THREADS;i++) {
162     threadmem[i]=0;
163 /* Note that it doesn't matter what type of event we chose here.  This
164    test isn't trying to thoroughly test events
165 */
166     event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
167     tstruct[i].threadnum=i;
168     tstruct[i].threadmem=threadmem;
169     tstruct[i].event=event;
170   }
171
172 /* Test that passing arguments to threads works okay */
173   for(i=0;i<NUM_THREADS;i++) {
174     thread[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc1,
175                              &tstruct[i],0,&threadid[i]);
176     ok(thread[i]!=(HANDLE)NULL,"Create Thread failed.");
177   }
178 /* Test that the threads actually complete */
179   for(i=0;i<NUM_THREADS;i++) {
180     error=WaitForSingleObject(thread[i],5000);
181     ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit");
182     if(ok!=WAIT_OBJECT_0) {
183       TerminateThread(thread[i],1);
184     }
185     ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code");
186     todo_wine {
187       ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code");
188     }
189   }
190 /* Test that each thread executed in its parent's address space
191    (it was able to change threadmem and pass that change back to its parent)
192    and that each thread id was independant).  Note that we prove that the
193    threads actually execute concurrently by having them block on each other
194    in threadFunc1
195 */
196   for(i=0;i<NUM_THREADS;i++) {
197     error=0;
198     for(j=i+1;j<NUM_THREADS;j++) {
199       if (threadmem[i]==threadmem[j]) {
200         error=1;
201       }
202     }
203     ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
204          "Thread did not execute successfully");
205     ok(CloseHandle(thread[i])!=0,"CloseHandle failed");
206   }
207   ok(TlsFree(tlsIndex)!=0,"TlsFree failed");
208 }
209
210 /* Check that using the CREATE_SUSPENDED flag works */
211 VOID test_CreateThread_suspended(DWORD version)
212 {
213   HANDLE thread;
214   DWORD threadId;
215   int error;
216
217   thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
218                         CREATE_SUSPENDED,&threadId);
219   ok(thread!=(HANDLE)NULL,"Create Thread failed.");
220 /* Check that the thread is suspended */
221   ok(SuspendThread(thread)==1,"Thread did not start suspended");
222   ok(ResumeThread(thread)==2,"Resume thread returned an invalid value");
223 /* Check that resume thread didn't actually start the thread.  I can't think
224    of a better way of checking this than just waiting.  I am not sure if this
225    will work on slow computers.
226 */
227   ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
228      "ResumeThread should not have actually started the thread");
229 /* Now actually resume the thread and make sure that it actually completes*/
230   ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
231   ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
232      "Thread did not resume");
233   if(error!=WAIT_OBJECT_0) {
234     TerminateThread(thread,1);
235   }
236   ok(CloseHandle(thread)!=0,"CloseHandle failed");
237 }
238
239 /* Check that SuspendThread and ResumeThread work */
240 VOID test_SuspendThread(DWORD version)
241 {
242   HANDLE thread,access_thread;
243   DWORD threadId,exitCode;
244   int i,error;
245
246   thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc3,NULL,
247                         0,&threadId);
248   ok(thread!=(HANDLE)NULL,"Create Thread failed.");
249 /* Check that the thread is suspended */
250 /* Note that this is a polling method, and there is a race between
251    SuspendThread being called (in the child, and the loop below timing out,
252    so the test could fail on a heavily loaded or slow computer.
253 */
254   error=0;
255   for(i=0;error==0 && i<100;i++) {
256     error=SuspendThread(thread);
257     ResumeThread(thread);
258     if(error==0) {
259       Sleep(50);
260       i++;
261     }
262   }
263   ok(error==1,"SuspendThread did not work");
264 /* check that access restrictions are obeyed */
265   if(WIN2K_PLUS(version)) {
266     access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
267                            0,threadId);
268     ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
269     if(access_thread!=(HANDLE)NULL) {
270       ok(SuspendThread(access_thread)==-1,
271          "SuspendThread did not obey access restrictions");
272       ok(ResumeThread(access_thread)==-1,
273          "ResumeThread did not obey access restrictions");
274       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
275     }
276   }
277 /* Double check that the thread really is suspended */
278   ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
279      "Thread did not really suspend");
280 /* Resume the thread, and make sure it actually completes */
281   ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
282   ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
283      "Thread did not resume");
284   if(error!=WAIT_OBJECT_0) {
285     TerminateThread(thread,1);
286   }
287   ok(CloseHandle(thread)!=0,"CloseHandle Failed");
288 }
289
290 /* Check that TerminateThread works properly
291 */
292 VOID test_TerminateThread(DWORD version)
293 {
294   HANDLE thread,access_thread,event;
295   DWORD threadId,exitCode;
296   int i,error;
297   i=0; error=0;
298   event=CreateEventA(NULL,TRUE,FALSE,NULL);
299   thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc4,
300                         (LPVOID)event, 0,&threadId);
301   ok(thread!=(HANDLE)NULL,"Create Thread failed.");
302 /* Terminate thread has a race condition in Wine.  If the thread is terminated
303    before it starts, it leaves a process behind.  Therefore, we wait for the
304    thread to signal that it has started.  There is no easy way to force the
305    race to occur, so we don't try to find it.
306 */
307   ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
308      "TerminateThread didn't work");
309 /* check that access restrictions are obeyed */
310   if(WIN2K_PLUS(version)) {
311     access_thread=OpenThreadPtr(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
312                              0,threadId);
313     ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
314     if(access_thread!=(HANDLE)NULL) {
315       ok(TerminateThread(access_thread,99)==0,
316          "TerminateThread did not obey access restrictions");
317       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
318     }
319   }
320 /* terminate a job and make sure it terminates */
321   ok(TerminateThread(thread,99)!=0,"TerminateThread failed");
322   ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
323      "TerminateThread didn't work");
324   ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
325      "TerminateThread should not leave the thread 'STILL_ACTIVE'");
326   if(WIN2K_PLUS(version)) {
327 /*NOTE: In Win2k, GetExitCodeThread does not return the value specified by
328         TerminateThread, even though MSDN says it should.  So currently
329         there is no check being done for this.
330 */
331     trace("TerminateThread returned: 0x%lx instead of 0x%x\n",exitCode,99);
332   } else {
333     ok(exitCode==99, "TerminateThread returned invalid exit code");
334   }
335   ok(CloseHandle(thread)!=0,"Error Closing thread handle");
336 }
337
338 /* Check if CreateThread obeys the specified stack size.  This code does
339    not work properly, and is currently disabled
340 */
341 VOID test_CreateThread_stack(DWORD version)
342 {
343 #if CHECK_STACK
344 /* The only way I know of to test the stack size is to use alloca
345    and __try/__except.  However, this is probably not portable,
346    and I couldn't get it to work under Wine anyhow.  However, here
347    is the code which should allow for testing that CreateThread
348    respects the stack-size limit
349 */
350      HANDLE thread;
351      DWORD threadId,exitCode;
352
353      SYSTEM_INFO sysInfo;
354      sysInfo.dwPageSize=0;
355      GetSystemInfo(&sysInfo);
356      ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size");
357      thread = CreateThread(NULL,sysInfo.dwPageSize,
358                            (LPTHREAD_START_ROUTINE)threadFunc5,&exitCode,
359                            0,&threadId);
360      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
361         "TerminateThread didn't work");
362      ok(exitCode==1,"CreateThread did not obey stack-size-limit");
363      ok(CloseHandle(thread)!=0,"CloseHandle failed");
364 #endif
365 }
366
367 /* Check whether setting/retreiving thread priorities works */
368 VOID test_thread_priority(DWORD version)
369 {
370    HANDLE curthread,access_thread;
371    DWORD curthreadId,exitCode;
372    int min_priority=-2,max_priority=2;
373    int i,error;
374
375    curthread=GetCurrentThread();
376    curthreadId=GetCurrentThreadId();
377 /* Check thread priority */
378 /* NOTE: on Win2k/XP priority can be from -7 to 6.  All other platforms it
379          is -2 to 2.  However, even on a real Win2k system, using thread
380          priorities beyond the -2 to 2 range does not work.  If you want to try
381          anyway, enable USE_EXTENDED_PRIORITIES
382 */
383    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
384       "GetThreadPriority Failed");
385
386    if(WIN2K_PLUS(version)) {
387 /* check that access control is obeyed */
388      access_thread=OpenThreadPtr(THREAD_ALL_ACCESS &
389                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
390                        0,curthreadId);
391      ok(access_thread!=(HANDLE)NULL,"OpenThread returned an invalid handle");
392      if(access_thread!=(HANDLE)NULL) {
393        ok(SetThreadPriority(access_thread,1)==0,
394           "SetThreadPriority did not obey access restrictions");
395        ok(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN,
396           "GetThreadPriority did not obey access restrictions");
397        ok(SetThreadPriorityBoost(access_thread,1)==0,
398           "SetThreadPriorityBoost did not obey access restrictions");
399        ok(GetThreadPriorityBoost(access_thread,&error)==0,
400           "GetThreadPriorityBoost did not obey access restrictions");
401        ok(GetExitCodeThread(access_thread,&exitCode)==0,
402           "GetExitCodeThread did not obey access restrictions");
403        ok(CloseHandle(access_thread),"Error Closing thread handle");
404      }
405 #if USE_EXTENDED_PRIORITIES
406      min_priority=-7; max_priority=6;
407 #endif
408    }
409    for(i=min_priority;i<=max_priority;i++) {
410      ok(SetThreadPriority(curthread,i)!=0,
411         "SetThreadPriority Failed for priority: %d",i);
412      ok(GetThreadPriority(curthread)==i,
413         "GetThreadPriority Failed for priority: %d",i);
414    }
415    ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
416       "SetThreadPriority Failed");
417    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
418       "GetThreadPriority Failed");
419    ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
420        "SetThreadPriority Failed");
421    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
422        "GetThreadPriority Failed");
423    ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed");
424
425 /* Check thread priority boost */
426 /* NOTE: This only works on WinNT/2000/XP) */
427    if(version < 0x80000000) {
428      todo_wine {
429        ok(SetThreadPriorityBoost(curthread,1)!=0,
430           "SetThreadPriorityBoost Failed");
431        ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==1,
432           "GetThreadPriorityBoost Failed");
433        ok(SetThreadPriorityBoost(curthread,0)!=0,
434           "SetThreadPriorityBoost Failed");
435        ok(GetThreadPriorityBoost(curthread,&error)!=0 && error==0,
436           "GetThreadPriorityBoost Failed");
437      }
438    }
439 }
440
441 /* check the GetThreadTimes function */
442 VOID test_GetThreadTimes(DWORD version)
443 {
444      HANDLE thread,access_thread=(HANDLE)NULL;
445      FILETIME creationTime,exitTime,kernelTime,userTime;
446      DWORD threadId;
447      int error;
448
449      thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
450                            CREATE_SUSPENDED,&threadId);
451
452      ok(thread!=(HANDLE)NULL,"Create Thread failed.");
453 /* check that access control is obeyed */
454      if(WIN2K_PLUS(version)) {
455        access_thread=OpenThreadPtr(THREAD_ALL_ACCESS &
456                                    (~THREAD_QUERY_INFORMATION), 0,threadId);
457        ok(access_thread!=(HANDLE)NULL,
458           "OpenThread returned an invalid handle");
459      }
460      ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
461      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
462         "ResumeThread didn't work");
463      if(WIN2K_PLUS(version)) {
464        if(access_thread!=(HANDLE)NULL) {
465          error=GetThreadTimes(access_thread,&creationTime,&exitTime,
466                               &kernelTime,&userTime);
467          ok(error==0, "GetThreadTimes did not obey access restrictions");
468          ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
469        }
470      }
471      creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
472      exitTime.dwLowDateTime=99;     exitTime.dwHighDateTime=99;
473      kernelTime.dwLowDateTime=99;   kernelTime.dwHighDateTime=99;
474      userTime.dwLowDateTime=99;     userTime.dwHighDateTime=99;
475 /* GetThreadTimes should set all of the parameters passed to it */
476      todo_wine {
477        error=GetThreadTimes(thread,&creationTime,&exitTime,
478                             &kernelTime,&userTime);
479        ok(error!=0,"GetThreadTimes failed");
480        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
481           "creationTime was invalid");
482        ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
483           "exitTime was invalid");
484        ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
485           "kernelTime was invalid");
486        ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
487           "userTime was invalid");
488      }
489      ok(CloseHandle(thread)!=0,"ClosewHandle failed");
490 }
491
492 /* Check the processor affinity functions */
493 /* NOTE: These functions should also be checked that they obey access control
494 */
495 VOID test_thread_processor(DWORD version)
496 {
497    HANDLE curthread,curproc;
498    DWORD processMask,systemMask;
499    SYSTEM_INFO sysInfo;
500    int error=0;
501
502    sysInfo.dwNumberOfProcessors=0;
503    GetSystemInfo(&sysInfo);
504    ok(sysInfo.dwNumberOfProcessors>0,
505       "GetSystemInfo failed to return a valid # of processors");
506 /* Use the current Thread/process for all tests */
507    curthread=GetCurrentThread();
508    ok(curthread!=(HANDLE)NULL,"GetCurrentThread failed");
509    curproc=GetCurrentProcess();
510    ok(curproc!=(HANDLE)NULL,"GetCurrentProcess failed");
511 /* Check the Affinity Mask functions */
512    ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
513       "GetProcessAffinityMask failed");
514    ok(SetThreadAffinityMask(curthread,processMask)==1,
515       "SetThreadAffinityMask failed");
516    ok(SetThreadAffinityMask(curthread,processMask+1)==0,
517       "SetThreadAffinityMask passed for an illegal processor");
518 /* NOTE: This only works on WinNT/2000/XP) */
519    if(version < 0x80000000) {
520      todo_wine {
521        error=SetThreadIdealProcessor(curthread,0);
522        ok(error!=-1, "SetThreadIdealProcessor failed");
523        error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
524      }
525        ok(error==-1,
526           "SetThreadIdealProccesor succeded with an illegal processor #");
527      todo_wine {
528        error=SetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
529        ok(error==0, "SetThreadIdealProccesor returned an incorrect value");
530      }
531    }
532 }
533
534 START_TEST(thread)
535 {
536    DWORD version;
537    HINSTANCE lib;
538    version=GetVersion();
539 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
540    so that the compile passes
541 */
542    lib=LoadLibraryA("kernel32");
543    ok(lib!=(HANDLE)NULL,"Couldn't load kernel32.dll");
544    OpenThreadPtr=(OPENTHREADPTR)GetProcAddress(lib,"OpenThread");
545    if(OpenThreadPtr==NULL) {
546       OpenThreadPtr=&OpenThreadDefault;
547    }
548    test_CreateThread_basic(version);
549    test_CreateThread_suspended(version);
550    test_SuspendThread(version);
551    test_TerminateThread(version);
552    test_CreateThread_stack(version);
553    test_thread_priority(version);
554    test_GetThreadTimes(version);
555    test_thread_processor(version);
556 }