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