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