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