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