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