msvcrt: Add a helper function to flush all buffers.
[wine] / dlls / kernel32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winternl.h"
38 #include "wine/exception.h"
39 #include "wine/library.h"
40 #include "wine/server.h"
41 #include "wine/debug.h"
42
43 #include "kernel_private.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(thread);
46
47
48 /***********************************************************************
49  *           CreateThread   (KERNEL32.@)
50  */
51 HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack, LPTHREAD_START_ROUTINE start,
52                                               LPVOID param, DWORD flags, LPDWORD id )
53 {
54      return CreateRemoteThread( GetCurrentProcess(),
55                                 sa, stack, start, param, flags, id );
56 }
57
58
59 /***************************************************************************
60  *                  CreateRemoteThread   (KERNEL32.@)
61  *
62  * Creates a thread that runs in the address space of another process
63  *
64  * PARAMS
65  *
66  * RETURNS
67  *   Success: Handle to the new thread.
68  *   Failure: NULL. Use GetLastError() to find the error cause.
69  *
70  * BUGS
71  *   Improper memory allocation: there's no ability to free new_thread_info
72  *   in other process.
73  *   Bad start address for RtlCreateUserThread because the library
74  *   may be loaded at different address in other process.
75  */
76 HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
77                                   LPTHREAD_START_ROUTINE start, LPVOID param,
78                                   DWORD flags, LPDWORD id )
79 {
80     HANDLE handle;
81     CLIENT_ID client_id;
82     NTSTATUS status;
83     SIZE_T stack_reserve = 0, stack_commit = 0;
84
85     if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
86     else stack_commit = stack;
87
88     status = RtlCreateUserThread( hProcess, NULL, TRUE,
89                                   NULL, stack_reserve, stack_commit,
90                                   (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id );
91     if (status == STATUS_SUCCESS)
92     {
93         if (id) *id = HandleToULong(client_id.UniqueThread);
94         if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
95             SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
96         if (!(flags & CREATE_SUSPENDED))
97         {
98             ULONG ret;
99             if (NtResumeThread( handle, &ret ))
100             {
101                 NtClose( handle );
102                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
103                 handle = 0;
104             }
105         }
106     }
107     else
108     {
109         SetLastError( RtlNtStatusToDosError(status) );
110         handle = 0;
111     }
112     return handle;
113 }
114
115
116 /***********************************************************************
117  * OpenThread  [KERNEL32.@]   Retrieves a handle to a thread from its thread id
118  */
119 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
120 {
121     NTSTATUS status;
122     HANDLE handle;
123     OBJECT_ATTRIBUTES attr;
124     CLIENT_ID cid;
125
126     attr.Length = sizeof(attr);
127     attr.RootDirectory = 0;
128     attr.Attributes = bInheritHandle ? OBJ_INHERIT : 0;
129     attr.ObjectName = NULL;
130     attr.SecurityDescriptor = NULL;
131     attr.SecurityQualityOfService = NULL;
132
133     cid.UniqueProcess = 0; /* FIXME */
134     cid.UniqueThread = ULongToHandle(dwThreadId);
135     status = NtOpenThread( &handle, dwDesiredAccess, &attr, &cid );
136     if (status)
137     {
138         SetLastError( RtlNtStatusToDosError(status) );
139         handle = 0;
140     }
141     return handle;
142 }
143
144
145 /***********************************************************************
146  * ExitThread [KERNEL32.@]  Ends a thread
147  *
148  * RETURNS
149  *    None
150  */
151 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
152 {
153     RtlFreeThreadActivationContextStack();
154     RtlExitUserThread( code );
155 }
156
157
158 /**********************************************************************
159  * TerminateThread [KERNEL32.@]  Terminates a thread
160  *
161  * RETURNS
162  *    Success: TRUE
163  *    Failure: FALSE
164  */
165 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
166                              DWORD exit_code)  /* [in] Exit code for thread */
167 {
168     NTSTATUS status = NtTerminateThread( handle, exit_code );
169     if (status) SetLastError( RtlNtStatusToDosError(status) );
170     return !status;
171 }
172
173
174 /***********************************************************************
175  *           FreeLibraryAndExitThread (KERNEL32.@)
176  */
177 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
178 {
179     FreeLibrary(hLibModule);
180     ExitThread(dwExitCode);
181 }
182
183
184 /**********************************************************************
185  *              GetExitCodeThread (KERNEL32.@)
186  *
187  * Gets termination status of thread.
188  *
189  * RETURNS
190  *    Success: TRUE
191  *    Failure: FALSE
192  */
193 BOOL WINAPI GetExitCodeThread(
194     HANDLE hthread, /* [in]  Handle to thread */
195     LPDWORD exitcode) /* [out] Address to receive termination status */
196 {
197     THREAD_BASIC_INFORMATION info;
198     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
199                                                 &info, sizeof(info), NULL );
200
201     if (status)
202     {
203         SetLastError( RtlNtStatusToDosError(status) );
204         return FALSE;
205     }
206     if (exitcode) *exitcode = info.ExitStatus;
207     return TRUE;
208 }
209
210
211 /***********************************************************************
212  * SetThreadContext [KERNEL32.@]  Sets context of thread.
213  *
214  * RETURNS
215  *    Success: TRUE
216  *    Failure: FALSE
217  */
218 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
219                               const CONTEXT *context ) /* [in] Address of context structure */
220 {
221     NTSTATUS status = NtSetContextThread( handle, context );
222     if (status) SetLastError( RtlNtStatusToDosError(status) );
223     return !status;
224 }
225
226
227 /***********************************************************************
228  * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
229  *
230  * RETURNS
231  *    Success: TRUE
232  *    Failure: FALSE
233  */
234 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
235                               CONTEXT *context ) /* [out] Address of context structure */
236 {
237     NTSTATUS status = NtGetContextThread( handle, context );
238     if (status) SetLastError( RtlNtStatusToDosError(status) );
239     return !status;
240 }
241
242
243 /**********************************************************************
244  * SuspendThread [KERNEL32.@]  Suspends a thread.
245  *
246  * RETURNS
247  *    Success: Previous suspend count
248  *    Failure: 0xFFFFFFFF
249  */
250 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
251 {
252     DWORD ret;
253     NTSTATUS status = NtSuspendThread( hthread, &ret );
254
255     if (status)
256     {
257         ret = ~0U;
258         SetLastError( RtlNtStatusToDosError(status) );
259     }
260     return ret;
261 }
262
263
264 /**********************************************************************
265  * ResumeThread [KERNEL32.@]  Resumes a thread.
266  *
267  * Decrements a thread's suspend count.  When count is zero, the
268  * execution of the thread is resumed.
269  *
270  * RETURNS
271  *    Success: Previous suspend count
272  *    Failure: 0xFFFFFFFF
273  *    Already running: 0
274  */
275 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
276 {
277     DWORD ret;
278     NTSTATUS status = NtResumeThread( hthread, &ret );
279
280     if (status)
281     {
282         ret = ~0U;
283         SetLastError( RtlNtStatusToDosError(status) );
284     }
285     return ret;
286 }
287
288
289 /**********************************************************************
290  * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
291  *
292  * RETURNS
293  *    Success: Thread's priority level.
294  *    Failure: THREAD_PRIORITY_ERROR_RETURN
295  */
296 INT WINAPI GetThreadPriority(
297     HANDLE hthread) /* [in] Handle to thread */
298 {
299     THREAD_BASIC_INFORMATION info;
300     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
301                                                 &info, sizeof(info), NULL );
302
303     if (status)
304     {
305         SetLastError( RtlNtStatusToDosError(status) );
306         return THREAD_PRIORITY_ERROR_RETURN;
307     }
308     return info.Priority;
309 }
310
311
312 /**********************************************************************
313  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
314  *
315  * RETURNS
316  *    Success: TRUE
317  *    Failure: FALSE
318  */
319 BOOL WINAPI SetThreadPriority(
320     HANDLE hthread, /* [in] Handle to thread */
321     INT priority)   /* [in] Thread priority level */
322 {
323     DWORD       prio = priority;
324     NTSTATUS    status;
325
326     status = NtSetInformationThread(hthread, ThreadBasePriority,
327                                     &prio, sizeof(prio));
328
329     if (status)
330     {
331         SetLastError( RtlNtStatusToDosError(status) );
332         return FALSE;
333     }
334
335     return TRUE;
336 }
337
338
339 /**********************************************************************
340  * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
341  *
342  * Always reports that priority boost is disabled.
343  *
344  * RETURNS
345  *    Success: TRUE.
346  *    Failure: FALSE
347  */
348 BOOL WINAPI GetThreadPriorityBoost(
349     HANDLE hthread, /* [in] Handle to thread */
350     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
351 {
352     if (pstate) *pstate = FALSE;
353     return TRUE;
354 }
355
356
357 /**********************************************************************
358  * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
359  *
360  * Priority boost is not implemented. This function always returns
361  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
362  *
363  * RETURNS
364  *    Always returns FALSE to indicate a failure
365  */
366 BOOL WINAPI SetThreadPriorityBoost(
367     HANDLE hthread, /* [in] Handle to thread */
368     BOOL disable)   /* [in] TRUE to disable priority boost */
369 {
370     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
371     return FALSE;
372 }
373
374
375 /**********************************************************************
376  *           SetThreadAffinityMask   (KERNEL32.@)
377  */
378 DWORD_PTR WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask )
379 {
380     NTSTATUS                    status;
381     THREAD_BASIC_INFORMATION    tbi;
382
383     status = NtQueryInformationThread( hThread, ThreadBasicInformation, 
384                                        &tbi, sizeof(tbi), NULL );
385     if (status)
386     {
387         SetLastError( RtlNtStatusToDosError(status) );
388         return 0;
389     }
390     status = NtSetInformationThread( hThread, ThreadAffinityMask, 
391                                      &dwThreadAffinityMask,
392                                      sizeof(dwThreadAffinityMask));
393     if (status)
394     {
395         SetLastError( RtlNtStatusToDosError(status) );
396         return 0;
397     }
398     return tbi.AffinityMask;
399 }
400
401
402 /**********************************************************************
403  * SetThreadIdealProcessor [KERNEL32.@]  Sets preferred processor for thread.
404  *
405  * RETURNS
406  *    Success: Value of last call to SetThreadIdealProcessor
407  *    Failure: -1
408  */
409 DWORD WINAPI SetThreadIdealProcessor(
410     HANDLE hThread,          /* [in] Specifies the thread of interest */
411     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
412 {
413     FIXME("(%p): stub\n",hThread);
414     if (dwIdealProcessor > MAXIMUM_PROCESSORS)
415     {
416         SetLastError(ERROR_INVALID_PARAMETER);
417         return ~0u;
418     }
419     return 0;
420 }
421
422
423 /***********************************************************************
424  *           GetThreadSelectorEntry   (KERNEL32.@)
425  */
426 BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent )
427 {
428     THREAD_DESCRIPTOR_INFORMATION tdi;
429     NTSTATUS status;
430
431     tdi.Selector = sel;
432     status = NtQueryInformationThread( hthread, ThreadDescriptorTableEntry, &tdi, sizeof(tdi), NULL);
433     if (status)
434     {
435         SetLastError( RtlNtStatusToDosError(status) );
436         return FALSE;
437     }
438     *ldtent = tdi.Entry;
439     return TRUE;
440 }
441
442
443 /* callback for QueueUserAPC */
444 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
445 {
446     PAPCFUNC func = (PAPCFUNC)arg1;
447     func( arg2 );
448 }
449
450 /***********************************************************************
451  *              QueueUserAPC  (KERNEL32.@)
452  */
453 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
454 {
455     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
456
457     if (status) SetLastError( RtlNtStatusToDosError(status) );
458     return !status;
459 }
460
461 /***********************************************************************
462  *              QueueUserWorkItem  (KERNEL32.@)
463  */
464 BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
465 {
466     NTSTATUS status;
467
468     TRACE("(%p,%p,0x%08x)\n", Function, Context, Flags);
469
470     status = RtlQueueWorkItem( Function, Context, Flags );
471
472     if (status) SetLastError( RtlNtStatusToDosError(status) );
473     return !status;
474 }
475
476 /**********************************************************************
477  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
478  *
479  * RETURNS
480  *    Success: TRUE
481  *    Failure: FALSE
482  */
483 BOOL WINAPI GetThreadTimes(
484     HANDLE thread,         /* [in]  Specifies the thread of interest */
485     LPFILETIME creationtime, /* [out] When the thread was created */
486     LPFILETIME exittime,     /* [out] When the thread was destroyed */
487     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
488     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
489 {
490     KERNEL_USER_TIMES   kusrt;
491     NTSTATUS            status;
492
493     status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
494                                       sizeof(kusrt), NULL);
495     if (status)
496     {
497         SetLastError( RtlNtStatusToDosError(status) );
498         return FALSE;
499     }
500     if (creationtime)
501     {
502         creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
503         creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
504     }
505     if (exittime)
506     {
507         exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
508         exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
509     }
510     if (kerneltime)
511     {
512         kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
513         kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
514     }
515     if (usertime)
516     {
517         usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
518         usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
519     }
520     
521     return TRUE;
522 }
523
524 /**********************************************************************
525  * GetThreadId [KERNEL32.@]
526  *
527  * Retrieve the identifier of a thread.
528  *
529  * PARAMS
530  *  Thread [I] The thread to retrieve the identifier of.
531  *
532  * RETURNS
533  *    Success: Identifier of the target thread.
534  *    Failure: 0
535  */
536 DWORD WINAPI GetThreadId(HANDLE Thread)
537 {
538     THREAD_BASIC_INFORMATION tbi;
539     NTSTATUS status;
540
541     TRACE("(%p)\n", Thread);
542
543     status = NtQueryInformationThread(Thread, ThreadBasicInformation, &tbi,
544                                       sizeof(tbi), NULL);
545     if (status)
546     {
547         SetLastError( RtlNtStatusToDosError(status) );
548         return 0;
549     }
550
551     return HandleToULong(tbi.ClientId.UniqueThread);
552 }
553
554
555 /***********************************************************************
556  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
557  *
558  * RETURNS
559  *    Pseudohandle for the current thread
560  */
561 #undef GetCurrentThread
562 HANDLE WINAPI GetCurrentThread(void)
563 {
564     return (HANDLE)~(ULONG_PTR)1;
565 }
566
567
568 #ifdef __i386__
569
570 /***********************************************************************
571  *              SetLastError (KERNEL32.@)
572  */
573 /* void WINAPI SetLastError( DWORD error ); */
574 __ASM_STDCALL_FUNC( SetLastError, 4,
575                    "movl 4(%esp),%eax\n\t"
576                    ".byte 0x64\n\t"
577                    "movl %eax,0x34\n\t"
578                    "ret $4" )
579
580 /***********************************************************************
581  *              GetLastError (KERNEL32.@)
582  */
583 /* DWORD WINAPI GetLastError(void); */
584 __ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
585
586 /***********************************************************************
587  *              GetCurrentProcessId (KERNEL32.@)
588  */
589 /* DWORD WINAPI GetCurrentProcessId(void) */
590 __ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
591
592 /***********************************************************************
593  *              GetCurrentThreadId (KERNEL32.@)
594  */
595 /* DWORD WINAPI GetCurrentThreadId(void) */
596 __ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
597
598 /***********************************************************************
599  *              GetProcessHeap (KERNEL32.@)
600  */
601 /* HANDLE WINAPI GetProcessHeap(void) */
602 __ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x64\n\tmovl 0x30,%eax\n\tmovl 0x18(%eax),%eax\n\tret");
603
604 #elif defined(__x86_64__)
605
606 /***********************************************************************
607  *              SetLastError (KERNEL32.@)
608  */
609 /* void WINAPI SetLastError( DWORD error ); */
610 __ASM_STDCALL_FUNC( SetLastError, 8, ".byte 0x65\n\tmovl %ecx,0x68\n\tret" );
611
612 /***********************************************************************
613  *              GetLastError (KERNEL32.@)
614  */
615 /* DWORD WINAPI GetLastError(void); */
616 __ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x65\n\tmovl 0x68,%eax\n\tret" );
617
618 /***********************************************************************
619  *              GetCurrentProcessId (KERNEL32.@)
620  */
621 /* DWORD WINAPI GetCurrentProcessId(void) */
622 __ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x65\n\tmovl 0x40,%eax\n\tret" );
623
624 /***********************************************************************
625  *              GetCurrentThreadId (KERNEL32.@)
626  */
627 /* DWORD WINAPI GetCurrentThreadId(void) */
628 __ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x65\n\tmovl 0x48,%eax\n\tret" );
629
630 /***********************************************************************
631  *              GetProcessHeap (KERNEL32.@)
632  */
633 /* HANDLE WINAPI GetProcessHeap(void) */
634 __ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x65\n\tmovq 0x60,%rax\n\tmovq 0x30(%rax),%rax\n\tret");
635
636 #else  /* __x86_64__ */
637
638 /**********************************************************************
639  *              SetLastError (KERNEL32.@)
640  *
641  * Sets the last-error code.
642  *
643  * RETURNS
644  * Nothing.
645  */
646 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
647 {
648     NtCurrentTeb()->LastErrorValue = error;
649 }
650
651 /**********************************************************************
652  *              GetLastError (KERNEL32.@)
653  *
654  * Get the last-error code.
655  *
656  * RETURNS
657  *  last-error code.
658  */
659 DWORD WINAPI GetLastError(void)
660 {
661     return NtCurrentTeb()->LastErrorValue;
662 }
663
664 /***********************************************************************
665  *              GetCurrentProcessId (KERNEL32.@)
666  *
667  * Get the current process identifier.
668  *
669  * RETURNS
670  *  current process identifier
671  */
672 DWORD WINAPI GetCurrentProcessId(void)
673 {
674     return HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess);
675 }
676
677 /***********************************************************************
678  *              GetCurrentThreadId (KERNEL32.@)
679  *
680  * Get the current thread identifier.
681  *
682  * RETURNS
683  *  current thread identifier
684  */
685 DWORD WINAPI GetCurrentThreadId(void)
686 {
687     return HandleToULong(NtCurrentTeb()->ClientId.UniqueThread);
688 }
689
690 /***********************************************************************
691  *           GetProcessHeap    (KERNEL32.@)
692  */
693 HANDLE WINAPI GetProcessHeap(void)
694 {
695     return NtCurrentTeb()->Peb->ProcessHeap;
696 }
697
698 #endif  /* __i386__ */
699
700 /*************************************************************************
701  *              rtlmode_to_win32mode
702  */
703 static DWORD rtlmode_to_win32mode( DWORD rtlmode )
704 {
705     DWORD win32mode = 0;
706
707     if (rtlmode & 0x10)
708         win32mode |= SEM_FAILCRITICALERRORS;
709     if (rtlmode & 0x20)
710         win32mode |= SEM_NOGPFAULTERRORBOX;
711     if (rtlmode & 0x40)
712         win32mode |= SEM_NOOPENFILEERRORBOX;
713
714     return win32mode;
715 }
716
717 /***********************************************************************
718  *              SetThreadErrorMode (KERNEL32.@)
719  *
720  * Set the thread local error mode.
721  *
722  * PARAMS
723  *  mode    [I] The new error mode, a bitwise or of SEM_FAILCRITICALERRORS,
724  *              SEM_NOGPFAULTERRORBOX and SEM_NOOPENFILEERRORBOX.
725  *  oldmode [O] Destination of the old error mode (may be NULL)
726  *
727  * RETURNS
728  *  Success: TRUE
729  *  Failure: FALSE, check GetLastError
730  */
731 BOOL WINAPI SetThreadErrorMode( DWORD mode, LPDWORD oldmode )
732 {
733     NTSTATUS status;
734     DWORD tmp = 0;
735
736     if (mode & ~(SEM_FAILCRITICALERRORS |
737                  SEM_NOGPFAULTERRORBOX |
738                  SEM_NOOPENFILEERRORBOX))
739     {
740         SetLastError( ERROR_INVALID_PARAMETER );
741         return FALSE;
742     }
743
744     if (mode & SEM_FAILCRITICALERRORS)
745         tmp |= 0x10;
746     if (mode & SEM_NOGPFAULTERRORBOX)
747         tmp |= 0x20;
748     if (mode & SEM_NOOPENFILEERRORBOX)
749         tmp |= 0x40;
750
751     status = RtlSetThreadErrorMode( tmp, oldmode );
752     if (status)
753     {
754         SetLastError( RtlNtStatusToDosError(status) );
755         return FALSE;
756     }
757
758     if (oldmode)
759         *oldmode = rtlmode_to_win32mode(*oldmode);
760
761     return TRUE;
762 }
763
764 /***********************************************************************
765  *              GetThreadErrorMode (KERNEL32.@)
766  *
767  * Get the thread local error mode.
768  *
769  * PARAMS
770  *  None.
771  *
772  * RETURNS
773  *  The current thread local error mode.
774  */
775 DWORD WINAPI GetThreadErrorMode( void )
776 {
777     return rtlmode_to_win32mode( RtlGetThreadErrorMode() );
778 }
779
780 /***********************************************************************
781  *              GetThreadUILanguage (KERNEL32.@)
782  *
783  * Get the current thread's language identifier.
784  *
785  * PARAMS
786  *  None.
787  *
788  * RETURNS
789  *  The current thread's language identifier.
790  */
791 LANGID WINAPI GetThreadUILanguage( void )
792 {
793     LANGID lang;
794     NtQueryDefaultUILanguage( &lang );
795     FIXME(": stub, returning default language.\n");
796     return lang;
797 }
798
799 /***********************************************************************
800  *              GetThreadIOPendingFlag (KERNEL32.@)
801  */
802 BOOL WINAPI GetThreadIOPendingFlag( HANDLE thread, PBOOL io_pending )
803 {
804     FIXME("%p, %p\n", thread, io_pending);
805     *io_pending = FALSE;
806     return TRUE;
807 }
808
809 /***********************************************************************
810  *              SetThreadPreferredUILanguages (KERNEL32.@)
811  */
812 BOOL WINAPI SetThreadPreferredUILanguages( DWORD flags, PCZZWSTR buffer, PULONG count )
813 {
814     FIXME( "%u, %p, %p\n", flags, buffer, count );
815     return TRUE;
816 }
817
818 /***********************************************************************
819  *              GetThreadPreferredUILanguages (KERNEL32.@)
820  */
821 BOOL WINAPI GetThreadPreferredUILanguages( DWORD flags, PULONG count, PCZZWSTR buffer, PULONG buffersize )
822 {
823     FIXME( "%u, %p, %p %p\n", flags, count, buffer, buffersize );
824     *count = 0;
825     *buffersize = 0;
826     return TRUE;
827 }
828
829 /***********************************************************************
830  *              InitializeSRWLock (KERNEL32.@)
831  */
832 VOID WINAPI InitializeSRWLock( PSRWLOCK srwlock )
833 {
834     FIXME( "(%p): stub\n", srwlock );
835 }
836
837 /***********************************************************************
838  *              AcquireSRWLockExclusive (KERNEL32.@)
839  */
840 VOID WINAPI AcquireSRWLockExclusive( PSRWLOCK srwlock )
841 {
842     FIXME( "(%p): stub\n", srwlock );
843 }
844
845 /***********************************************************************
846  *              ReleaseSRWLockExclusive (KERNEL32.@)
847  */
848 VOID WINAPI ReleaseSRWLockExclusive( PSRWLOCK srwlock )
849 {
850     FIXME( "(%p): stub\n", srwlock );
851 }
852
853 /***********************************************************************
854  *              AcquireSRWLockShared (KERNEL32.@)
855  */
856 VOID WINAPI AcquireSRWLockShared( PSRWLOCK srwlock )
857 {
858     FIXME( "(%p): stub\n", srwlock );
859 }
860
861 /***********************************************************************
862  *              ReleaseSRWLockShared (KERNEL32.@)
863  */
864 VOID WINAPI ReleaseSRWLockShared( PSRWLOCK srwlock )
865 {
866     FIXME( "(%p): stub\n", srwlock );
867 }