Added a first-cut version of MapVirtualKeyExW() that has the same
[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 "global.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 "winnls.h"
32
33 DEFAULT_DEBUG_CHANNEL(thread);
34
35 /* TEB of the initial thread */
36 static TEB initial_teb;
37
38 /***********************************************************************
39  *           THREAD_IsWin16
40  */
41 BOOL THREAD_IsWin16( TEB *teb )
42 {
43     return !teb || !(teb->tibflags & TEBF_WIN32);
44 }
45
46 /***********************************************************************
47  *           THREAD_IdToTEB
48  *
49  * Convert a thread id to a TEB, making sure it is valid.
50  */
51 TEB *THREAD_IdToTEB( DWORD id )
52 {
53     TEB *ret = NULL;
54
55     if (!id || id == GetCurrentThreadId()) return NtCurrentTeb();
56
57     SERVER_START_REQ
58     {
59         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
60         req->handle = -1;
61         req->tid_in = (void *)id;
62         if (!server_call_noerr( REQ_GET_THREAD_INFO )) ret = req->teb;
63     }
64     SERVER_END_REQ;
65
66     if (!ret)
67     {
68         /* Allow task handles to be used; convert to main thread */
69         if ( IsTask16( id ) )
70         {
71             TDB *pTask = (TDB *)GlobalLock16( id );
72             if (pTask) return pTask->teb;
73         }
74         SetLastError( ERROR_INVALID_PARAMETER );
75     }
76     return ret;
77 }
78
79
80 /***********************************************************************
81  *           THREAD_InitTEB
82  *
83  * Initialization of a newly created TEB.
84  */
85 static BOOL THREAD_InitTEB( TEB *teb )
86 {
87     teb->except    = (void *)~0UL;
88     teb->self      = teb;
89     teb->tibflags  = TEBF_WIN32;
90     teb->tls_ptr   = teb->tls_array;
91     teb->exit_code = STILL_ACTIVE;
92     teb->socket    = -1;
93     teb->stack_top = (void *)~0UL;
94     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
95     teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
96     teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
97     return (teb->teb_sel != 0);
98 }
99
100
101 /***********************************************************************
102  *           THREAD_FreeTEB
103  *
104  * Free data structures associated with a thread.
105  * Must be called from the context of another thread.
106  */
107 static void CALLBACK THREAD_FreeTEB( TEB *teb )
108 {
109     TRACE("(%p) called\n", teb );
110     if (teb->cleanup) SERVICE_Delete( teb->cleanup );
111
112     /* Free the associated memory */
113
114     if (teb->socket != -1) close( teb->socket );
115     if (teb->stack_sel) FreeSelector16( teb->stack_sel );
116     FreeSelector16( teb->teb_sel );
117     if (teb->buffer) munmap( (void *)teb->buffer,
118                              (char *)(teb->buffer_info+1) - (char *)teb->buffer );
119     if (teb->debug_info) HeapFree( GetProcessHeap(), 0, teb->debug_info );
120     VirtualFree( teb->stack_base, 0, MEM_RELEASE );
121 }
122
123
124 /***********************************************************************
125  *           THREAD_InitStack
126  *
127  * Allocate the stack of a thread.
128  */
129 TEB *THREAD_InitStack( TEB *teb, DWORD stack_size, BOOL alloc_stack16 )
130 {
131     DWORD old_prot, total_size;
132     DWORD page_size = VIRTUAL_GetPageSize();
133     void *base;
134
135     /* Allocate the stack */
136
137     if (stack_size >= 16*1024*1024)
138         WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024);
139
140     /* if size is smaller than default, get stack size from parent */
141     if (stack_size < 1024 * 1024)
142     {
143         if (teb)
144             stack_size = 1024 * 1024;  /* no parent */
145         else
146             stack_size = ((char *)NtCurrentTeb()->stack_top - (char *)NtCurrentTeb()->stack_base
147                           - SIGNAL_STACK_SIZE - 3 * page_size);
148     }
149
150     /* FIXME: some Wine functions use a lot of stack, so we add 64Kb here */
151     stack_size += 64 * 1024;
152
153     /* Memory layout in allocated block:
154      *
155      *   size                 contents
156      * 1 page              NOACCESS guard page
157      * SIGNAL_STACK_SIZE   signal stack
158      * 1 page              NOACCESS guard page
159      * 1 page              PAGE_GUARD guard page
160      * stack_size          normal stack
161      * 64Kb                16-bit stack (optional)
162      * 1 page              TEB (except for initial thread)
163      */
164
165     stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
166     total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
167     if (alloc_stack16) total_size += 0x10000;
168     if (!teb) total_size += page_size;
169
170     if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
171         return NULL;
172
173     if (!teb)
174     {
175         teb = (TEB *)((char *)base + total_size - page_size);
176         if (!THREAD_InitTEB( teb ))
177         {
178             VirtualFree( base, 0, MEM_RELEASE );
179             return NULL;
180         }
181     }
182
183     teb->stack_low    = base;
184     teb->stack_base   = base;
185     teb->signal_stack = (char *)base + page_size;
186     teb->stack_top    = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size;
187
188     /* Setup guard pages */
189
190     VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot );
191     VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot );
192     VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1,
193                     PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
194
195     /* Allocate the 16-bit stack selector */
196
197     if (alloc_stack16)
198     {
199         teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, WINE_LDT_FLAGS_DATA );
200         if (!teb->stack_sel) goto error;
201         teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( teb->stack_sel, 
202                                                 0x10000 - sizeof(STACK16FRAME) );
203     }
204     return teb;
205
206 error:
207     THREAD_FreeTEB( teb );
208     return NULL;
209 }
210
211
212 /***********************************************************************
213  *           THREAD_Init
214  *
215  * Setup the initial thread.
216  *
217  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
218  */
219 void THREAD_Init(void)
220 {
221     if (!initial_teb.self)  /* do it only once */
222     {
223         THREAD_InitTEB( &initial_teb );
224         assert( initial_teb.teb_sel );
225         initial_teb.process = &current_process;
226         SYSDEPS_SetCurThread( &initial_teb );
227     }
228 }
229
230 DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
231
232 /***********************************************************************
233  *           THREAD_Create
234  *
235  */
236 TEB *THREAD_Create( int fd, DWORD stack_size, BOOL alloc_stack16 )
237 {
238     TEB *teb;
239
240     if ((teb = THREAD_InitStack( NULL, stack_size, alloc_stack16 )))
241     {
242         teb->tibflags = (current_process.flags & PDB32_WIN16_PROC) ? 0 : TEBF_WIN32;
243         teb->process  = &current_process;
244         teb->socket   = fd;
245         fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
246         TRACE("(%p) succeeded\n", teb);
247     }
248     return teb;
249 }
250
251
252 /***********************************************************************
253  *           THREAD_Start
254  *
255  * Start execution of a newly created thread. Does not return.
256  */
257 static void THREAD_Start(void)
258 {
259     HANDLE cleanup_object;
260     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)NtCurrentTeb()->entry_point;
261
262     /* install cleanup handler */
263     if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
264                          GetCurrentProcess(), &cleanup_object, 
265                          0, FALSE, DUPLICATE_SAME_ACCESS ))
266         NtCurrentTeb()->cleanup = SERVICE_AddObject( cleanup_object, (PAPCFUNC)THREAD_FreeTEB,
267                                                      (ULONG_PTR)NtCurrentTeb() );
268
269     PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
270     PE_InitTls();
271     MODULE_DllThreadAttach( NULL );
272     ExitThread( func( NtCurrentTeb()->entry_arg ) );
273 }
274
275
276 /***********************************************************************
277  *           CreateThread   (KERNEL32.63)
278  */
279 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
280                             LPTHREAD_START_ROUTINE start, LPVOID param,
281                             DWORD flags, LPDWORD id )
282 {
283     int socket, handle = -1;
284     TEB *teb;
285     void *tid = 0;
286
287     SERVER_START_REQ
288     {
289         struct new_thread_request *req = server_alloc_req( sizeof(*req), 0 );
290
291         req->suspend = ((flags & CREATE_SUSPENDED) != 0);
292         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
293         if (!server_call_fd( REQ_NEW_THREAD, -1, &socket ))
294         {
295             handle = req->handle;
296             tid = req->tid;
297         }
298     }
299     SERVER_END_REQ;
300     if (handle == -1) return 0;
301
302     if (!(teb = THREAD_Create( socket, stack, TRUE )))
303     {
304         close( socket );
305         return 0;
306     }
307     teb->tibflags   |= TEBF_WIN32;
308     teb->entry_point = start;
309     teb->entry_arg   = param;
310     teb->startup     = THREAD_Start;
311     teb->htask16     = GetCurrentTask();
312     if (id) *id = (DWORD)tid;
313     if (SYSDEPS_SpawnThread( teb ) == -1)
314     {
315         CloseHandle( handle );
316         THREAD_FreeTEB( teb );
317         return 0;
318     }
319     return handle;
320 }
321
322 /***********************************************************************
323  *           CreateThread16   (KERNEL.441)
324  */
325 static DWORD CALLBACK THREAD_StartThread16( LPVOID threadArgs )
326 {
327     FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
328     DWORD     param = ((DWORD *)threadArgs)[1];
329     HeapFree( GetProcessHeap(), 0, threadArgs );
330
331     ((LPDWORD)CURRENT_STACK16)[-1] = param;
332     return wine_call_to_16_long( start, sizeof(DWORD) );
333 }
334 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
335                               FARPROC16 start, SEGPTR param,
336                               DWORD flags, LPDWORD id )
337 {
338     DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
339     if (!threadArgs) return INVALID_HANDLE_VALUE;
340     threadArgs[0] = (DWORD)start;
341     threadArgs[1] = (DWORD)param;
342
343     return CreateThread( sa, stack, THREAD_StartThread16, threadArgs, flags, id );
344 }
345
346
347 /***********************************************************************
348  * ExitThread [KERNEL32.215]  Ends a thread
349  *
350  * RETURNS
351  *    None
352  */
353 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
354 {
355     BOOL last;
356     SERVER_START_REQ
357     {
358         struct terminate_thread_request *req = server_alloc_req( sizeof(*req), 0 );
359
360         /* send the exit code to the server */
361         req->handle    = GetCurrentThread();
362         req->exit_code = code;
363         server_call( REQ_TERMINATE_THREAD );
364         last = req->last;
365     }
366     SERVER_END_REQ;
367
368     if (last)
369     {
370         MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
371         exit( code );
372     }
373     else
374     {
375         MODULE_DllThreadDetach( NULL );
376         if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_ExitTask();
377         SYSDEPS_ExitThread( code );
378     }
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     DWORD i, mask, ret = 0;
394     DWORD *bits = current_process.tls_bits;
395     EnterCriticalSection( &current_process.crit_section );
396     if (*bits == 0xffffffff)
397     {
398         bits++;
399         ret = 32;
400         if (*bits == 0xffffffff)
401         {
402             LeaveCriticalSection( &current_process.crit_section );
403             SetLastError( ERROR_NO_MORE_ITEMS );
404             return 0xffffffff;
405         }
406     }
407     for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
408     *bits |= mask;
409     LeaveCriticalSection( &current_process.crit_section );
410     return ret + i;
411 }
412
413
414 /**********************************************************************
415  * TlsFree [KERNEL32.531]  Releases a TLS index.
416  *
417  * Releases a thread local storage index, making it available for reuse
418  * 
419  * RETURNS
420  *    Success: TRUE
421  *    Failure: FALSE
422  */
423 BOOL WINAPI TlsFree(
424     DWORD index) /* [in] TLS Index to free */
425 {
426     DWORD mask;
427     DWORD *bits = current_process.tls_bits;
428     if (index >= 64)
429     {
430         SetLastError( ERROR_INVALID_PARAMETER );
431         return FALSE;
432     }
433     EnterCriticalSection( &current_process.crit_section );
434     if (index >= 32) bits++;
435     mask = (1 << (index & 31));
436     if (!(*bits & mask))  /* already free? */
437     {
438         LeaveCriticalSection( &current_process.crit_section );
439         SetLastError( ERROR_INVALID_PARAMETER );
440         return FALSE;
441     }
442     *bits &= ~mask;
443     NtCurrentTeb()->tls_array[index] = 0;
444     /* FIXME: should zero all other thread values */
445     LeaveCriticalSection( &current_process.crit_section );
446     return TRUE;
447 }
448
449
450 /**********************************************************************
451  * TlsGetValue [KERNEL32.532]  Gets value in a thread's TLS slot
452  *
453  * RETURNS
454  *    Success: Value stored in calling thread's TLS slot for index
455  *    Failure: 0 and GetLastError returns NO_ERROR
456  */
457 LPVOID WINAPI TlsGetValue(
458     DWORD index) /* [in] TLS index to retrieve value for */
459 {
460     if (index >= 64)
461     {
462         SetLastError( ERROR_INVALID_PARAMETER );
463         return NULL;
464     }
465     SetLastError( ERROR_SUCCESS );
466     return NtCurrentTeb()->tls_array[index];
467 }
468
469
470 /**********************************************************************
471  * TlsSetValue [KERNEL32.533]  Stores a value in the thread's TLS slot.
472  *
473  * RETURNS
474  *    Success: TRUE
475  *    Failure: FALSE
476  */
477 BOOL WINAPI TlsSetValue(
478     DWORD index,  /* [in] TLS index to set value for */
479     LPVOID value) /* [in] Value to be stored */
480 {
481     if (index >= 64)
482     {
483         SetLastError( ERROR_INVALID_PARAMETER );
484         return FALSE;
485     }
486     NtCurrentTeb()->tls_array[index] = value;
487     return TRUE;
488 }
489
490
491 /***********************************************************************
492  * SetThreadContext [KERNEL32.670]  Sets context of thread.
493  *
494  * RETURNS
495  *    Success: TRUE
496  *    Failure: FALSE
497  */
498 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
499                               const CONTEXT *context ) /* [in] Address of context structure */
500 {
501     BOOL ret;
502     SERVER_START_REQ
503     {
504         struct set_thread_context_request *req = server_alloc_req( sizeof(*req),
505                                                                    sizeof(*context) );
506         req->handle = handle;
507         req->flags = context->ContextFlags;
508         memcpy( server_data_ptr(req), context, sizeof(*context) );
509         ret = !server_call( REQ_SET_THREAD_CONTEXT );
510     }
511     SERVER_END_REQ;
512     return ret;
513 }
514
515
516 /***********************************************************************
517  * GetThreadContext [KERNEL32.294]  Retrieves context of thread.
518  *
519  * RETURNS
520  *    Success: TRUE
521  *    Failure: FALSE
522  */
523 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
524                               CONTEXT *context ) /* [out] Address of context structure */
525 {
526     BOOL ret;
527     SERVER_START_REQ
528     {
529         struct get_thread_context_request *req = server_alloc_req( sizeof(*req),
530                                                                    sizeof(*context) );
531         req->handle = handle;
532         req->flags = context->ContextFlags;
533         memcpy( server_data_ptr(req), context, sizeof(*context) );
534         if ((ret = !server_call( REQ_GET_THREAD_CONTEXT )))
535             memcpy( context, server_data_ptr(req), sizeof(*context) );
536     }
537     SERVER_END_REQ;
538     return ret;
539 }
540
541
542 /**********************************************************************
543  * GetThreadPriority [KERNEL32.296]  Returns priority for thread.
544  *
545  * RETURNS
546  *    Success: Thread's priority level.
547  *    Failure: THREAD_PRIORITY_ERROR_RETURN
548  */
549 INT WINAPI GetThreadPriority(
550     HANDLE hthread) /* [in] Handle to thread */
551 {
552     INT ret = THREAD_PRIORITY_ERROR_RETURN;
553     SERVER_START_REQ
554     {
555         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
556         req->handle = hthread;
557         req->tid_in = 0;
558         if (!server_call( REQ_GET_THREAD_INFO )) ret = req->priority;
559     }
560     SERVER_END_REQ;
561     return ret;
562 }
563
564
565 /**********************************************************************
566  * SetThreadPriority [KERNEL32.514]  Sets priority for thread.
567  *
568  * RETURNS
569  *    Success: TRUE
570  *    Failure: FALSE
571  */
572 BOOL WINAPI SetThreadPriority(
573     HANDLE hthread, /* [in] Handle to thread */
574     INT priority)   /* [in] Thread priority level */
575 {
576     BOOL ret;
577     SERVER_START_REQ
578     {
579         struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
580         req->handle   = hthread;
581         req->priority = priority;
582         req->mask     = SET_THREAD_INFO_PRIORITY;
583         ret = !server_call( REQ_SET_THREAD_INFO );
584     }
585     SERVER_END_REQ;
586     return ret;
587 }
588
589
590 /**********************************************************************
591  * GetThreadPriorityBoost [KERNEL32.877]  Returns priority boost for thread.
592  *
593  * Always reports that priority boost is disabled.
594  *
595  * RETURNS
596  *    Success: TRUE.
597  *    Failure: FALSE
598  */
599 BOOL WINAPI GetThreadPriorityBoost(
600     HANDLE hthread, /* [in] Handle to thread */
601     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
602 {
603     if (pstate) *pstate = FALSE;
604     return NO_ERROR;
605 }
606
607
608 /**********************************************************************
609  * SetThreadPriorityBoost [KERNEL32.893]  Sets priority boost for thread.
610  *
611  * Priority boost is not implemented. Thsi function always returns 
612  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
613  *
614  * RETURNS
615  *    Always returns FALSE to indicate a failure 
616  */
617 BOOL WINAPI SetThreadPriorityBoost(
618     HANDLE hthread, /* [in] Handle to thread */
619     BOOL disable)   /* [in] TRUE to disable priority boost */
620 {
621     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
622     return FALSE;
623 }
624
625
626 /**********************************************************************
627  *           SetThreadAffinityMask   (KERNEL32.669)
628  */
629 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
630 {
631     DWORD ret;
632     SERVER_START_REQ
633     {
634         struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
635         req->handle   = hThread;
636         req->affinity = dwThreadAffinityMask;
637         req->mask     = SET_THREAD_INFO_AFFINITY;
638         ret = !server_call( REQ_SET_THREAD_INFO );
639         /* FIXME: should return previous value */
640     }
641     SERVER_END_REQ;
642     return ret;
643 }
644
645
646 /**********************************************************************
647  * TerminateThread [KERNEL32.685]  Terminates a thread
648  *
649  * RETURNS
650  *    Success: TRUE
651  *    Failure: FALSE
652  */
653 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
654                              DWORD exit_code)  /* [in] Exit code for thread */
655 {
656     NTSTATUS status = NtTerminateThread( handle, exit_code );
657     if (status) SetLastError( RtlNtStatusToDosError(status) );
658     return !status;
659 }
660
661
662 /**********************************************************************
663  * GetExitCodeThread [KERNEL32.???]  Gets termination status of thread.
664  * 
665  * RETURNS
666  *    Success: TRUE
667  *    Failure: FALSE
668  */
669 BOOL WINAPI GetExitCodeThread(
670     HANDLE hthread, /* [in]  Handle to thread */
671     LPDWORD exitcode) /* [out] Address to receive termination status */
672 {
673     BOOL ret;
674     SERVER_START_REQ
675     {
676         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
677         req->handle = hthread;
678         req->tid_in = 0;
679         ret = !server_call( REQ_GET_THREAD_INFO );
680         if (ret && exitcode) *exitcode = req->exit_code;
681     }
682     SERVER_END_REQ;
683     return ret;
684 }
685
686
687 /**********************************************************************
688  * ResumeThread [KERNEL32.587]  Resumes a thread.
689  *
690  * Decrements a thread's suspend count.  When count is zero, the
691  * execution of the thread is resumed.
692  *
693  * RETURNS
694  *    Success: Previous suspend count
695  *    Failure: 0xFFFFFFFF
696  *    Already running: 0
697  */
698 DWORD WINAPI ResumeThread(
699     HANDLE hthread) /* [in] Identifies thread to restart */
700 {
701     DWORD ret = 0xffffffff;
702     SERVER_START_REQ
703     {
704         struct resume_thread_request *req = server_alloc_req( sizeof(*req), 0 );
705         req->handle = hthread;
706         if (!server_call( REQ_RESUME_THREAD )) ret = req->count;
707     }
708     SERVER_END_REQ;
709     return ret;
710 }
711
712
713 /**********************************************************************
714  * SuspendThread [KERNEL32.681]  Suspends a thread.
715  *
716  * RETURNS
717  *    Success: Previous suspend count
718  *    Failure: 0xFFFFFFFF
719  */
720 DWORD WINAPI SuspendThread(
721     HANDLE hthread) /* [in] Handle to the thread */
722 {
723     DWORD ret = 0xffffffff;
724     SERVER_START_REQ
725     {
726         struct suspend_thread_request *req = server_alloc_req( sizeof(*req), 0 );
727         req->handle = hthread;
728         if (!server_call( REQ_SUSPEND_THREAD )) ret = req->count;
729     }
730     SERVER_END_REQ;
731     return ret;
732 }
733
734
735 /***********************************************************************
736  *              QueueUserAPC  (KERNEL32.566)
737  */
738 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
739 {
740     DWORD ret;
741     SERVER_START_REQ
742     {
743         struct queue_apc_request *req = server_alloc_req( sizeof(*req), 0 );
744         req->handle = hthread;
745         req->func   = func;
746         req->param  = (void *)data;
747         ret = !server_call( REQ_QUEUE_APC );
748     }
749     SERVER_END_REQ;
750     return ret;
751 }
752
753
754 /**********************************************************************
755  * GetThreadTimes [KERNEL32.???]  Obtains timing information.
756  *
757  * NOTES
758  *    What are the fields where these values are stored?
759  *
760  * RETURNS
761  *    Success: TRUE
762  *    Failure: FALSE
763  */
764 BOOL WINAPI GetThreadTimes( 
765     HANDLE thread,         /* [in]  Specifies the thread of interest */
766     LPFILETIME creationtime, /* [out] When the thread was created */
767     LPFILETIME exittime,     /* [out] When the thread was destroyed */
768     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
769     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
770 {
771     FIXME("(0x%08x): stub\n",thread);
772     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
773     return FALSE;
774 }
775
776
777 /**********************************************************************
778  * VWin32_BoostThreadGroup [KERNEL.535]
779  */
780 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
781 {
782     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
783 }
784
785 /**********************************************************************
786  * VWin32_BoostThreadStatic [KERNEL.536]
787  */
788 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
789 {
790     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
791 }
792
793
794 /***********************************************************************
795  *           GetThreadLocale    (KERNEL32.295)
796  */
797 LCID WINAPI GetThreadLocale(void)
798 {
799     LCID ret = NtCurrentTeb()->CurrentLocale;
800     if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
801     return ret;
802 }
803
804
805 /**********************************************************************
806  * SetThreadLocale [KERNEL32.671]  Sets the calling threads current locale.
807  *
808  * RETURNS
809  *    Success: TRUE
810  *    Failure: FALSE
811  *
812  * FIXME
813  *  check if lcid is a valid cp
814  */
815 BOOL WINAPI SetThreadLocale(
816     LCID lcid)     /* [in] Locale identifier */
817 {
818     switch (lcid)
819     {
820       case LOCALE_SYSTEM_DEFAULT:
821         lcid = GetSystemDefaultLCID();
822         break;
823       case LOCALE_USER_DEFAULT:
824       case LOCALE_NEUTRAL:
825         lcid = GetUserDefaultLCID();
826         break;
827     }
828     NtCurrentTeb()->CurrentLocale = lcid;
829     return TRUE;
830 }
831
832
833 /***********************************************************************
834  * GetCurrentThread [KERNEL32.200]  Gets pseudohandle for current thread
835  *
836  * RETURNS
837  *    Pseudohandle for the current thread
838  */
839 #undef GetCurrentThread
840 HANDLE WINAPI GetCurrentThread(void)
841 {
842     return 0xfffffffe;
843 }
844
845
846 /***********************************************************************
847  * ProcessIdToSessionId   (KERNEL32)
848  * This function is available on Terminal Server 4SP4 and Windows 2000
849  */
850 BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
851 {
852         /* According to MSDN, if the calling process is not in a terminal
853          * services environment, then the sessionid returned is zero.
854          */
855         *sessionid_ptr = 0;
856         return TRUE;
857 }
858
859
860 #ifdef __i386__
861
862 /* void WINAPI SetLastError( DWORD error ); */
863 __ASM_GLOBAL_FUNC( SetLastError,
864                    "movl 4(%esp),%eax\n\t"
865                    ".byte 0x64\n\t"
866                    "movl %eax,0x60\n\t"
867                    "ret $4" );
868
869 /* DWORD WINAPI GetLastError(void); */
870 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
871
872 /* DWORD WINAPI GetCurrentProcessId(void) */
873 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
874                    
875 /* DWORD WINAPI GetCurrentThreadId(void) */
876 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
877                    
878 #else  /* __i386__ */
879
880 /**********************************************************************
881  * SetLastError [KERNEL.147] [KERNEL32.497]  Sets the last-error code.
882  */
883 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
884 {
885     NtCurrentTeb()->last_error = error;
886 }
887
888 /**********************************************************************
889  * GetLastError [KERNEL.148] [KERNEL32.227]  Returns last-error code.
890  */
891 DWORD WINAPI GetLastError(void)
892 {
893     return NtCurrentTeb()->last_error;
894 }
895
896 /***********************************************************************
897  * GetCurrentProcessId [KERNEL32.199]  Returns process identifier.
898  */
899 DWORD WINAPI GetCurrentProcessId(void)
900 {
901     return (DWORD)NtCurrentTeb()->pid;
902 }
903
904 /***********************************************************************
905  * GetCurrentThreadId [KERNEL32.201]  Returns thread identifier.
906  */
907 DWORD WINAPI GetCurrentThreadId(void)
908 {
909     return (DWORD)NtCurrentTeb()->tid;
910 }
911
912 #endif  /* __i386__ */