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