Moved a bunch of routines to kernel32.dll (with the help of
[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 "thread.h"
18 #include "process.h"
19 #include "task.h"
20 #include "module.h"
21 #include "global.h"
22 #include "winerror.h"
23 #include "heap.h"
24 #include "selectors.h"
25 #include "winnt.h"
26 #include "server.h"
27 #include "services.h"
28 #include "stackframe.h"
29 #include "builtin16.h"
30 #include "debugtools.h"
31 #include "winnls.h"
32
33 DEFAULT_DEBUG_CHANNEL(thread);
34
35 /* TEB of the initial thread */
36 static TEB initial_teb;
37
38 /***********************************************************************
39  *           THREAD_IsWin16
40  */
41 BOOL THREAD_IsWin16( TEB *teb )
42 {
43     return !teb || !(teb->tibflags & TEBF_WIN32);
44 }
45
46 /***********************************************************************
47  *           THREAD_IdToTEB
48  *
49  * Convert a thread id to a TEB, making sure it is valid.
50  */
51 TEB *THREAD_IdToTEB( DWORD id )
52 {
53     TEB *ret = NULL;
54
55     if (!id || id == GetCurrentThreadId()) return NtCurrentTeb();
56
57     SERVER_START_REQ
58     {
59         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
60         req->handle = -1;
61         req->tid_in = (void *)id;
62         if (!server_call_noerr( REQ_GET_THREAD_INFO )) ret = req->teb;
63     }
64     SERVER_END_REQ;
65
66     if (!ret)
67     {
68         /* Allow task handles to be used; convert to main thread */
69         if ( IsTask16( id ) )
70         {
71             TDB *pTask = (TDB *)GlobalLock16( id );
72             if (pTask) return pTask->teb;
73         }
74         SetLastError( ERROR_INVALID_PARAMETER );
75     }
76     return ret;
77 }
78
79
80 /***********************************************************************
81  *           THREAD_InitTEB
82  *
83  * Initialization of a newly created TEB.
84  */
85 static BOOL THREAD_InitTEB( TEB *teb )
86 {
87     teb->except    = (void *)~0UL;
88     teb->self      = teb;
89     teb->tibflags  = TEBF_WIN32;
90     teb->tls_ptr   = teb->tls_array;
91     teb->exit_code = STILL_ACTIVE;
92     teb->socket    = -1;
93     teb->stack_top = (void *)~0UL;
94     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
95     teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
96     teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE );
97     return (teb->teb_sel != 0);
98 }
99
100
101 /***********************************************************************
102  *           THREAD_FreeTEB
103  *
104  * Free data structures associated with a thread.
105  * Must be called from the context of another thread.
106  */
107 static void CALLBACK THREAD_FreeTEB( TEB *teb )
108 {
109     TRACE("(%p) called\n", teb );
110     if (teb->cleanup) SERVICE_Delete( teb->cleanup );
111
112     /* Free the associated memory */
113
114     if (teb->socket != -1) close( teb->socket );
115     if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
116     SELECTOR_FreeBlock( teb->teb_sel, 1 );
117     if (teb->buffer) munmap( (void *)teb->buffer,
118                              (char *)(teb->buffer_info+1) - (char *)teb->buffer );
119     if (teb->debug_info) HeapFree( GetProcessHeap(), 0, teb->debug_info );
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, BOOL alloc_stack16 )
130 {
131     DWORD old_prot, total_size;
132     DWORD page_size = VIRTUAL_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      */
164
165     stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
166     total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
167     if (alloc_stack16) total_size += 0x10000;
168     if (!teb) total_size += page_size;
169
170     if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
171         return NULL;
172
173     if (!teb)
174     {
175         teb = (TEB *)((char *)base + total_size - page_size);
176         if (!THREAD_InitTEB( teb ))
177         {
178             VirtualFree( base, 0, MEM_RELEASE );
179             return NULL;
180         }
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     if (alloc_stack16)
198     {
199         teb->stack_sel = SELECTOR_AllocBlock( teb->stack_top, 0x10000, SEGMENT_DATA,
200                                               FALSE, FALSE );
201         if (!teb->stack_sel) goto error;
202         teb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( teb->stack_sel, 
203                                                 0x10000 - sizeof(STACK16FRAME) );
204     }
205     return teb;
206
207 error:
208     THREAD_FreeTEB( teb );
209     return NULL;
210 }
211
212
213 /***********************************************************************
214  *           THREAD_Init
215  *
216  * Setup the initial thread.
217  *
218  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
219  */
220 void THREAD_Init(void)
221 {
222     if (!initial_teb.self)  /* do it only once */
223     {
224         THREAD_InitTEB( &initial_teb );
225         assert( initial_teb.teb_sel );
226         initial_teb.process = &current_process;
227         SYSDEPS_SetCurThread( &initial_teb );
228     }
229 }
230
231 DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
232
233 /***********************************************************************
234  *           THREAD_Create
235  *
236  */
237 TEB *THREAD_Create( int fd, DWORD stack_size, BOOL alloc_stack16 )
238 {
239     TEB *teb;
240
241     if ((teb = THREAD_InitStack( NULL, stack_size, alloc_stack16 )))
242     {
243         teb->tibflags = (current_process.flags & PDB32_WIN16_PROC) ? 0 : TEBF_WIN32;
244         teb->process  = &current_process;
245         teb->socket   = fd;
246         fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
247         TRACE("(%p) succeeded\n", teb);
248     }
249     return teb;
250 }
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     HANDLE cleanup_object;
261     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)NtCurrentTeb()->entry_point;
262
263     /* install cleanup handler */
264     if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
265                          GetCurrentProcess(), &cleanup_object, 
266                          0, FALSE, DUPLICATE_SAME_ACCESS ))
267         NtCurrentTeb()->cleanup = SERVICE_AddObject( cleanup_object, (PAPCFUNC)THREAD_FreeTEB,
268                                                      (ULONG_PTR)NtCurrentTeb() );
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.63)
279  */
280 HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
281                             LPTHREAD_START_ROUTINE start, LPVOID param,
282                             DWORD flags, LPDWORD id )
283 {
284     int socket, handle = -1;
285     TEB *teb;
286     void *tid = 0;
287
288     SERVER_START_REQ
289     {
290         struct new_thread_request *req = server_alloc_req( sizeof(*req), 0 );
291
292         req->suspend = ((flags & CREATE_SUSPENDED) != 0);
293         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
294         if (!server_call_fd( REQ_NEW_THREAD, -1, &socket ))
295         {
296             handle = req->handle;
297             tid = req->tid;
298         }
299     }
300     SERVER_END_REQ;
301     if (handle == -1) return 0;
302
303     if (!(teb = THREAD_Create( socket, stack, TRUE )))
304     {
305         close( socket );
306         return 0;
307     }
308     teb->tibflags   |= TEBF_WIN32;
309     teb->entry_point = start;
310     teb->entry_arg   = param;
311     teb->startup     = THREAD_Start;
312     teb->htask16     = GetCurrentTask();
313     if (id) *id = (DWORD)tid;
314     if (SYSDEPS_SpawnThread( teb ) == -1)
315     {
316         CloseHandle( handle );
317         THREAD_FreeTEB( teb );
318         return 0;
319     }
320     return handle;
321 }
322
323 /***********************************************************************
324  *           CreateThread16   (KERNEL.441)
325  */
326 static DWORD CALLBACK THREAD_StartThread16( LPVOID threadArgs )
327 {
328     FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
329     DWORD     param = ((DWORD *)threadArgs)[1];
330     HeapFree( GetProcessHeap(), 0, threadArgs );
331
332     ((LPDWORD)CURRENT_STACK16)[-1] = param;
333     return CallTo16Long( start, sizeof(DWORD) );
334 }
335 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
336                               FARPROC16 start, SEGPTR param,
337                               DWORD flags, LPDWORD id )
338 {
339     DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
340     if (!threadArgs) return INVALID_HANDLE_VALUE;
341     threadArgs[0] = (DWORD)start;
342     threadArgs[1] = (DWORD)param;
343
344     return CreateThread( sa, stack, THREAD_StartThread16, threadArgs, flags, id );
345 }
346
347
348 /***********************************************************************
349  * ExitThread [KERNEL32.215]  Ends a thread
350  *
351  * RETURNS
352  *    None
353  */
354 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
355 {
356     BOOL last;
357     SERVER_START_REQ
358     {
359         struct terminate_thread_request *req = server_alloc_req( sizeof(*req), 0 );
360
361         /* send the exit code to the server */
362         req->handle    = GetCurrentThread();
363         req->exit_code = code;
364         server_call( REQ_TERMINATE_THREAD );
365         last = req->last;
366     }
367     SERVER_END_REQ;
368
369     if (last)
370     {
371         MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
372         exit( code );
373     }
374     else
375     {
376         MODULE_DllThreadDetach( NULL );
377         if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_KillTask( 0 );
378         SYSDEPS_ExitThread( code );
379     }
380 }
381
382
383 /**********************************************************************
384  * TlsAlloc [KERNEL32.530]  Allocates a TLS index.
385  *
386  * Allocates a thread local storage index
387  *
388  * RETURNS
389  *    Success: TLS Index
390  *    Failure: 0xFFFFFFFF
391  */
392 DWORD WINAPI TlsAlloc( void )
393 {
394     DWORD i, mask, ret = 0;
395     DWORD *bits = current_process.tls_bits;
396     EnterCriticalSection( &current_process.crit_section );
397     if (*bits == 0xffffffff)
398     {
399         bits++;
400         ret = 32;
401         if (*bits == 0xffffffff)
402         {
403             LeaveCriticalSection( &current_process.crit_section );
404             SetLastError( ERROR_NO_MORE_ITEMS );
405             return 0xffffffff;
406         }
407     }
408     for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
409     *bits |= mask;
410     LeaveCriticalSection( &current_process.crit_section );
411     return ret + i;
412 }
413
414
415 /**********************************************************************
416  * TlsFree [KERNEL32.531]  Releases a TLS index.
417  *
418  * Releases a thread local storage index, making it available for reuse
419  * 
420  * RETURNS
421  *    Success: TRUE
422  *    Failure: FALSE
423  */
424 BOOL WINAPI TlsFree(
425     DWORD index) /* [in] TLS Index to free */
426 {
427     DWORD mask;
428     DWORD *bits = current_process.tls_bits;
429     if (index >= 64)
430     {
431         SetLastError( ERROR_INVALID_PARAMETER );
432         return FALSE;
433     }
434     EnterCriticalSection( &current_process.crit_section );
435     if (index >= 32) bits++;
436     mask = (1 << (index & 31));
437     if (!(*bits & mask))  /* already free? */
438     {
439         LeaveCriticalSection( &current_process.crit_section );
440         SetLastError( ERROR_INVALID_PARAMETER );
441         return FALSE;
442     }
443     *bits &= ~mask;
444     NtCurrentTeb()->tls_array[index] = 0;
445     /* FIXME: should zero all other thread values */
446     LeaveCriticalSection( &current_process.crit_section );
447     return TRUE;
448 }
449
450
451 /**********************************************************************
452  * TlsGetValue [KERNEL32.532]  Gets value in a thread's TLS slot
453  *
454  * RETURNS
455  *    Success: Value stored in calling thread's TLS slot for index
456  *    Failure: 0 and GetLastError returns NO_ERROR
457  */
458 LPVOID WINAPI TlsGetValue(
459     DWORD index) /* [in] TLS index to retrieve value for */
460 {
461     if (index >= 64)
462     {
463         SetLastError( ERROR_INVALID_PARAMETER );
464         return NULL;
465     }
466     SetLastError( ERROR_SUCCESS );
467     return NtCurrentTeb()->tls_array[index];
468 }
469
470
471 /**********************************************************************
472  * TlsSetValue [KERNEL32.533]  Stores a value in the thread's TLS slot.
473  *
474  * RETURNS
475  *    Success: TRUE
476  *    Failure: FALSE
477  */
478 BOOL WINAPI TlsSetValue(
479     DWORD index,  /* [in] TLS index to set value for */
480     LPVOID value) /* [in] Value to be stored */
481 {
482     if (index >= 64)
483     {
484         SetLastError( ERROR_INVALID_PARAMETER );
485         return FALSE;
486     }
487     NtCurrentTeb()->tls_array[index] = value;
488     return TRUE;
489 }
490
491
492 /***********************************************************************
493  * SetThreadContext [KERNEL32.670]  Sets context of thread.
494  *
495  * RETURNS
496  *    Success: TRUE
497  *    Failure: FALSE
498  */
499 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
500                               const CONTEXT *context ) /* [in] Address of context structure */
501 {
502     BOOL ret;
503     SERVER_START_REQ
504     {
505         struct set_thread_context_request *req = server_alloc_req( sizeof(*req),
506                                                                    sizeof(*context) );
507         req->handle = handle;
508         req->flags = context->ContextFlags;
509         memcpy( server_data_ptr(req), context, sizeof(*context) );
510         ret = !server_call( REQ_SET_THREAD_CONTEXT );
511     }
512     SERVER_END_REQ;
513     return ret;
514 }
515
516
517 /***********************************************************************
518  * GetThreadContext [KERNEL32.294]  Retrieves context of thread.
519  *
520  * RETURNS
521  *    Success: TRUE
522  *    Failure: FALSE
523  */
524 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
525                               CONTEXT *context ) /* [out] Address of context structure */
526 {
527     BOOL ret;
528     SERVER_START_REQ
529     {
530         struct get_thread_context_request *req = server_alloc_req( sizeof(*req),
531                                                                    sizeof(*context) );
532         req->handle = handle;
533         req->flags = context->ContextFlags;
534         memcpy( server_data_ptr(req), context, sizeof(*context) );
535         if ((ret = !server_call( REQ_GET_THREAD_CONTEXT )))
536             memcpy( context, server_data_ptr(req), sizeof(*context) );
537     }
538     SERVER_END_REQ;
539     return ret;
540 }
541
542
543 /**********************************************************************
544  * GetThreadPriority [KERNEL32.296]  Returns priority for thread.
545  *
546  * RETURNS
547  *    Success: Thread's priority level.
548  *    Failure: THREAD_PRIORITY_ERROR_RETURN
549  */
550 INT WINAPI GetThreadPriority(
551     HANDLE hthread) /* [in] Handle to thread */
552 {
553     INT ret = THREAD_PRIORITY_ERROR_RETURN;
554     SERVER_START_REQ
555     {
556         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
557         req->handle = hthread;
558         req->tid_in = 0;
559         if (!server_call( REQ_GET_THREAD_INFO )) ret = req->priority;
560     }
561     SERVER_END_REQ;
562     return ret;
563 }
564
565
566 /**********************************************************************
567  * SetThreadPriority [KERNEL32.514]  Sets priority for thread.
568  *
569  * RETURNS
570  *    Success: TRUE
571  *    Failure: FALSE
572  */
573 BOOL WINAPI SetThreadPriority(
574     HANDLE hthread, /* [in] Handle to thread */
575     INT priority)   /* [in] Thread priority level */
576 {
577     BOOL ret;
578     SERVER_START_REQ
579     {
580         struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
581         req->handle   = hthread;
582         req->priority = priority;
583         req->mask     = SET_THREAD_INFO_PRIORITY;
584         ret = !server_call( REQ_SET_THREAD_INFO );
585     }
586     SERVER_END_REQ;
587     return ret;
588 }
589
590
591 /**********************************************************************
592  * GetThreadPriorityBoost [KERNEL32.877]  Returns priority boost for thread.
593  *
594  * Always reports that priority boost is disabled.
595  *
596  * RETURNS
597  *    Success: TRUE.
598  *    Failure: FALSE
599  */
600 BOOL WINAPI GetThreadPriorityBoost(
601     HANDLE hthread, /* [in] Handle to thread */
602     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
603 {
604     if (pstate) *pstate = FALSE;
605     return NO_ERROR;
606 }
607
608
609 /**********************************************************************
610  * SetThreadPriorityBoost [KERNEL32.893]  Sets priority boost for thread.
611  *
612  * Priority boost is not implemented. Thsi function always returns 
613  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
614  *
615  * RETURNS
616  *    Always returns FALSE to indicate a failure 
617  */
618 BOOL WINAPI SetThreadPriorityBoost(
619     HANDLE hthread, /* [in] Handle to thread */
620     BOOL disable)   /* [in] TRUE to disable priority boost */
621 {
622     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
623     return FALSE;
624 }
625
626
627 /**********************************************************************
628  *           SetThreadAffinityMask   (KERNEL32.669)
629  */
630 DWORD WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD dwThreadAffinityMask )
631 {
632     DWORD ret;
633     SERVER_START_REQ
634     {
635         struct set_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
636         req->handle   = hThread;
637         req->affinity = dwThreadAffinityMask;
638         req->mask     = SET_THREAD_INFO_AFFINITY;
639         ret = !server_call( REQ_SET_THREAD_INFO );
640         /* FIXME: should return previous value */
641     }
642     SERVER_END_REQ;
643     return ret;
644 }
645
646
647 /**********************************************************************
648  * TerminateThread [KERNEL32.685]  Terminates a thread
649  *
650  * RETURNS
651  *    Success: TRUE
652  *    Failure: FALSE
653  */
654 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
655                              DWORD exit_code)  /* [in] Exit code for thread */
656 {
657     NTSTATUS status = NtTerminateThread( handle, exit_code );
658     if (status) SetLastError( RtlNtStatusToDosError(status) );
659     return !status;
660 }
661
662
663 /**********************************************************************
664  * GetExitCodeThread [KERNEL32.???]  Gets termination status of thread.
665  * 
666  * RETURNS
667  *    Success: TRUE
668  *    Failure: FALSE
669  */
670 BOOL WINAPI GetExitCodeThread(
671     HANDLE hthread, /* [in]  Handle to thread */
672     LPDWORD exitcode) /* [out] Address to receive termination status */
673 {
674     BOOL ret;
675     SERVER_START_REQ
676     {
677         struct get_thread_info_request *req = server_alloc_req( sizeof(*req), 0 );
678         req->handle = hthread;
679         req->tid_in = 0;
680         ret = !server_call( REQ_GET_THREAD_INFO );
681         if (ret && exitcode) *exitcode = req->exit_code;
682     }
683     SERVER_END_REQ;
684     return ret;
685 }
686
687
688 /**********************************************************************
689  * ResumeThread [KERNEL32.587]  Resumes a thread.
690  *
691  * Decrements a thread's suspend count.  When count is zero, the
692  * execution of the thread is resumed.
693  *
694  * RETURNS
695  *    Success: Previous suspend count
696  *    Failure: 0xFFFFFFFF
697  *    Already running: 0
698  */
699 DWORD WINAPI ResumeThread(
700     HANDLE hthread) /* [in] Identifies thread to restart */
701 {
702     DWORD ret = 0xffffffff;
703     SERVER_START_REQ
704     {
705         struct resume_thread_request *req = server_alloc_req( sizeof(*req), 0 );
706         req->handle = hthread;
707         if (!server_call( REQ_RESUME_THREAD )) ret = req->count;
708     }
709     SERVER_END_REQ;
710     return ret;
711 }
712
713
714 /**********************************************************************
715  * SuspendThread [KERNEL32.681]  Suspends a thread.
716  *
717  * RETURNS
718  *    Success: Previous suspend count
719  *    Failure: 0xFFFFFFFF
720  */
721 DWORD WINAPI SuspendThread(
722     HANDLE hthread) /* [in] Handle to the thread */
723 {
724     DWORD ret = 0xffffffff;
725     SERVER_START_REQ
726     {
727         struct suspend_thread_request *req = server_alloc_req( sizeof(*req), 0 );
728         req->handle = hthread;
729         if (!server_call( REQ_SUSPEND_THREAD )) ret = req->count;
730     }
731     SERVER_END_REQ;
732     return ret;
733 }
734
735
736 /***********************************************************************
737  *              QueueUserAPC  (KERNEL32.566)
738  */
739 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
740 {
741     DWORD ret;
742     SERVER_START_REQ
743     {
744         struct queue_apc_request *req = server_alloc_req( sizeof(*req), 0 );
745         req->handle = hthread;
746         req->func   = func;
747         req->param  = (void *)data;
748         ret = !server_call( REQ_QUEUE_APC );
749     }
750     SERVER_END_REQ;
751     return ret;
752 }
753
754
755 /**********************************************************************
756  * GetThreadTimes [KERNEL32.???]  Obtains timing information.
757  *
758  * NOTES
759  *    What are the fields where these values are stored?
760  *
761  * RETURNS
762  *    Success: TRUE
763  *    Failure: FALSE
764  */
765 BOOL WINAPI GetThreadTimes( 
766     HANDLE thread,         /* [in]  Specifies the thread of interest */
767     LPFILETIME creationtime, /* [out] When the thread was created */
768     LPFILETIME exittime,     /* [out] When the thread was destroyed */
769     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
770     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
771 {
772     FIXME("(0x%08x): stub\n",thread);
773     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
774     return FALSE;
775 }
776
777
778 /**********************************************************************
779  * VWin32_BoostThreadGroup [KERNEL.535]
780  */
781 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
782 {
783     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
784 }
785
786 /**********************************************************************
787  * VWin32_BoostThreadStatic [KERNEL.536]
788  */
789 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
790 {
791     FIXME("(0x%08lx,%d): stub\n", threadId, boost);
792 }
793
794
795 /***********************************************************************
796  *           GetThreadLocale    (KERNEL32.295)
797  */
798 LCID WINAPI GetThreadLocale(void)
799 {
800     LCID ret = NtCurrentTeb()->CurrentLocale;
801     if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
802     return ret;
803 }
804
805
806 /**********************************************************************
807  * SetThreadLocale [KERNEL32.671]  Sets the calling threads current locale.
808  *
809  * RETURNS
810  *    Success: TRUE
811  *    Failure: FALSE
812  *
813  * FIXME
814  *  check if lcid is a valid cp
815  */
816 BOOL WINAPI SetThreadLocale(
817     LCID lcid)     /* [in] Locale identifier */
818 {
819     switch (lcid)
820     {
821       case LOCALE_SYSTEM_DEFAULT:
822         lcid = GetSystemDefaultLCID();
823         break;
824       case LOCALE_USER_DEFAULT:
825       case LOCALE_NEUTRAL:
826         lcid = GetUserDefaultLCID();
827         break;
828     }
829     NtCurrentTeb()->CurrentLocale = lcid;
830     return TRUE;
831 }
832
833
834 /***********************************************************************
835  * GetCurrentThread [KERNEL32.200]  Gets pseudohandle for current thread
836  *
837  * RETURNS
838  *    Pseudohandle for the current thread
839  */
840 #undef GetCurrentThread
841 HANDLE WINAPI GetCurrentThread(void)
842 {
843     return 0xfffffffe;
844 }
845
846
847 #ifdef __i386__
848
849 /* void WINAPI SetLastError( DWORD error ); */
850 __ASM_GLOBAL_FUNC( SetLastError,
851                    "movl 4(%esp),%eax\n\t"
852                    ".byte 0x64\n\t"
853                    "movl %eax,0x60\n\t"
854                    "ret $4" );
855
856 /* DWORD WINAPI GetLastError(void); */
857 __ASM_GLOBAL_FUNC( GetLastError, ".byte 0x64\n\tmovl 0x60,%eax\n\tret" );
858
859 /* DWORD WINAPI GetCurrentProcessId(void) */
860 __ASM_GLOBAL_FUNC( GetCurrentProcessId, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" );
861                    
862 /* DWORD WINAPI GetCurrentThreadId(void) */
863 __ASM_GLOBAL_FUNC( GetCurrentThreadId, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" );
864                    
865 #else  /* __i386__ */
866
867 /**********************************************************************
868  * SetLastError [KERNEL.147] [KERNEL32.497]  Sets the last-error code.
869  */
870 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
871 {
872     NtCurrentTeb()->last_error = error;
873 }
874
875 /**********************************************************************
876  * GetLastError [KERNEL.148] [KERNEL32.227]  Returns last-error code.
877  */
878 DWORD WINAPI GetLastError(void)
879 {
880     return NtCurrentTeb()->last_error;
881 }
882
883 /***********************************************************************
884  * GetCurrentProcessId [KERNEL32.199]  Returns process identifier.
885  */
886 DWORD WINAPI GetCurrentProcessId(void)
887 {
888     return (DWORD)NtCurrentTeb()->pid;
889 }
890
891 /***********************************************************************
892  * GetCurrentThreadId [KERNEL32.201]  Returns thread identifier.
893  */
894 DWORD WINAPI GetCurrentThreadId(void)
895 {
896     return (DWORD)NtCurrentTeb()->tid;
897 }
898
899 #endif  /* __i386__ */