Fixed usage of RegEnumValueA.
[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 = 0;
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;
288     HANDLE handle = 0;
289     TEB *teb;
290     void *tid = 0;
291
292     SERVER_START_REQ
293     {
294         struct new_thread_request *req = server_alloc_req( sizeof(*req), 0 );
295
296         req->suspend = ((flags & CREATE_SUSPENDED) != 0);
297         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
298         if (!server_call( REQ_NEW_THREAD ))
299         {
300             handle = req->handle;
301             tid = req->tid;
302             socket = wine_server_recv_fd( handle, 0 );
303         }
304     }
305     SERVER_END_REQ;
306     if (!handle) return 0;
307
308     if (!(teb = THREAD_Create( socket, stack, TRUE )))
309     {
310         close( socket );
311         return 0;
312     }
313     teb->entry_point = start;
314     teb->entry_arg   = param;
315     teb->startup     = THREAD_Start;
316     teb->htask16     = GetCurrentTask();
317     if (id) *id = (DWORD)tid;
318     if (SYSDEPS_SpawnThread( teb ) == -1)
319     {
320         CloseHandle( handle );
321         THREAD_FreeTEB( teb );
322         return 0;
323     }
324     return handle;
325 }
326
327 /***********************************************************************
328  *           CreateThread16   (KERNEL.441)
329  */
330 static DWORD CALLBACK THREAD_StartThread16( LPVOID threadArgs )
331 {
332     FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
333     DWORD     param = ((DWORD *)threadArgs)[1];
334     HeapFree( GetProcessHeap(), 0, threadArgs );
335
336     ((LPDWORD)CURRENT_STACK16)[-1] = param;
337     return wine_call_to_16_long( start, sizeof(DWORD) );
338 }
339 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
340                               FARPROC16 start, SEGPTR param,
341                               DWORD flags, LPDWORD id )
342 {
343     DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
344     if (!threadArgs) return INVALID_HANDLE_VALUE;
345     threadArgs[0] = (DWORD)start;
346     threadArgs[1] = (DWORD)param;
347
348     return CreateThread( sa, stack, THREAD_StartThread16, threadArgs, flags, id );
349 }
350
351
352 /***********************************************************************
353  * ExitThread [KERNEL32.215]  Ends a thread
354  *
355  * RETURNS
356  *    None
357  */
358 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
359 {
360     BOOL last;
361     SERVER_START_REQ
362     {
363         struct terminate_thread_request *req = server_alloc_req( sizeof(*req), 0 );
364
365         /* send the exit code to the server */
366         req->handle    = GetCurrentThread();
367         req->exit_code = code;
368         server_call( REQ_TERMINATE_THREAD );
369         last = req->last;
370     }
371     SERVER_END_REQ;
372
373     if (last)
374     {
375         MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
376         exit( code );
377     }
378     else
379     {
380         MODULE_DllThreadDetach( NULL );
381         if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_ExitTask();
382         SYSDEPS_ExitThread( code );
383     }
384 }
385
386
387 /***********************************************************************
388  * SetThreadContext [KERNEL32.670]  Sets context of thread.
389  *
390  * RETURNS
391  *    Success: TRUE
392  *    Failure: FALSE
393  */
394 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
395                               const CONTEXT *context ) /* [in] Address of context structure */
396 {
397     BOOL ret;
398     SERVER_START_REQ
399     {
400         struct set_thread_context_request *req = server_alloc_req( sizeof(*req),
401                                                                    sizeof(*context) );
402         req->handle = handle;
403         req->flags = context->ContextFlags;
404         memcpy( server_data_ptr(req), context, sizeof(*context) );
405         ret = !server_call( REQ_SET_THREAD_CONTEXT );
406     }
407     SERVER_END_REQ;
408     return ret;
409 }
410
411
412 /***********************************************************************
413  * GetThreadContext [KERNEL32.294]  Retrieves context of thread.
414  *
415  * RETURNS
416  *    Success: TRUE
417  *    Failure: FALSE
418  */
419 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
420                               CONTEXT *context ) /* [out] Address of context structure */
421 {
422     BOOL ret;
423     SERVER_START_REQ
424     {
425         struct get_thread_context_request *req = server_alloc_req( sizeof(*req),
426                                                                    sizeof(*context) );
427         req->handle = handle;
428         req->flags = context->ContextFlags;
429         memcpy( server_data_ptr(req), context, sizeof(*context) );
430         if ((ret = !server_call( REQ_GET_THREAD_CONTEXT )))
431             memcpy( context, server_data_ptr(req), sizeof(*context) );
432     }
433     SERVER_END_REQ;
434     return ret;
435 }
436
437
438 /**********************************************************************
439  * GetThreadPriority [KERNEL32.296]  Returns priority for thread.
440  *
441  * RETURNS
442  *    Success: Thread's priority level.
443  *    Failure: THREAD_PRIORITY_ERROR_RETURN
444  */
445 INT WINAPI GetThreadPriority(
446     HANDLE hthread) /* [in] Handle to thread */
447 {
448     INT ret = THREAD_PRIORITY_ERROR_RETURN;
449     SERVER_START_REQ
450     {
451         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
452         req->handle = hthread;
453         req->tid_in = 0;
454         if (!server_call( REQ_GET_THREAD_INFO )) ret = req->priority;
455     }
456     SERVER_END_REQ;
457     return ret;
458 }
459
460
461 /**********************************************************************
462  * SetThreadPriority [KERNEL32.514]  Sets priority for thread.
463  *
464  * RETURNS
465  *    Success: TRUE
466  *    Failure: FALSE
467  */
468 BOOL WINAPI SetThreadPriority(
469     HANDLE hthread, /* [in] Handle to thread */
470     INT priority)   /* [in] Thread priority level */
471 {
472     BOOL ret;
473     SERVER_START_REQ
474     {
475         struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
476         req->handle   = hthread;
477         req->priority = priority;
478         req->mask     = SET_THREAD_INFO_PRIORITY;
479         ret = !server_call( REQ_SET_THREAD_INFO );
480     }
481     SERVER_END_REQ;
482     return ret;
483 }
484
485
486 /**********************************************************************
487  * GetThreadPriorityBoost [KERNEL32.877]  Returns priority boost for thread.
488  *
489  * Always reports that priority boost is disabled.
490  *
491  * RETURNS
492  *    Success: TRUE.
493  *    Failure: FALSE
494  */
495 BOOL WINAPI GetThreadPriorityBoost(
496     HANDLE hthread, /* [in] Handle to thread */
497     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
498 {
499     if (pstate) *pstate = FALSE;
500     return NO_ERROR;
501 }
502
503
504 /**********************************************************************
505  * SetThreadPriorityBoost [KERNEL32.893]  Sets priority boost for thread.
506  *
507  * Priority boost is not implemented. Thsi function always returns 
508  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
509  *
510  * RETURNS
511  *    Always returns FALSE to indicate a failure 
512  */
513 BOOL WINAPI SetThreadPriorityBoost(
514     HANDLE hthread, /* [in] Handle to thread */
515     BOOL disable)   /* [in] TRUE to disable priority boost */
516 {
517     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
518     return FALSE;
519 }
520
521
522 /**********************************************************************
523  *           SetThreadAffinityMask   (KERNEL32.669)
524  */
525 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
526 {
527     DWORD ret;
528     SERVER_START_REQ
529     {
530         struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
531         req->handle   = hThread;
532         req->affinity = dwThreadAffinityMask;
533         req->mask     = SET_THREAD_INFO_AFFINITY;
534         ret = !server_call( REQ_SET_THREAD_INFO );
535         /* FIXME: should return previous value */
536     }
537     SERVER_END_REQ;
538     return ret;
539 }
540
541
542 /**********************************************************************
543  * TerminateThread [KERNEL32.685]  Terminates a thread
544  *
545  * RETURNS
546  *    Success: TRUE
547  *    Failure: FALSE
548  */
549 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
550                              DWORD exit_code)  /* [in] Exit code for thread */
551 {
552     NTSTATUS status = NtTerminateThread( handle, exit_code );
553     if (status) SetLastError( RtlNtStatusToDosError(status) );
554     return !status;
555 }
556
557
558 /**********************************************************************
559  * GetExitCodeThread [KERNEL32.???]  Gets termination status of thread.
560  * 
561  * RETURNS
562  *    Success: TRUE
563  *    Failure: FALSE
564  */
565 BOOL WINAPI GetExitCodeThread(
566     HANDLE hthread, /* [in]  Handle to thread */
567     LPDWORD exitcode) /* [out] Address to receive termination status */
568 {
569     BOOL ret;
570     SERVER_START_REQ
571     {
572         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
573         req->handle = hthread;
574         req->tid_in = 0;
575         ret = !server_call( REQ_GET_THREAD_INFO );
576         if (ret && exitcode) *exitcode = req->exit_code;
577     }
578     SERVER_END_REQ;
579     return ret;
580 }
581
582
583 /**********************************************************************
584  * ResumeThread [KERNEL32.587]  Resumes a thread.
585  *
586  * Decrements a thread's suspend count.  When count is zero, the
587  * execution of the thread is resumed.
588  *
589  * RETURNS
590  *    Success: Previous suspend count
591  *    Failure: 0xFFFFFFFF
592  *    Already running: 0
593  */
594 DWORD WINAPI ResumeThread(
595     HANDLE hthread) /* [in] Identifies thread to restart */
596 {
597     DWORD ret = 0xffffffff;
598     SERVER_START_REQ
599     {
600         struct resume_thread_request *req = server_alloc_req( sizeof(*req), 0 );
601         req->handle = hthread;
602         if (!server_call( REQ_RESUME_THREAD )) ret = req->count;
603     }
604     SERVER_END_REQ;
605     return ret;
606 }
607
608
609 /**********************************************************************
610  * SuspendThread [KERNEL32.681]  Suspends a thread.
611  *
612  * RETURNS
613  *    Success: Previous suspend count
614  *    Failure: 0xFFFFFFFF
615  */
616 DWORD WINAPI SuspendThread(
617     HANDLE hthread) /* [in] Handle to the thread */
618 {
619     DWORD ret = 0xffffffff;
620     SERVER_START_REQ
621     {
622         struct suspend_thread_request *req = server_alloc_req( sizeof(*req), 0 );
623         req->handle = hthread;
624         if (!server_call( REQ_SUSPEND_THREAD )) ret = req->count;
625     }
626     SERVER_END_REQ;
627     return ret;
628 }
629
630
631 /***********************************************************************
632  *              QueueUserAPC  (KERNEL32.566)
633  */
634 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
635 {
636     DWORD ret;
637     SERVER_START_REQ
638     {
639         struct queue_apc_request *req = server_alloc_req( sizeof(*req), 0 );
640         req->handle = hthread;
641         req->user   = 1;
642         req->func   = func;
643         req->param  = (void *)data;
644         ret = !server_call( REQ_QUEUE_APC );
645     }
646     SERVER_END_REQ;
647     return ret;
648 }
649
650
651 /**********************************************************************
652  * GetThreadTimes [KERNEL32.???]  Obtains timing information.
653  *
654  * NOTES
655  *    What are the fields where these values are stored?
656  *
657  * RETURNS
658  *    Success: TRUE
659  *    Failure: FALSE
660  */
661 BOOL WINAPI GetThreadTimes( 
662     HANDLE thread,         /* [in]  Specifies the thread of interest */
663     LPFILETIME creationtime, /* [out] When the thread was created */
664     LPFILETIME exittime,     /* [out] When the thread was destroyed */
665     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
666     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
667 {
668     FIXME("(0x%08x): stub\n",thread);
669     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
670     return FALSE;
671 }
672
673
674 /**********************************************************************
675  * VWin32_BoostThreadGroup [KERNEL.535]
676  */
677 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
678 {
679     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
680 }
681
682 /**********************************************************************
683  * VWin32_BoostThreadStatic [KERNEL.536]
684  */
685 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
686 {
687     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
688 }
689
690
691 /***********************************************************************
692  *           GetThreadLocale    (KERNEL32.295)
693  */
694 LCID WINAPI GetThreadLocale(void)
695 {
696     LCID ret = NtCurrentTeb()->CurrentLocale;
697     if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
698     return ret;
699 }
700
701
702 /**********************************************************************
703  * SetThreadLocale [KERNEL32.671]  Sets the calling threads current locale.
704  *
705  * RETURNS
706  *    Success: TRUE
707  *    Failure: FALSE
708  *
709  * FIXME
710  *  check if lcid is a valid cp
711  */
712 BOOL WINAPI SetThreadLocale(
713     LCID lcid)     /* [in] Locale identifier */
714 {
715     switch (lcid)
716     {
717       case LOCALE_SYSTEM_DEFAULT:
718         lcid = GetSystemDefaultLCID();
719         break;
720       case LOCALE_USER_DEFAULT:
721       case LOCALE_NEUTRAL:
722         lcid = GetUserDefaultLCID();
723         break;
724     }
725     NtCurrentTeb()->CurrentLocale = lcid;
726     return TRUE;
727 }
728
729
730 /***********************************************************************
731  * GetCurrentThread [KERNEL32.200]  Gets pseudohandle for current thread
732  *
733  * RETURNS
734  *    Pseudohandle for the current thread
735  */
736 #undef GetCurrentThread
737 HANDLE WINAPI GetCurrentThread(void)
738 {
739     return 0xfffffffe;
740 }
741
742
743 /***********************************************************************
744  * ProcessIdToSessionId   (KERNEL32)
745  * This function is available on Terminal Server 4SP4 and Windows 2000
746  */
747 BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
748 {
749         /* According to MSDN, if the calling process is not in a terminal
750          * services environment, then the sessionid returned is zero.
751          */
752         *sessionid_ptr = 0;
753         return TRUE;
754 }
755
756
757 #ifdef __i386__
758
759 /* void WINAPI SetLastError( DWORD error ); */
760 __ASM_GLOBAL_FUNC( SetLastError,
761                    "movl 4(%esp),%eax\n\t"
762                    ".byte 0x64\n\t"
763                    "movl %eax,0x60\n\t"
764                    "ret $4" );
765
766 /* DWORD WINAPI GetLastError(void); */
767 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
768
769 /* DWORD WINAPI GetCurrentProcessId(void) */
770 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
771                    
772 /* DWORD WINAPI GetCurrentThreadId(void) */
773 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
774                    
775 #else  /* __i386__ */
776
777 /**********************************************************************
778  * SetLastError [KERNEL.147] [KERNEL32.497]  Sets the last-error code.
779  */
780 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
781 {
782     NtCurrentTeb()->last_error = error;
783 }
784
785 /**********************************************************************
786  * GetLastError [KERNEL.148] [KERNEL32.227]  Returns last-error code.
787  */
788 DWORD WINAPI GetLastError(void)
789 {
790     return NtCurrentTeb()->last_error;
791 }
792
793 /***********************************************************************
794  * GetCurrentProcessId [KERNEL32.199]  Returns process identifier.
795  */
796 DWORD WINAPI GetCurrentProcessId(void)
797 {
798     return (DWORD)NtCurrentTeb()->pid;
799 }
800
801 /***********************************************************************
802  * GetCurrentThreadId [KERNEL32.201]  Returns thread identifier.
803  */
804 DWORD WINAPI GetCurrentThreadId(void)
805 {
806     return (DWORD)NtCurrentTeb()->tid;
807 }
808
809 #endif  /* __i386__ */