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