Only append .dll if no extension yet.
[wine] / scheduler / thread.c
1 /*
2  * Win32 threads
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <unistd.h>
9 #include "wine/winbase16.h"
10 #include "thread.h"
11 #include "process.h"
12 #include "task.h"
13 #include "module.h"
14 #include "user.h"
15 #include "winerror.h"
16 #include "heap.h"
17 #include "selectors.h"
18 #include "winnt.h"
19 #include "server.h"
20 #include "stackframe.h"
21 #include "debug.h"
22 #include "queue.h"
23 #include "hook.h"
24
25 #ifndef __i386__
26 THDB *pCurrentThread;
27 #endif
28
29 static void THREAD_Destroy( K32OBJ *obj );
30
31 const K32OBJ_OPS THREAD_Ops =
32 {
33     THREAD_Destroy      /* destroy */
34 };
35
36 /* Is threading code initialized? */
37 BOOL32 THREAD_InitDone = FALSE;
38
39
40 /***********************************************************************
41  *           THREAD_Current
42  *
43  * Return the current thread THDB pointer.
44  */
45 THDB *THREAD_Current(void)
46 {
47     if (!THREAD_InitDone) return NULL;
48     return (THDB *)((char *)NtCurrentTeb() - (int)&((THDB *)0)->teb);
49 }
50
51 /***********************************************************************
52  *           THREAD_IsWin16
53  */
54 BOOL32 THREAD_IsWin16( THDB *thdb )
55 {
56     if (!thdb || !thdb->process)
57         return TRUE;
58     else
59     {
60         TDB* pTask = (TDB*)GlobalLock16( thdb->process->task );
61         return !pTask || pTask->thdb == thdb;
62     }
63 }
64
65 /***********************************************************************
66  *           THREAD_IdToTHDB
67  *
68  * Convert a thread id to a THDB, making sure it is valid.
69  */
70 THDB *THREAD_IdToTHDB( DWORD id )
71 {
72     THDB *thdb;
73
74     if (!id) return THREAD_Current();
75     thdb = THREAD_ID_TO_THDB( id );
76     if (!K32OBJ_IsValid( &thdb->header, K32OBJ_THREAD ))
77     {
78         /* Allow task handles to be used; convert to main thread */
79         if ( IsTask( id ) )
80         {
81             TDB *pTask = (TDB *)GlobalLock16( id );
82             if (pTask) return pTask->thdb;
83         }
84         
85         SetLastError( ERROR_INVALID_PARAMETER );
86         return NULL;
87     }
88     return thdb;
89 }
90
91
92 /***********************************************************************
93  *           THREAD_AddQueue
94  *
95  * Add a thread to a queue.
96  */
97 void THREAD_AddQueue( THREAD_QUEUE *queue, THDB *thread )
98 {
99     THREAD_ENTRY *entry = HeapAlloc( SystemHeap, HEAP_NO_SERIALIZE,
100                                      sizeof(*entry) );
101     assert(entry);
102     SYSTEM_LOCK();
103     entry->thread = thread;
104     if (*queue)
105     {
106         entry->next = (*queue)->next;
107         (*queue)->next = entry;
108     }
109     else entry->next = entry;
110     *queue = entry;
111     SYSTEM_UNLOCK();
112 }
113
114 /***********************************************************************
115  *           THREAD_RemoveQueue
116  *
117  * Remove a thread from a queue.
118  */
119 void THREAD_RemoveQueue( THREAD_QUEUE *queue, THDB *thread )
120 {
121     THREAD_ENTRY *entry = *queue;
122     SYSTEM_LOCK();
123     if (entry->next == entry)  /* Only one element in the queue */
124     {
125         assert( entry->thread == thread );
126         *queue = NULL;
127     }
128     else
129     {
130         THREAD_ENTRY *next;
131         while (entry->next->thread != thread)
132         {
133             entry = entry->next;
134             assert( entry != *queue );  /* Have we come all the way around? */
135         }
136         if ((next = entry->next) == *queue) *queue = entry;
137         entry->next = entry->next->next;
138         entry = next;  /* This is the one we want to free */
139     }
140     HeapFree( SystemHeap, 0, entry );
141     SYSTEM_UNLOCK();
142 }
143
144
145 /***********************************************************************
146  *           THREAD_Create
147  */
148 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size, BOOL32 alloc_stack16,
149                      int *server_thandle, int *server_phandle,
150                      LPTHREAD_START_ROUTINE start_addr, LPVOID param )
151 {
152     DWORD old_prot;
153
154     THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
155     if (!thdb) return NULL;
156     thdb->header.type     = K32OBJ_THREAD;
157     thdb->header.refcount = 1;
158     thdb->process         = pdb;
159     thdb->teb.except      = (void *)-1;
160     thdb->teb.htask16     = 0; /* FIXME */
161     thdb->teb.self        = &thdb->teb;
162     thdb->teb.flags       = (pdb->flags & PDB32_WIN16_PROC)? 0 : TEBF_WIN32;
163     thdb->teb.tls_ptr     = thdb->tls_array;
164     thdb->teb.process     = pdb;
165     thdb->wait_list       = &thdb->wait_struct;
166     thdb->exit_code       = 0x103; /* STILL_ACTIVE */
167     thdb->entry_point     = start_addr;
168     thdb->entry_arg       = param;
169     thdb->socket          = -1;
170
171     /* Allocate the stack */
172
173     /* FIXME:
174      * If stacksize smaller than 1 MB, allocate 1MB 
175      * (one program wanted only 10 kB, which is recommendable, but some WINE
176      *  functions, noteably in the files subdir, push HUGE structures and
177      *  arrays on the stack. They probably shouldn't.)
178      * If stacksize larger than 16 MB, warn the user. (We could shrink the stack
179      * but this could give more or less unexplainable crashes.)
180      */
181     if (stack_size<1024*1024)
182         stack_size = 1024 * 1024;
183     if (stack_size >= 16*1024*1024)
184         WARN(thread,"Thread stack size is %ld MB.\n",stack_size/1024/1024);
185     thdb->stack_base = VirtualAlloc(NULL,
186                                     stack_size + (alloc_stack16 ? 0x10000 : 0),
187                                     MEM_COMMIT, PAGE_EXECUTE_READWRITE );
188     if (!thdb->stack_base) goto error;
189     /* Set a guard page at the bottom of the stack */
190     VirtualProtect( thdb->stack_base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD,
191                     &old_prot );
192     thdb->teb.stack_top   = (char *)thdb->stack_base + stack_size;
193     thdb->teb.stack_low   = thdb->stack_base;
194     thdb->exit_stack      = thdb->teb.stack_top;
195
196     /* Allocate the TEB selector (%fs register) */
197
198     thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
199                                          TRUE, FALSE );
200     if (!thdb->teb_sel) goto error;
201
202     /* Allocate the 16-bit stack selector */
203
204     if (alloc_stack16)
205     {
206         thdb->teb.stack_sel = SELECTOR_AllocBlock( thdb->teb.stack_top,
207                                                    0x10000, SEGMENT_DATA,
208                                                    FALSE, FALSE );
209         if (!thdb->teb.stack_sel) goto error;
210         thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( thdb->teb.stack_sel, 
211                                                  0x10000 - sizeof(STACK16FRAME) );
212     }
213
214     /* Create the thread socket */
215
216     if (CLIENT_NewThread( thdb, server_thandle, server_phandle )) goto error;
217
218     /* Add thread to process's list of threads */
219
220     THREAD_AddQueue( &pdb->thread_list, thdb );
221
222     /* Create the thread event */
223
224     if (!(thdb->event = CreateEvent32A( NULL, FALSE, FALSE, NULL ))) goto error;
225     thdb->event = ConvertToGlobalHandle( thdb->event );
226
227     PE_InitTls( thdb );
228     return thdb;
229
230 error:
231     if (thdb->socket != -1) close( thdb->socket );
232     if (thdb->event) CloseHandle( thdb->event );
233     if (thdb->teb.stack_sel) SELECTOR_FreeBlock( thdb->teb.stack_sel, 1 );
234     if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
235     if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
236     HeapFree( SystemHeap, 0, thdb );
237     return NULL;
238 }
239
240
241 /***********************************************************************
242  *           THREAD_Destroy
243  */
244 static void THREAD_Destroy( K32OBJ *ptr )
245 {
246     THDB *thdb = (THDB *)ptr;
247
248     assert( ptr->type == K32OBJ_THREAD );
249     ptr->type = K32OBJ_UNKNOWN;
250
251     /* Free the associated memory */
252
253 #ifdef __i386__
254     {
255         /* Check if we are deleting the current thread */
256         WORD fs;
257         GET_FS( fs );
258         if (fs == thdb->teb_sel)
259         {
260             GET_DS( fs );
261             SET_FS( fs );
262         }
263     }
264 #endif
265     CloseHandle( thdb->event );
266     close( thdb->socket );
267     SELECTOR_FreeBlock( thdb->teb_sel, 1 );
268     if (thdb->teb.stack_sel) SELECTOR_FreeBlock( thdb->teb.stack_sel, 1 );
269     HeapFree( SystemHeap, 0, thdb );
270
271 }
272
273
274 /***********************************************************************
275  *           THREAD_Start
276  *
277  * Start execution of a newly created thread. Does not return.
278  */
279 void THREAD_Start( THDB *thdb )
280 {
281     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
282     assert( THREAD_Current() == thdb );
283     CLIENT_InitThread();
284     MODULE_InitializeDLLs( thdb->process, 0, DLL_THREAD_ATTACH, NULL );
285     ExitThread( func( thdb->entry_arg ) );
286 }
287
288
289 /***********************************************************************
290  *           CreateThread   (KERNEL32.63)
291  */
292 HANDLE32 WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
293                               LPTHREAD_START_ROUTINE start, LPVOID param,
294                               DWORD flags, LPDWORD id )
295 {
296     int server_handle = -1;
297     HANDLE32 handle = INVALID_HANDLE_VALUE32;
298     BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
299
300     THDB *thread = THREAD_Create( PROCESS_Current(), stack,
301                                   TRUE, &server_handle, NULL, start, param );
302     if (!thread) return INVALID_HANDLE_VALUE32;
303     handle = HANDLE_Alloc( PROCESS_Current(), &thread->header,
304                            THREAD_ALL_ACCESS, inherit, server_handle );
305     if (handle == INVALID_HANDLE_VALUE32) goto error;
306     if (SYSDEPS_SpawnThread( thread ) == -1) goto error;
307     if (id) *id = THDB_TO_THREAD_ID( thread );
308     return handle;
309
310 error:
311     if (handle != INVALID_HANDLE_VALUE32) CloseHandle( handle );
312     K32OBJ_DecCount( &thread->header );
313     return INVALID_HANDLE_VALUE32;
314 }
315
316
317 /***********************************************************************
318  * ExitThread [KERNEL32.215]  Ends a thread
319  *
320  * RETURNS
321  *    None
322  */
323 void WINAPI ExitThread(
324     DWORD code) /* [in] Exit code for this thread */
325 {
326     THDB *thdb = THREAD_Current();
327     LONG count;
328
329     /* Remove thread from process's list */
330     THREAD_RemoveQueue( &thdb->process->thread_list, thdb );
331
332     MODULE_InitializeDLLs( thdb->process, 0, DLL_THREAD_DETACH, NULL );
333
334     SYSTEM_LOCK();
335     thdb->exit_code = code;
336
337     /* cleanup the message queue, if there's one */
338     if (thdb->teb.queue)
339         USER_QueueCleanup( thdb->teb.queue );
340         
341     /* FIXME: should free the stack somehow */
342 #if 0
343     /* FIXME: We cannot do this; once the current thread is destroyed,
344        synchronization primitives do not work properly. */
345     K32OBJ_DecCount( &thdb->header );
346 #endif
347     /* Completely unlock the system lock just in case */
348     count = SYSTEM_LOCK_COUNT();
349     while (count--) SYSTEM_UNLOCK();
350     SYSDEPS_ExitThread();
351 }
352
353
354 /***********************************************************************
355  * GetCurrentThread [KERNEL32.200]  Gets pseudohandle for current thread
356  *
357  * RETURNS
358  *    Pseudohandle for the current thread
359  */
360 HANDLE32 WINAPI GetCurrentThread(void)
361 {
362     return CURRENT_THREAD_PSEUDOHANDLE;
363 }
364
365
366 /***********************************************************************
367  * GetCurrentThreadId [KERNEL32.201]  Returns thread identifier.
368  *
369  * RETURNS
370  *    Thread identifier of calling thread
371  */
372 DWORD WINAPI GetCurrentThreadId(void)
373 {
374     return THDB_TO_THREAD_ID( THREAD_Current() );
375 }
376
377
378 /**********************************************************************
379  * GetLastError [KERNEL.148] [KERNEL32.227]  Returns last-error code.
380  *
381  * RETURNS
382  *     Calling thread's last error code value.
383  */
384 DWORD WINAPI GetLastError(void)
385 {
386     THDB *thread = THREAD_Current();
387     DWORD ret = thread->last_error;
388     TRACE(thread,"0x%lx\n",ret);
389     return ret;
390 }
391
392
393 /**********************************************************************
394  * SetLastError [KERNEL.147] [KERNEL32.497]  Sets the last-error code.
395  *
396  * RETURNS
397  *    None.
398  */
399 void WINAPI SetLastError(
400     DWORD error) /* [in] Per-thread error code */
401 {
402     THDB *thread = THREAD_Current();
403     /* This one must work before we have a thread (FIXME) */
404
405     TRACE(thread,"%p error=0x%lx\n",thread,error);
406
407     if (thread)
408       thread->last_error = error;
409 }
410
411
412 /**********************************************************************
413  * SetLastErrorEx [USER32.485]  Sets the last-error code.
414  *
415  * RETURNS
416  *    None.
417  */
418 void WINAPI SetLastErrorEx(
419     DWORD error, /* [in] Per-thread error code */
420     DWORD type)  /* [in] Error type */
421 {
422     TRACE(thread, "(0x%08lx, 0x%08lx)\n", error,type);
423     switch(type) {
424         case 0:
425             break;
426         case SLE_ERROR:
427         case SLE_MINORERROR:
428         case SLE_WARNING:
429             /* Fall through for now */
430         default:
431             FIXME(thread, "(error=%08lx, type=%08lx): Unhandled type\n", error,type);
432             break;
433     }
434     SetLastError( error );
435 }
436
437
438 /**********************************************************************
439  *           THREAD_TlsAlloc
440  */
441 DWORD THREAD_TlsAlloc(THDB *thread)
442 {
443     DWORD i, mask, ret = 0;
444     DWORD *bits = thread->process->tls_bits;
445     EnterCriticalSection( &thread->process->crit_section );
446     if (*bits == 0xffffffff)
447     {
448         bits++;
449         ret = 32;
450         if (*bits == 0xffffffff)
451         {
452             LeaveCriticalSection( &thread->process->crit_section );
453             SetLastError( ERROR_NO_MORE_ITEMS );
454             return 0xffffffff;
455         }
456     }
457     for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
458     *bits |= mask;
459     LeaveCriticalSection( &thread->process->crit_section );
460     return ret + i;
461 }
462
463
464 /**********************************************************************
465  * TlsAlloc [KERNEL32.530]  Allocates a TLS index.
466  *
467  * Allocates a thread local storage index
468  *
469  * RETURNS
470  *    Success: TLS Index
471  *    Failure: 0xFFFFFFFF
472  */
473 DWORD WINAPI TlsAlloc(void)
474 {
475     return THREAD_TlsAlloc(THREAD_Current());
476 }
477
478
479 /**********************************************************************
480  * TlsFree [KERNEL32.531]  Releases a TLS index.
481  *
482  * Releases a thread local storage index, making it available for reuse
483  * 
484  * RETURNS
485  *    Success: TRUE
486  *    Failure: FALSE
487  */
488 BOOL32 WINAPI TlsFree(
489     DWORD index) /* [in] TLS Index to free */
490 {
491     DWORD mask;
492     THDB *thread = THREAD_Current();
493     DWORD *bits = thread->process->tls_bits;
494     if (index >= 64)
495     {
496         SetLastError( ERROR_INVALID_PARAMETER );
497         return FALSE;
498     }
499     EnterCriticalSection( &thread->process->crit_section );
500     if (index >= 32) bits++;
501     mask = (1 << (index & 31));
502     if (!(*bits & mask))  /* already free? */
503     {
504         LeaveCriticalSection( &thread->process->crit_section );
505         SetLastError( ERROR_INVALID_PARAMETER );
506         return FALSE;
507     }
508     *bits &= ~mask;
509     thread->tls_array[index] = 0;
510     /* FIXME: should zero all other thread values */
511     LeaveCriticalSection( &thread->process->crit_section );
512     return TRUE;
513 }
514
515
516 /**********************************************************************
517  * TlsGetValue [KERNEL32.532]  Gets value in a thread's TLS slot
518  *
519  * RETURNS
520  *    Success: Value stored in calling thread's TLS slot for index
521  *    Failure: 0 and GetLastError returns NO_ERROR
522  */
523 LPVOID WINAPI TlsGetValue(
524     DWORD index) /* [in] TLS index to retrieve value for */
525 {
526     THDB *thread = THREAD_Current();
527     if (index >= 64)
528     {
529         SetLastError( ERROR_INVALID_PARAMETER );
530         return NULL;
531     }
532     SetLastError( ERROR_SUCCESS );
533     return thread->tls_array[index];
534 }
535
536
537 /**********************************************************************
538  * TlsSetValue [KERNEL32.533]  Stores a value in the thread's TLS slot.
539  *
540  * RETURNS
541  *    Success: TRUE
542  *    Failure: FALSE
543  */
544 BOOL32 WINAPI TlsSetValue(
545     DWORD index,  /* [in] TLS index to set value for */
546     LPVOID value) /* [in] Value to be stored */
547 {
548     THDB *thread = THREAD_Current();
549     if (index >= 64)
550     {
551         SetLastError( ERROR_INVALID_PARAMETER );
552         return FALSE;
553     }
554     thread->tls_array[index] = value;
555     return TRUE;
556 }
557
558
559 /***********************************************************************
560  * SetThreadContext [KERNEL32.670]  Sets context of thread.
561  *
562  * RETURNS
563  *    Success: TRUE
564  *    Failure: FALSE
565  */
566 BOOL32 WINAPI SetThreadContext(
567     HANDLE32 handle,  /* [in]  Handle to thread with context */
568     CONTEXT *context) /* [out] Address of context structure */
569 {
570     FIXME( thread, "not implemented\n" );
571     return TRUE;
572 }
573
574 /***********************************************************************
575  * GetThreadContext [KERNEL32.294]  Retrieves context of thread.
576  *
577  * RETURNS
578  *    Success: TRUE
579  *    Failure: FALSE
580  */
581 BOOL32 WINAPI GetThreadContext(
582     HANDLE32 handle,  /* [in]  Handle to thread with context */
583     CONTEXT *context) /* [out] Address of context structure */
584 {
585     WORD cs, ds;
586
587     FIXME( thread, "returning dummy info\n" );
588
589     /* make up some plausible values for segment registers */
590     GET_CS(cs);
591     GET_DS(ds);
592     context->SegCs   = cs;
593     context->SegDs   = ds;
594     context->SegEs   = ds;
595     context->SegGs   = ds;
596     context->SegSs   = ds;
597     context->SegFs   = ds;
598     return TRUE;
599 }
600
601
602 /**********************************************************************
603  * GetThreadPriority [KERNEL32.296]  Returns priority for thread.
604  *
605  * RETURNS
606  *    Success: Thread's priority level.
607  *    Failure: THREAD_PRIORITY_ERROR_RETURN
608  */
609 INT32 WINAPI GetThreadPriority(
610     HANDLE32 hthread) /* [in] Handle to thread */
611 {
612     struct get_thread_info_request req;
613     struct get_thread_info_reply reply;
614     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hthread,
615                                          K32OBJ_THREAD, THREAD_QUERY_INFORMATION );
616     CLIENT_SendRequest( REQ_GET_THREAD_INFO, -1, 1, &req, sizeof(req) );
617     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL ))
618         return THREAD_PRIORITY_ERROR_RETURN;
619     return reply.priority;
620 }
621
622
623 /**********************************************************************
624  * SetThreadPriority [KERNEL32.514]  Sets priority for thread.
625  *
626  * RETURNS
627  *    Success: TRUE
628  *    Failure: FALSE
629  */
630 BOOL32 WINAPI SetThreadPriority(
631     HANDLE32 hthread, /* [in] Handle to thread */
632     INT32 priority)   /* [in] Thread priority level */
633 {
634     struct set_thread_info_request req;
635     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hthread,
636                                          K32OBJ_THREAD, THREAD_SET_INFORMATION );
637     if (req.handle == -1) return FALSE;
638     req.priority = priority;
639     req.mask     = SET_THREAD_INFO_PRIORITY;
640     CLIENT_SendRequest( REQ_SET_THREAD_INFO, -1, 1, &req, sizeof(req) );
641     return !CLIENT_WaitReply( NULL, NULL, 0 );
642 }
643
644
645 /**********************************************************************
646  *           SetThreadAffinityMask   (KERNEL32.669)
647  */
648 DWORD WINAPI SetThreadAffinityMask( HANDLE32 hThread, DWORD dwThreadAffinityMask )
649 {
650     struct set_thread_info_request req;
651     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hThread,
652                                          K32OBJ_THREAD, THREAD_SET_INFORMATION );
653     if (req.handle == -1) return FALSE;
654     req.affinity = dwThreadAffinityMask;
655     req.mask     = SET_THREAD_INFO_AFFINITY;
656     CLIENT_SendRequest( REQ_SET_THREAD_INFO, -1, 1, &req, sizeof(req) );
657     if (CLIENT_WaitReply( NULL, NULL, 0 )) return 0;
658     return 1;  /* FIXME: should return previous value */
659 }
660
661
662 /**********************************************************************
663  * TerminateThread [KERNEL32.685]  Terminates a thread
664  *
665  * RETURNS
666  *    Success: TRUE
667  *    Failure: FALSE
668  */
669 BOOL32 WINAPI TerminateThread(
670     HANDLE32 handle, /* [in] Handle to thread */
671     DWORD exitcode)  /* [in] Exit code for thread */
672 {
673     struct terminate_thread_request req;
674
675     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
676                                          K32OBJ_THREAD, THREAD_TERMINATE );
677     req.exit_code = exitcode;
678     CLIENT_SendRequest( REQ_TERMINATE_THREAD, -1, 1, &req, sizeof(req) );
679     return !CLIENT_WaitReply( NULL, NULL, 0 );
680 }
681
682
683 /**********************************************************************
684  * GetExitCodeThread [KERNEL32.???]  Gets termination status of thread.
685  * 
686  * RETURNS
687  *    Success: TRUE
688  *    Failure: FALSE
689  */
690 BOOL32 WINAPI GetExitCodeThread(
691     HANDLE32 hthread, /* [in]  Handle to thread */
692     LPDWORD exitcode) /* [out] Address to receive termination status */
693 {
694     struct get_thread_info_request req;
695     struct get_thread_info_reply reply;
696     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hthread,
697                                          K32OBJ_THREAD, THREAD_QUERY_INFORMATION );
698     CLIENT_SendRequest( REQ_GET_THREAD_INFO, -1, 1, &req, sizeof(req) );
699     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return FALSE;
700     if (exitcode) *exitcode = reply.exit_code;
701     return TRUE;
702 }
703
704
705 /**********************************************************************
706  * ResumeThread [KERNEL32.587]  Resumes a thread.
707  *
708  * Decrements a thread's suspend count.  When count is zero, the
709  * execution of the thread is resumed.
710  *
711  * RETURNS
712  *    Success: Previous suspend count
713  *    Failure: 0xFFFFFFFF
714  *    Already running: 0
715  */
716 DWORD WINAPI ResumeThread(
717     HANDLE32 hthread) /* [in] Identifies thread to restart */
718 {
719     struct resume_thread_request req;
720     struct resume_thread_reply reply;
721     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hthread,
722                                          K32OBJ_THREAD, THREAD_SUSPEND_RESUME );
723     CLIENT_SendRequest( REQ_RESUME_THREAD, -1, 1, &req, sizeof(req) );
724     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0xffffffff;
725     return reply.count;
726 }
727
728
729 /**********************************************************************
730  * SuspendThread [KERNEL32.681]  Suspends a thread.
731  *
732  * RETURNS
733  *    Success: Previous suspend count
734  *    Failure: 0xFFFFFFFF
735  */
736 DWORD WINAPI SuspendThread(
737     HANDLE32 hthread) /* [in] Handle to the thread */
738 {
739     struct suspend_thread_request req;
740     struct suspend_thread_reply reply;
741     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hthread,
742                                          K32OBJ_THREAD, THREAD_SUSPEND_RESUME );
743     CLIENT_SendRequest( REQ_SUSPEND_THREAD, -1, 1, &req, sizeof(req) );
744     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0xffffffff;
745     return reply.count;
746 }
747
748
749 /***********************************************************************
750  *              QueueUserAPC  (KERNEL32.566)
751  */
752 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE32 hthread, ULONG_PTR data )
753 {
754     struct queue_apc_request req;
755     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hthread,
756                                          K32OBJ_THREAD, THREAD_SET_CONTEXT );
757     req.func  = func;
758     req.param = (void *)data;
759     CLIENT_SendRequest( REQ_QUEUE_APC, -1, 1, &req, sizeof(req) );
760     return !CLIENT_WaitReply( NULL, NULL, 0 );
761 }
762
763
764 /**********************************************************************
765  * GetThreadTimes [KERNEL32.???]  Obtains timing information.
766  *
767  * NOTES
768  *    What are the fields where these values are stored?
769  *
770  * RETURNS
771  *    Success: TRUE
772  *    Failure: FALSE
773  */
774 BOOL32 WINAPI GetThreadTimes( 
775     HANDLE32 thread,         /* [in]  Specifies the thread of interest */
776     LPFILETIME creationtime, /* [out] When the thread was created */
777     LPFILETIME exittime,     /* [out] When the thread was destroyed */
778     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
779     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
780 {
781     FIXME(thread,"(0x%08x): stub\n",thread);
782     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
783     return FALSE;
784 }
785
786
787 /**********************************************************************
788  * AttachThreadInput [KERNEL32.8]  Attaches input of 1 thread to other
789  *
790  * Attaches the input processing mechanism of one thread to that of
791  * another thread.
792  *
793  * RETURNS
794  *    Success: TRUE
795  *    Failure: FALSE
796  *
797  * TODO:
798  *    1. Reset the Key State (currenly per thread key state is not maintained)
799  */
800 BOOL32 WINAPI AttachThreadInput( 
801     DWORD idAttach,   /* [in] Thread to attach */
802     DWORD idAttachTo, /* [in] Thread to attach to */
803     BOOL32 fAttach)   /* [in] Attach or detach */
804 {
805     MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
806     BOOL16 bRet = 0;
807
808     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
809
810     /* A thread cannot attach to itself */
811     if ( idAttach == idAttachTo )
812         goto CLEANUP;
813
814     /* According to the docs this method should fail if a
815      * "Journal record" hook is installed. (attaches all input queues together)
816      */
817     if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
818         goto CLEANUP;
819         
820     /* Retrieve message queues corresponding to the thread id's */
821     pTgtMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue( idAttach ) );
822     pSrcMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue( idAttachTo ) );
823
824     /* Ensure we have message queues and that Src and Tgt threads
825      * are not system threads.
826      */
827     if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
828         goto CLEANUP;
829
830     if (fAttach)   /* Attach threads */
831     {
832         /* Only attach if currently detached  */
833         if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
834         {
835             /* First release the target threads perQData */
836             PERQDATA_Release( pTgtMsgQ->pQData );
837         
838             /* Share a reference to the source threads perQDATA */
839             PERQDATA_Addref( pSrcMsgQ->pQData );
840             pTgtMsgQ->pQData = pSrcMsgQ->pQData;
841         }
842     }
843     else    /* Detach threads */
844     {
845         /* Only detach if currently attached */
846         if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
847         {
848             /* First release the target threads perQData */
849             PERQDATA_Release( pTgtMsgQ->pQData );
850         
851             /* Give the target thread its own private perQDATA once more */
852             pTgtMsgQ->pQData = PERQDATA_CreateInstance();
853         }
854     }
855
856     /* TODO: Reset the Key State */
857
858     bRet = 1;      // Success
859     
860 CLEANUP:
861
862     /* Unlock the queues before returning */
863     if ( pSrcMsgQ )
864         QUEUE_Unlock( pSrcMsgQ );
865     if ( pTgtMsgQ )
866         QUEUE_Unlock( pTgtMsgQ );
867     
868     return bRet;
869 }
870
871 /**********************************************************************
872  * VWin32_BoostThreadGroup [KERNEL.535]
873  */
874 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT32 boost )
875 {
876     FIXME(thread, "(0x%08lx,%d): stub\n", threadId, boost);
877 }
878
879 /**********************************************************************
880  * VWin32_BoostThreadStatic [KERNEL.536]
881  */
882 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT32 boost )
883 {
884     FIXME(thread, "(0x%08lx,%d): stub\n", threadId, boost);
885 }
886
887 /**********************************************************************
888  * SetThreadLocale [KERNEL32.671]  Sets the calling threads current locale.
889  *
890  * RETURNS
891  *    Success: TRUE
892  *    Failure: FALSE
893  *
894  * NOTES
895  *  Implemented in NT only (3.1 and above according to MS
896  */
897 BOOL32 WINAPI SetThreadLocale(
898     LCID lcid)     /* [in] Locale identifier */
899 {
900     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
901     return FALSE;
902 }