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