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