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