Moved atom functions to dlls/kernel.
[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
52 typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
53 static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
54
55 typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
56 static OpenThread_t pOpenThread=NULL;
57
58 typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
59 static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
60
61 typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
62 static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
63
64 /* Functions not tested yet:
65   AttachThreadInput
66   CreateRemoteThread
67   SetThreadContext
68   SwitchToThread
69
70 In addition there are no checks that the inheritance works properly in
71 CreateThread
72 */
73
74 DWORD tlsIndex;
75
76 typedef struct {
77   int threadnum;
78   HANDLE *event;
79   DWORD *threadmem;
80 } t1Struct;
81
82 /* Basic test that simulatneous threads can access shared memory,
83    that the thread local storage routines work correctly, and that
84    threads actually run concurrently
85 */
86 VOID WINAPI threadFunc1(t1Struct *tstruct)
87 {
88    int i;
89 /* write our thread # into shared memory */
90    tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
91    ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
92       "TlsSetValue failed");
93 /* The threads synchronize before terminating.  This is done by
94    Signaling an event, and waiting for all events to occur
95 */
96    SetEvent(tstruct->event[tstruct->threadnum]);
97    WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
98 /* Double check that all threads really did run by validating that
99    they have all written to the shared memory. There should be no race
100    here, since all threads were synchronized after the write.*/
101    for(i=0;i<NUM_THREADS;i++) {
102      while(tstruct->threadmem[i]==0) ;
103    }
104 /* Check that noone cahnged our tls memory */
105    ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
106       "TlsGetValue failed");
107    ExitThread(NUM_THREADS+tstruct->threadnum);
108 }
109
110 VOID WINAPI threadFunc2()
111 {
112    ExitThread(99);
113 }
114
115 VOID WINAPI threadFunc3()
116 {
117    HANDLE thread;
118    thread=GetCurrentThread();
119    SuspendThread(thread);
120    ExitThread(99);
121 }
122
123 VOID WINAPI threadFunc4(HANDLE event)
124 {
125    if(event != NULL) {
126      SetEvent(event);
127    }
128    Sleep(99000);
129    ExitThread(0);
130 }
131
132 #if CHECK_STACK
133 VOID WINAPI threadFunc5(DWORD *exitCode)
134 {
135   SYSTEM_INFO sysInfo;
136   sysInfo.dwPageSize=0;
137   GetSystemInfo(&sysInfo);
138   *exitCode=0;
139    __TRY
140    {
141      alloca(2*sysInfo.dwPageSize);
142    }
143     __EXCEPT(1) {
144      *exitCode=1;
145    }
146    __ENDTRY
147    ExitThread(0);
148 }
149 #endif
150
151 /* Check basic funcationality of CreateThread and Tls* functions */
152 VOID test_CreateThread_basic()
153 {
154    HANDLE thread[NUM_THREADS],event[NUM_THREADS];
155    DWORD threadid[NUM_THREADS],curthreadId;
156    DWORD threadmem[NUM_THREADS];
157    DWORD exitCode;
158    t1Struct tstruct[NUM_THREADS];
159    int error;
160    DWORD i,j;
161 /* Retrieve current Thread ID for later comparisons */
162   curthreadId=GetCurrentThreadId();
163 /* Allocate some local storage */
164   ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed");
165 /* Create events for thread synchronization */
166   for(i=0;i<NUM_THREADS;i++) {
167     threadmem[i]=0;
168 /* Note that it doesn't matter what type of event we chose here.  This
169    test isn't trying to thoroughly test events
170 */
171     event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
172     tstruct[i].threadnum=i;
173     tstruct[i].threadmem=threadmem;
174     tstruct[i].event=event;
175   }
176
177 /* Test that passing arguments to threads works okay */
178   for(i=0;i<NUM_THREADS;i++) {
179     thread[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc1,
180                              &tstruct[i],0,&threadid[i]);
181     ok(thread[i]!=NULL,"Create Thread failed.");
182   }
183 /* Test that the threads actually complete */
184   for(i=0;i<NUM_THREADS;i++) {
185     error=WaitForSingleObject(thread[i],5000);
186     ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit");
187     if(error!=WAIT_OBJECT_0) {
188       TerminateThread(thread[i],i+NUM_THREADS);
189     }
190     ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code");
191     ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code");
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()
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!=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()
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!=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 (pOpenThread) {
269     access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
270                            0,threadId);
271     ok(access_thread!=NULL,"OpenThread returned an invalid handle");
272     if (access_thread!=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   /* Trying to suspend a terminated thread should fail */
291   error=SuspendThread(thread);
292   ok(error==0xffffffff, "wrong return code: %d", error);
293   ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld", GetLastError());
294
295   ok(CloseHandle(thread)!=0,"CloseHandle Failed");
296 }
297
298 /* Check that TerminateThread works properly
299 */
300 VOID test_TerminateThread()
301 {
302   HANDLE thread,access_thread,event;
303   DWORD threadId,exitCode;
304   int i,error;
305   i=0; error=0;
306   event=CreateEventA(NULL,TRUE,FALSE,NULL);
307   thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc4,
308                         (LPVOID)event, 0,&threadId);
309   ok(thread!=NULL,"Create Thread failed.");
310 /* Terminate thread has a race condition in Wine.  If the thread is terminated
311    before it starts, it leaves a process behind.  Therefore, we wait for the
312    thread to signal that it has started.  There is no easy way to force the
313    race to occur, so we don't try to find it.
314 */
315   ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
316      "TerminateThread didn't work");
317 /* check that access restrictions are obeyed */
318   if (pOpenThread) {
319     access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
320                              0,threadId);
321     ok(access_thread!=NULL,"OpenThread returned an invalid handle");
322     if (access_thread!=NULL) {
323       ok(TerminateThread(access_thread,99)==0,
324          "TerminateThread did not obey access restrictions");
325       ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
326     }
327   }
328 /* terminate a job and make sure it terminates */
329   ok(TerminateThread(thread,99)!=0,"TerminateThread failed");
330   ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
331      "TerminateThread didn't work");
332   ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
333      "TerminateThread should not leave the thread 'STILL_ACTIVE'");
334   ok(exitCode==99, "TerminateThread returned invalid exit code");
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()
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()
369 {
370    HANDLE curthread,access_thread;
371    DWORD curthreadId,exitCode;
372    int min_priority=-2,max_priority=2;
373    BOOL disabled;
374    int i;
375
376    curthread=GetCurrentThread();
377    curthreadId=GetCurrentThreadId();
378 /* Check thread priority */
379 /* NOTE: on Win2k/XP priority can be from -7 to 6.  All other platforms it
380          is -2 to 2.  However, even on a real Win2k system, using thread
381          priorities beyond the -2 to 2 range does not work.  If you want to try
382          anyway, enable USE_EXTENDED_PRIORITIES
383 */
384    ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
385       "GetThreadPriority Failed");
386
387    if (pOpenThread) {
388 /* check that access control is obeyed */
389      access_thread=pOpenThread(THREAD_ALL_ACCESS &
390                        (~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
391                        0,curthreadId);
392      ok(access_thread!=NULL,"OpenThread returned an invalid handle");
393      if (access_thread!=NULL) {
394        ok(SetThreadPriority(access_thread,1)==0,
395           "SetThreadPriority did not obey access restrictions");
396        ok(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN,
397           "GetThreadPriority did not obey access restrictions");
398        if (pSetThreadPriorityBoost)
399          ok(pSetThreadPriorityBoost(access_thread,1)==0,
400             "SetThreadPriorityBoost did not obey access restrictions");
401        if (pGetThreadPriorityBoost)
402          ok(pGetThreadPriorityBoost(access_thread,&disabled)==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    if (pGetThreadPriorityBoost && pSetThreadPriorityBoost) {
430      BOOL rc;
431      todo_wine {
432          SetLastError(0);
433          rc=pGetThreadPriorityBoost(curthread,&disabled);
434          if (rc!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
435              ok(rc!=0,"error=%ld",GetLastError());
436
437              ok(pSetThreadPriorityBoost(curthread,1)!=0,
438                 "error=%ld",GetLastError());
439              rc=pGetThreadPriorityBoost(curthread,&disabled);
440              ok(rc!=0 && disabled==1,
441                 "rc=%d error=%ld disabled=%d",rc,GetLastError(),disabled);
442
443              ok(pSetThreadPriorityBoost(curthread,0)!=0,
444                 "error=%ld",GetLastError());
445              rc=pGetThreadPriorityBoost(curthread,&disabled);
446              ok(rc!=0 && disabled==0,
447                 "rc=%d error=%ld disabled=%d",rc,GetLastError(),disabled);
448          }
449      }
450    }
451 }
452
453 /* check the GetThreadTimes function */
454 VOID test_GetThreadTimes()
455 {
456      HANDLE thread,access_thread=NULL;
457      FILETIME creationTime,exitTime,kernelTime,userTime;
458      DWORD threadId;
459      int error;
460
461      thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFunc2,NULL,
462                            CREATE_SUSPENDED,&threadId);
463
464      ok(thread!=NULL,"Create Thread failed.");
465 /* check that access control is obeyed */
466      if (pOpenThread) {
467        access_thread=pOpenThread(THREAD_ALL_ACCESS &
468                                    (~THREAD_QUERY_INFORMATION), 0,threadId);
469        ok(access_thread!=NULL,
470           "OpenThread returned an invalid handle");
471      }
472      ok(ResumeThread(thread)==1,"Resume thread returned an invalid value");
473      ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
474         "ResumeThread didn't work");
475      if(access_thread!=NULL) {
476        error=GetThreadTimes(access_thread,&creationTime,&exitTime,
477                             &kernelTime,&userTime);
478        ok(error==0, "GetThreadTimes did not obey access restrictions");
479        ok(CloseHandle(access_thread)!=0,"CloseHandle Failed");
480      }
481      creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
482      exitTime.dwLowDateTime=99;     exitTime.dwHighDateTime=99;
483      kernelTime.dwLowDateTime=99;   kernelTime.dwHighDateTime=99;
484      userTime.dwLowDateTime=99;     userTime.dwHighDateTime=99;
485 /* GetThreadTimes should set all of the parameters passed to it */
486      error=GetThreadTimes(thread,&creationTime,&exitTime,
487                           &kernelTime,&userTime);
488      if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
489        ok(error!=0,"GetThreadTimes failed");
490        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
491           "creationTime was invalid");
492        ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
493           "exitTime was invalid");
494        ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
495           "kernelTimewas invalid");
496        ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
497           "userTime was invalid");
498        ok(CloseHandle(thread)!=0,"CloseHandle failed");
499      }
500 }
501
502 /* Check the processor affinity functions */
503 /* NOTE: These functions should also be checked that they obey access control
504 */
505 VOID test_thread_processor()
506 {
507    HANDLE curthread,curproc;
508    DWORD processMask,systemMask;
509    SYSTEM_INFO sysInfo;
510    int error=0;
511
512    sysInfo.dwNumberOfProcessors=0;
513    GetSystemInfo(&sysInfo);
514    ok(sysInfo.dwNumberOfProcessors>0,
515       "GetSystemInfo failed to return a valid # of processors");
516 /* Use the current Thread/process for all tests */
517    curthread=GetCurrentThread();
518    ok(curthread!=NULL,"GetCurrentThread failed");
519    curproc=GetCurrentProcess();
520    ok(curproc!=NULL,"GetCurrentProcess failed");
521 /* Check the Affinity Mask functions */
522    ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
523       "GetProcessAffinityMask failed");
524    ok(SetThreadAffinityMask(curthread,processMask)==1,
525       "SetThreadAffinityMask failed");
526    ok(SetThreadAffinityMask(curthread,processMask+1)==0,
527       "SetThreadAffinityMask passed for an illegal processor");
528 /* NOTE: This only works on WinNT/2000/XP) */
529    if (pSetThreadIdealProcessor) {
530      todo_wine {
531        SetLastError(0);
532        error=pSetThreadIdealProcessor(curthread,0);
533        if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
534          ok(error!=-1, "SetThreadIdealProcessor failed");
535        }
536      }
537      if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
538        error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
539        ok(error==-1,
540           "SetThreadIdealProccesor succeeded with an illegal processor #");
541        todo_wine {
542          error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
543          ok(error==0, "SetThreadIdealProccesor returned an incorrect value");
544        }
545      }
546    }
547 }
548
549 START_TEST(thread)
550 {
551    HINSTANCE lib;
552 /* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
553    so that the compile passes
554 */
555    lib=LoadLibraryA("kernel32");
556    ok(lib!=NULL,"Couldn't load kernel32.dll");
557    pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
558    pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
559    pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
560    pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
561    test_CreateThread_basic();
562    test_CreateThread_suspended();
563    test_SuspendThread();
564    test_TerminateThread();
565    test_CreateThread_stack();
566    test_thread_priority();
567    test_GetThreadTimes();
568    test_thread_processor();
569 }