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