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