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