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