- Add routines to dump out tab items internally and externally
[wine] / scheduler / thread.c
1 /*
2  * Win32 threads
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_MMAN_H
28 #include <sys/mman.h>
29 #endif
30 #include <unistd.h>
31 #include "wine/winbase16.h"
32 #include "thread.h"
33 #include "task.h"
34 #include "module.h"
35 #include "winerror.h"
36 #include "selectors.h"
37 #include "winnt.h"
38 #include "wine/server.h"
39 #include "stackframe.h"
40 #include "wine/debug.h"
41 #include "winnls.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(thread);
44 WINE_DECLARE_DEBUG_CHANNEL(relay);
45
46 /* TEB of the initial thread */
47 static TEB initial_teb;
48
49 extern struct _PDB current_process;
50
51 /***********************************************************************
52  *           THREAD_IdToTEB
53  *
54  * Convert a thread id to a TEB, making sure it is valid.
55  */
56 TEB *THREAD_IdToTEB( DWORD id )
57 {
58     TEB *ret = NULL;
59
60     if (!id || id == GetCurrentThreadId()) return NtCurrentTeb();
61
62     SERVER_START_REQ( get_thread_info )
63     {
64         req->handle = 0;
65         req->tid_in = (void *)id;
66         if (!wine_server_call( req )) ret = reply->teb;
67     }
68     SERVER_END_REQ;
69
70     if (!ret)
71     {
72         /* Allow task handles to be used; convert to main thread */
73         if ( IsTask16( id ) )
74         {
75             TDB *pTask = TASK_GetPtr( id );
76             if (pTask) return pTask->teb;
77         }
78         SetLastError( ERROR_INVALID_PARAMETER );
79     }
80     return ret;
81 }
82
83
84 /***********************************************************************
85  *           THREAD_InitTEB
86  *
87  * Initialization of a newly created TEB.
88  */
89 static BOOL THREAD_InitTEB( TEB *teb )
90 {
91     teb->except    = (void *)~0UL;
92     teb->self      = teb;
93     teb->tibflags  = TEBF_WIN32;
94     teb->tls_ptr   = teb->tls_array;
95     teb->exit_code = STILL_ACTIVE;
96     teb->request_fd = -1;
97     teb->reply_fd   = -1;
98     teb->wait_fd[0] = -1;
99     teb->wait_fd[1] = -1;
100     teb->stack_top  = (void *)~0UL;
101     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
102     teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
103     teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
104     return (teb->teb_sel != 0);
105 }
106
107
108 /***********************************************************************
109  *           THREAD_FreeTEB
110  *
111  * Free data structures associated with a thread.
112  * Must be called from the context of another thread.
113  */
114 static void THREAD_FreeTEB( TEB *teb )
115 {
116     TRACE("(%p) called\n", teb );
117     /* Free the associated memory */
118     FreeSelector16( teb->stack_sel );
119     FreeSelector16( teb->teb_sel );
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 )
130 {
131     DWORD old_prot, total_size;
132     DWORD page_size = 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      * 1 page              debug info (except for initial thread)
164      */
165
166     stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
167     total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
168     total_size += 0x10000; /* 16-bit stack */
169     if (!teb) total_size += 2 * page_size;
170
171     if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
172         return NULL;
173
174     if (!teb)
175     {
176         teb = (TEB *)((char *)base + total_size - 2 * page_size);
177         if (!THREAD_InitTEB( teb )) goto error;
178         teb->debug_info = (char *)teb + page_size;
179     }
180
181     teb->stack_low    = base;
182     teb->stack_base   = base;
183     teb->signal_stack = (char *)base + page_size;
184     teb->stack_top    = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size;
185
186     /* Setup guard pages */
187
188     VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot );
189     VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot );
190     VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1,
191                     PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
192
193     /* Allocate the 16-bit stack selector */
194
195     teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, WINE_LDT_FLAGS_DATA );
196     if (!teb->stack_sel) goto error;
197     teb->cur_stack = MAKESEGPTR( teb->stack_sel, 0x10000 - sizeof(STACK16FRAME) );
198
199     return teb;
200
201 error:
202     FreeSelector16( teb->teb_sel );
203     VirtualFree( base, 0, MEM_RELEASE );
204     return NULL;
205 }
206
207
208 /***********************************************************************
209  *           thread_errno_location
210  *
211  * Get the per-thread errno location.
212  */
213 static int *thread_errno_location(void)
214 {
215     return &NtCurrentTeb()->thread_errno;
216 }
217
218 /***********************************************************************
219  *           thread_h_errno_location
220  *
221  * Get the per-thread h_errno location.
222  */
223 static int *thread_h_errno_location(void)
224 {
225     return &NtCurrentTeb()->thread_h_errno;
226 }
227
228 /***********************************************************************
229  *           THREAD_Init
230  *
231  * Setup the initial thread.
232  *
233  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
234  */
235 void THREAD_Init(void)
236 {
237     if (!initial_teb.self)  /* do it only once */
238     {
239         THREAD_InitTEB( &initial_teb );
240         assert( initial_teb.teb_sel );
241         initial_teb.process = &current_process;
242         SYSDEPS_SetCurThread( &initial_teb );
243         wine_errno_location = thread_errno_location;
244         wine_h_errno_location = thread_h_errno_location;
245     }
246 }
247
248 DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
249
250
251 /***********************************************************************
252  *           THREAD_Start
253  *
254  * Start execution of a newly created thread. Does not return.
255  */
256 static void THREAD_Start(void)
257 {
258     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)NtCurrentTeb()->entry_point;
259
260     if (TRACE_ON(relay))
261         DPRINTF("%08lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
262
263     PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
264     MODULE_DllThreadAttach( NULL );
265     ExitThread( func( NtCurrentTeb()->entry_arg ) );
266 }
267
268
269 /***********************************************************************
270  *           CreateThread   (KERNEL32.@)
271  */
272 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
273                             LPTHREAD_START_ROUTINE start, LPVOID param,
274                             DWORD flags, LPDWORD id )
275 {
276     HANDLE handle = 0;
277     TEB *teb;
278     void *tid = 0;
279     int request_pipe[2];
280
281     if (pipe( request_pipe ) == -1)
282     {
283         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
284         return 0;
285     }
286     fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
287     wine_server_send_fd( request_pipe[0] );
288
289     SERVER_START_REQ( new_thread )
290     {
291         req->suspend    = ((flags & CREATE_SUSPENDED) != 0);
292         req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
293         req->request_fd = request_pipe[0];
294         if (!wine_server_call_err( req ))
295         {
296             handle = reply->handle;
297             tid = reply->tid;
298         }
299         close( request_pipe[0] );
300     }
301     SERVER_END_REQ;
302
303     if (!handle || !(teb = THREAD_InitStack( NULL, stack )))
304     {
305         close( request_pipe[1] );
306         return 0;
307     }
308
309     teb->process     = NtCurrentTeb()->process;
310     teb->tid         = tid;
311     teb->request_fd  = request_pipe[1];
312     teb->entry_point = start;
313     teb->entry_arg   = param;
314     teb->startup     = THREAD_Start;
315     teb->htask16     = GetCurrentTask();
316
317     if (id) *id = (DWORD)tid;
318     if (SYSDEPS_SpawnThread( teb ) == -1)
319     {
320         CloseHandle( handle );
321         close( request_pipe[1] );
322         THREAD_FreeTEB( teb );
323         return 0;
324     }
325     return handle;
326 }
327
328 /***********************************************************************
329  *           CreateThread16   (KERNEL.441)
330  */
331 static DWORD CALLBACK THREAD_StartThread16( LPVOID threadArgs )
332 {
333     FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
334     DWORD     param = ((DWORD *)threadArgs)[1];
335     HeapFree( GetProcessHeap(), 0, threadArgs );
336
337     ((LPDWORD)CURRENT_STACK16)[-1] = param;
338     return wine_call_to_16_long( start, sizeof(DWORD) );
339 }
340 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
341                               FARPROC16 start, SEGPTR param,
342                               DWORD flags, LPDWORD id )
343 {
344     DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
345     if (!threadArgs) return INVALID_HANDLE_VALUE;
346     threadArgs[0] = (DWORD)start;
347     threadArgs[1] = (DWORD)param;
348
349     return CreateThread( sa, stack, THREAD_StartThread16, threadArgs, flags, id );
350 }
351
352
353 /***********************************************************************
354  * ExitThread [KERNEL32.@]  Ends a thread
355  *
356  * RETURNS
357  *    None
358  */
359 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
360 {
361     BOOL last;
362     SERVER_START_REQ( terminate_thread )
363     {
364         /* send the exit code to the server */
365         req->handle    = GetCurrentThread();
366         req->exit_code = code;
367         wine_server_call( req );
368         last = reply->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  * OpenThread Retrieves a handle to a thread from its thread id
387  *
388  * RETURNS
389  *    None
390  */
391 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
392 {
393     HANDLE ret = 0;
394     SERVER_START_REQ( open_thread )
395     {
396         req->tid     = (void *)dwThreadId;
397         req->access  = dwDesiredAccess;
398         req->inherit = bInheritHandle;
399         if (!wine_server_call_err( req )) ret = reply->handle;
400     }
401     SERVER_END_REQ;
402     return ret;
403 }
404
405 /***********************************************************************
406  * SetThreadContext [KERNEL32.@]  Sets context of thread.
407  *
408  * RETURNS
409  *    Success: TRUE
410  *    Failure: FALSE
411  */
412 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
413                               const CONTEXT *context ) /* [in] Address of context structure */
414 {
415     BOOL ret;
416     SERVER_START_REQ( set_thread_context )
417     {
418         req->handle = handle;
419         req->flags = context->ContextFlags;
420         wine_server_add_data( req, context, sizeof(*context) );
421         ret = !wine_server_call_err( req );
422     }
423     SERVER_END_REQ;
424     return ret;
425 }
426
427
428 /***********************************************************************
429  * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
430  *
431  * RETURNS
432  *    Success: TRUE
433  *    Failure: FALSE
434  */
435 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
436                               CONTEXT *context ) /* [out] Address of context structure */
437 {
438     BOOL ret;
439     SERVER_START_REQ( get_thread_context )
440     {
441         req->handle = handle;
442         req->flags = context->ContextFlags;
443         wine_server_add_data( req, context, sizeof(*context) );
444         wine_server_set_reply( req, context, sizeof(*context) );
445         ret = !wine_server_call_err( req );
446     }
447     SERVER_END_REQ;
448     return ret;
449 }
450
451
452 /**********************************************************************
453  * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
454  *
455  * RETURNS
456  *    Success: Thread's priority level.
457  *    Failure: THREAD_PRIORITY_ERROR_RETURN
458  */
459 INT WINAPI GetThreadPriority(
460     HANDLE hthread) /* [in] Handle to thread */
461 {
462     INT ret = THREAD_PRIORITY_ERROR_RETURN;
463     SERVER_START_REQ( get_thread_info )
464     {
465         req->handle = hthread;
466         req->tid_in = 0;
467         if (!wine_server_call_err( req )) ret = reply->priority;
468     }
469     SERVER_END_REQ;
470     return ret;
471 }
472
473
474 /**********************************************************************
475  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
476  *
477  * RETURNS
478  *    Success: TRUE
479  *    Failure: FALSE
480  */
481 BOOL WINAPI SetThreadPriority(
482     HANDLE hthread, /* [in] Handle to thread */
483     INT priority)   /* [in] Thread priority level */
484 {
485     BOOL ret;
486     SERVER_START_REQ( set_thread_info )
487     {
488         req->handle   = hthread;
489         req->priority = priority;
490         req->mask     = SET_THREAD_INFO_PRIORITY;
491         ret = !wine_server_call_err( req );
492     }
493     SERVER_END_REQ;
494     return ret;
495 }
496
497
498 /**********************************************************************
499  * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
500  *
501  * Always reports that priority boost is disabled.
502  *
503  * RETURNS
504  *    Success: TRUE.
505  *    Failure: FALSE
506  */
507 BOOL WINAPI GetThreadPriorityBoost(
508     HANDLE hthread, /* [in] Handle to thread */
509     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
510 {
511     if (pstate) *pstate = FALSE;
512     return NO_ERROR;
513 }
514
515
516 /**********************************************************************
517  * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
518  *
519  * Priority boost is not implemented. Thsi function always returns
520  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
521  *
522  * RETURNS
523  *    Always returns FALSE to indicate a failure
524  */
525 BOOL WINAPI SetThreadPriorityBoost(
526     HANDLE hthread, /* [in] Handle to thread */
527     BOOL disable)   /* [in] TRUE to disable priority boost */
528 {
529     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
530     return FALSE;
531 }
532
533
534 /**********************************************************************
535  *           SetThreadAffinityMask   (KERNEL32.@)
536  */
537 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
538 {
539     DWORD ret;
540     SERVER_START_REQ( set_thread_info )
541     {
542         req->handle   = hThread;
543         req->affinity = dwThreadAffinityMask;
544         req->mask     = SET_THREAD_INFO_AFFINITY;
545         ret = !wine_server_call_err( req );
546         /* FIXME: should return previous value */
547     }
548     SERVER_END_REQ;
549     return ret;
550 }
551
552 /**********************************************************************
553  * SetThreadIdealProcessor [KERNEL32.@]  Obtains timing information.
554  *
555  * RETURNS
556  *    Success: Value of last call to SetThreadIdealProcessor
557  *    Failure: -1
558  */
559 DWORD WINAPI SetThreadIdealProcessor(
560     HANDLE hThread,          /* [in] Specifies the thread of interest */
561     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
562 {
563     FIXME("(0x%08x): stub\n",hThread);
564     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
565     return -1L;
566 }
567
568 /**********************************************************************
569  * TerminateThread [KERNEL32.@]  Terminates a thread
570  *
571  * RETURNS
572  *    Success: TRUE
573  *    Failure: FALSE
574  */
575 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
576                              DWORD exit_code)  /* [in] Exit code for thread */
577 {
578     NTSTATUS status = NtTerminateThread( handle, exit_code );
579     if (status) SetLastError( RtlNtStatusToDosError(status) );
580     return !status;
581 }
582
583
584 /**********************************************************************
585  *              GetExitCodeThread (KERNEL32.@)
586  *
587  * Gets termination status of thread.
588  *
589  * RETURNS
590  *    Success: TRUE
591  *    Failure: FALSE
592  */
593 BOOL WINAPI GetExitCodeThread(
594     HANDLE hthread, /* [in]  Handle to thread */
595     LPDWORD exitcode) /* [out] Address to receive termination status */
596 {
597     BOOL ret;
598     SERVER_START_REQ( get_thread_info )
599     {
600         req->handle = hthread;
601         req->tid_in = 0;
602         ret = !wine_server_call_err( req );
603         if (ret && exitcode) *exitcode = reply->exit_code;
604     }
605     SERVER_END_REQ;
606     return ret;
607 }
608
609
610 /**********************************************************************
611  * ResumeThread [KERNEL32.@]  Resumes a thread.
612  *
613  * Decrements a thread's suspend count.  When count is zero, the
614  * execution of the thread is resumed.
615  *
616  * RETURNS
617  *    Success: Previous suspend count
618  *    Failure: 0xFFFFFFFF
619  *    Already running: 0
620  */
621 DWORD WINAPI ResumeThread(
622     HANDLE hthread) /* [in] Identifies thread to restart */
623 {
624     DWORD ret = 0xffffffff;
625     SERVER_START_REQ( resume_thread )
626     {
627         req->handle = hthread;
628         if (!wine_server_call_err( req )) ret = reply->count;
629     }
630     SERVER_END_REQ;
631     return ret;
632 }
633
634
635 /**********************************************************************
636  * SuspendThread [KERNEL32.@]  Suspends a thread.
637  *
638  * RETURNS
639  *    Success: Previous suspend count
640  *    Failure: 0xFFFFFFFF
641  */
642 DWORD WINAPI SuspendThread(
643     HANDLE hthread) /* [in] Handle to the thread */
644 {
645     DWORD ret = 0xffffffff;
646     SERVER_START_REQ( suspend_thread )
647     {
648         req->handle = hthread;
649         if (!wine_server_call_err( req )) ret = reply->count;
650     }
651     SERVER_END_REQ;
652     return ret;
653 }
654
655
656 /***********************************************************************
657  *              QueueUserAPC  (KERNEL32.@)
658  */
659 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
660 {
661     DWORD ret;
662     SERVER_START_REQ( queue_apc )
663     {
664         req->handle = hthread;
665         req->user   = 1;
666         req->func   = func;
667         req->param  = (void *)data;
668         ret = !wine_server_call_err( req );
669     }
670     SERVER_END_REQ;
671     return ret;
672 }
673
674
675 /**********************************************************************
676  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
677  *
678  * NOTES
679  *    What are the fields where these values are stored?
680  *
681  * RETURNS
682  *    Success: TRUE
683  *    Failure: FALSE
684  */
685 BOOL WINAPI GetThreadTimes(
686     HANDLE thread,         /* [in]  Specifies the thread of interest */
687     LPFILETIME creationtime, /* [out] When the thread was created */
688     LPFILETIME exittime,     /* [out] When the thread was destroyed */
689     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
690     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
691 {
692     FIXME("(0x%08x): stub\n",thread);
693     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
694     return FALSE;
695 }
696
697
698 /**********************************************************************
699  * VWin32_BoostThreadGroup [KERNEL.535]
700  */
701 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
702 {
703     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
704 }
705
706 /**********************************************************************
707  * VWin32_BoostThreadStatic [KERNEL.536]
708  */
709 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
710 {
711     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
712 }
713
714
715 /***********************************************************************
716  *           GetThreadLocale    (KERNEL32.@)
717  */
718 LCID WINAPI GetThreadLocale(void)
719 {
720     LCID ret = NtCurrentTeb()->CurrentLocale;
721     if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
722     return ret;
723 }
724
725
726 /**********************************************************************
727  * SetThreadLocale [KERNEL32.@]  Sets the calling threads current locale.
728  *
729  * RETURNS
730  *    Success: TRUE
731  *    Failure: FALSE
732  *
733  * FIXME
734  *  check if lcid is a valid cp
735  */
736 BOOL WINAPI SetThreadLocale(
737     LCID lcid)     /* [in] Locale identifier */
738 {
739     switch (lcid)
740     {
741       case LOCALE_SYSTEM_DEFAULT:
742         lcid = GetSystemDefaultLCID();
743         break;
744       case LOCALE_USER_DEFAULT:
745       case LOCALE_NEUTRAL:
746         lcid = GetUserDefaultLCID();
747         break;
748     }
749     NtCurrentTeb()->CurrentLocale = lcid;
750     return TRUE;
751 }
752
753
754 /***********************************************************************
755  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
756  *
757  * RETURNS
758  *    Pseudohandle for the current thread
759  */
760 #undef GetCurrentThread
761 HANDLE WINAPI GetCurrentThread(void)
762 {
763     return 0xfffffffe;
764 }
765
766
767 /***********************************************************************
768  * ProcessIdToSessionId   (KERNEL32.@)
769  * This function is available on Terminal Server 4SP4 and Windows 2000
770  */
771 BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
772 {
773         /* According to MSDN, if the calling process is not in a terminal
774          * services environment, then the sessionid returned is zero.
775          */
776         *sessionid_ptr = 0;
777         return TRUE;
778 }
779
780 /***********************************************************************
781  * SetThreadExecutionState (KERNEL32.@)
782  *
783  * Informs the system that activity is taking place for
784  * power management purposes.
785  */
786 EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE flags)
787 {
788     static EXECUTION_STATE current =
789             ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_USER_PRESENT;
790     EXECUTION_STATE old = current;
791
792     if (!(current & ES_CONTINUOUS) || (flags & ES_CONTINUOUS))
793         current = flags;
794     FIXME("(0x%lx): stub, harmless (power management).\n", flags);
795     return old;
796 }
797
798
799 #ifdef __i386__
800
801 /***********************************************************************
802  *              SetLastError (KERNEL.147)
803  *              SetLastError (KERNEL32.@)
804  */
805 /* void WINAPI SetLastError( DWORD error ); */
806 __ASM_GLOBAL_FUNC( SetLastError,
807                    "movl 4(%esp),%eax\n\t"
808                    ".byte 0x64\n\t"
809                    "movl %eax,0x60\n\t"
810                    "ret $4" );
811
812 /***********************************************************************
813  *              GetLastError (KERNEL.148)
814  *              GetLastError (KERNEL32.@)
815  */
816 /* DWORD WINAPI GetLastError(void); */
817 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
818
819 /***********************************************************************
820  *              GetCurrentProcessId (KERNEL.471)
821  *              GetCurrentProcessId (KERNEL32.@)
822  */
823 /* DWORD WINAPI GetCurrentProcessId(void) */
824 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
825
826 /***********************************************************************
827  *              GetCurrentThreadId (KERNEL.462)
828  *              GetCurrentThreadId (KERNEL32.@)
829  */
830 /* DWORD WINAPI GetCurrentThreadId(void) */
831 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
832
833 #else  /* __i386__ */
834
835 /**********************************************************************
836  *              SetLastError (KERNEL.147)
837  *              SetLastError (KERNEL32.@)
838  *
839  * Sets the last-error code.
840  */
841 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
842 {
843     NtCurrentTeb()->last_error = error;
844 }
845
846 /**********************************************************************
847  *              GetLastError (KERNEL.148)
848  *              GetLastError (KERNEL32.@)
849  *
850  * Returns last-error code.
851  */
852 DWORD WINAPI GetLastError(void)
853 {
854     return NtCurrentTeb()->last_error;
855 }
856
857 /***********************************************************************
858  *              GetCurrentProcessId (KERNEL.471)
859  *              GetCurrentProcessId (KERNEL32.@)
860  *
861  * Returns process identifier.
862  */
863 DWORD WINAPI GetCurrentProcessId(void)
864 {
865     return (DWORD)NtCurrentTeb()->pid;
866 }
867
868 /***********************************************************************
869  *              GetCurrentThreadId (KERNEL.462)
870  *              GetCurrentThreadId (KERNEL32.@)
871  *
872  * Returns thread identifier.
873  */
874 DWORD WINAPI GetCurrentThreadId(void)
875 {
876     return (DWORD)NtCurrentTeb()->tid;
877 }
878
879 #endif  /* __i386__ */