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