uiautomationcore: Add support for UIA_ProviderDescriptionPropertyId.
[wine.git] / dlls / kernelbase / thread.c
blob235624811f55d99bf7ddc073e5d332d83b097e36
1 /*
2 * Win32 threads
4 * Copyright 1996, 2002, 2019 Alexandre Julliard
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.
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.
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
21 #include <stdarg.h>
22 #include <string.h>
23 #include <limits.h>
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #define NONAMELESSUNION
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winnls.h"
31 #include "winternl.h"
33 #include "kernelbase.h"
34 #include "wine/exception.h"
35 #include "wine/asm.h"
36 #include "wine/debug.h"
37 #include "wine/heap.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(thread);
42 /***********************************************************************
43 * Threads
44 ***********************************************************************/
47 static DWORD rtlmode_to_win32mode( DWORD rtlmode )
49 DWORD win32mode = 0;
51 if (rtlmode & 0x10) win32mode |= SEM_FAILCRITICALERRORS;
52 if (rtlmode & 0x20) win32mode |= SEM_NOGPFAULTERRORBOX;
53 if (rtlmode & 0x40) win32mode |= SEM_NOOPENFILEERRORBOX;
54 return win32mode;
58 /***************************************************************************
59 * CreateRemoteThread (kernelbase.@)
61 HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThread( HANDLE process, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
62 LPTHREAD_START_ROUTINE start, LPVOID param,
63 DWORD flags, DWORD *id )
65 return CreateRemoteThreadEx( process, sa, stack, start, param, flags, NULL, id );
69 /***************************************************************************
70 * CreateRemoteThreadEx (kernelbase.@)
72 HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThreadEx( HANDLE process, SECURITY_ATTRIBUTES *sa,
73 SIZE_T stack, LPTHREAD_START_ROUTINE start,
74 LPVOID param, DWORD flags,
75 LPPROC_THREAD_ATTRIBUTE_LIST attributes, DWORD *id )
77 HANDLE handle;
78 CLIENT_ID client_id;
79 SIZE_T stack_reserve = 0, stack_commit = 0;
81 if (attributes) FIXME("thread attributes ignored\n");
83 if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
84 else stack_commit = stack;
86 if (!set_ntstatus( RtlCreateUserThread( process, sa ? sa->lpSecurityDescriptor : NULL, TRUE,
87 0, stack_reserve, stack_commit,
88 (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id )))
89 return 0;
91 if (id) *id = HandleToULong( client_id.UniqueThread );
92 if (sa && sa->nLength >= sizeof(*sa) && sa->bInheritHandle)
93 SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
94 if (!(flags & CREATE_SUSPENDED))
96 ULONG ret;
97 if (NtResumeThread( handle, &ret ))
99 NtClose( handle );
100 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
101 handle = 0;
104 return handle;
108 /***********************************************************************
109 * CreateThread (kernelbase.@)
111 HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
112 LPTHREAD_START_ROUTINE start, LPVOID param,
113 DWORD flags, LPDWORD id )
115 return CreateRemoteThread( GetCurrentProcess(), sa, stack, start, param, flags, id );
119 /***********************************************************************
120 * FreeLibraryAndExitThread (kernelbase.@)
122 void WINAPI DECLSPEC_HOTPATCH FreeLibraryAndExitThread( HINSTANCE module, DWORD exit_code )
124 FreeLibrary( module );
125 RtlExitUserThread( exit_code );
129 /***********************************************************************
130 * GetCurrentThreadStackLimits (kernelbase.@)
132 void WINAPI DECLSPEC_HOTPATCH GetCurrentThreadStackLimits( ULONG_PTR *low, ULONG_PTR *high )
134 *low = (ULONG_PTR)NtCurrentTeb()->DeallocationStack;
135 *high = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase;
139 /***********************************************************************
140 * GetCurrentThread (kernelbase.@)
142 HANDLE WINAPI kernelbase_GetCurrentThread(void)
144 return (HANDLE)~(ULONG_PTR)1;
148 /***********************************************************************
149 * GetCurrentThreadId (kernelbase.@)
151 DWORD WINAPI kernelbase_GetCurrentThreadId(void)
153 return HandleToULong( NtCurrentTeb()->ClientId.UniqueThread );
157 /**********************************************************************
158 * GetExitCodeThread (kernelbase.@)
160 BOOL WINAPI DECLSPEC_HOTPATCH GetExitCodeThread( HANDLE thread, LPDWORD exit_code )
162 THREAD_BASIC_INFORMATION info;
163 NTSTATUS status = NtQueryInformationThread( thread, ThreadBasicInformation,
164 &info, sizeof(info), NULL );
165 if (!status && exit_code) *exit_code = info.ExitStatus;
166 return set_ntstatus( status );
170 /**********************************************************************
171 * GetLastError (kernelbase.@)
173 DWORD WINAPI kernelbase_GetLastError(void)
175 return NtCurrentTeb()->LastErrorValue;
179 /**********************************************************************
180 * GetProcessIdOfThread (kernelbase.@)
182 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessIdOfThread( HANDLE thread )
184 THREAD_BASIC_INFORMATION tbi;
186 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL)))
187 return 0;
188 return HandleToULong( tbi.ClientId.UniqueProcess );
192 /***********************************************************************
193 * GetThreadContext (kernelbase.@)
195 BOOL WINAPI DECLSPEC_HOTPATCH GetThreadContext( HANDLE thread, CONTEXT *context )
197 return set_ntstatus( NtGetContextThread( thread, context ));
201 /***********************************************************************
202 * GetThreadErrorMode (kernelbase.@)
204 DWORD WINAPI DECLSPEC_HOTPATCH GetThreadErrorMode(void)
206 return rtlmode_to_win32mode( RtlGetThreadErrorMode() );
210 /***********************************************************************
211 * GetThreadGroupAffinity (kernelbase.@)
213 BOOL WINAPI DECLSPEC_HOTPATCH GetThreadGroupAffinity( HANDLE thread, GROUP_AFFINITY *affinity )
215 if (!affinity)
217 SetLastError( ERROR_INVALID_PARAMETER );
218 return FALSE;
220 return set_ntstatus( NtQueryInformationThread( thread, ThreadGroupInformation,
221 affinity, sizeof(*affinity), NULL ));
225 /***********************************************************************
226 * GetThreadIOPendingFlag (kernelbase.@)
228 BOOL WINAPI DECLSPEC_HOTPATCH GetThreadIOPendingFlag( HANDLE thread, PBOOL pending )
230 return set_ntstatus( NtQueryInformationThread( thread, ThreadIsIoPending,
231 pending, sizeof(*pending), NULL ));
235 /**********************************************************************
236 * GetThreadId (kernelbase.@)
238 DWORD WINAPI DECLSPEC_HOTPATCH GetThreadId( HANDLE thread )
240 THREAD_BASIC_INFORMATION tbi;
242 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL)))
243 return 0;
244 return HandleToULong( tbi.ClientId.UniqueThread );
248 /***********************************************************************
249 * GetThreadIdealProcessorEx (kernelbase.@)
251 BOOL WINAPI DECLSPEC_HOTPATCH GetThreadIdealProcessorEx( HANDLE thread, PROCESSOR_NUMBER *ideal )
253 return set_ntstatus( NtQueryInformationThread( thread, ThreadIdealProcessorEx, ideal, sizeof(*ideal), NULL));
257 /***********************************************************************
258 * GetThreadLocale (kernelbase.@)
260 LCID WINAPI /* DECLSPEC_HOTPATCH */ GetThreadLocale(void)
262 LCID ret = NtCurrentTeb()->CurrentLocale;
263 if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
264 return ret;
268 /**********************************************************************
269 * GetThreadPriority (kernelbase.@)
271 INT WINAPI DECLSPEC_HOTPATCH GetThreadPriority( HANDLE thread )
273 THREAD_BASIC_INFORMATION info;
275 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadBasicInformation,
276 &info, sizeof(info), NULL )))
277 return THREAD_PRIORITY_ERROR_RETURN;
278 return info.Priority;
282 /**********************************************************************
283 * GetThreadPriorityBoost (kernelbase.@)
285 BOOL WINAPI DECLSPEC_HOTPATCH GetThreadPriorityBoost( HANDLE thread, BOOL *state )
287 return set_ntstatus( NtQueryInformationThread( thread, ThreadPriorityBoost, state, sizeof(*state), NULL ));
291 /**********************************************************************
292 * GetThreadTimes (kernelbase.@)
294 BOOL WINAPI DECLSPEC_HOTPATCH GetThreadTimes( HANDLE thread, LPFILETIME creationtime, LPFILETIME exittime,
295 LPFILETIME kerneltime, LPFILETIME usertime )
297 KERNEL_USER_TIMES times;
299 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadTimes, &times, sizeof(times), NULL )))
300 return FALSE;
302 if (creationtime)
304 creationtime->dwLowDateTime = times.CreateTime.u.LowPart;
305 creationtime->dwHighDateTime = times.CreateTime.u.HighPart;
307 if (exittime)
309 exittime->dwLowDateTime = times.ExitTime.u.LowPart;
310 exittime->dwHighDateTime = times.ExitTime.u.HighPart;
312 if (kerneltime)
314 kerneltime->dwLowDateTime = times.KernelTime.u.LowPart;
315 kerneltime->dwHighDateTime = times.KernelTime.u.HighPart;
317 if (usertime)
319 usertime->dwLowDateTime = times.UserTime.u.LowPart;
320 usertime->dwHighDateTime = times.UserTime.u.HighPart;
322 return TRUE;
326 /***********************************************************************
327 * GetThreadUILanguage (kernelbase.@)
329 LANGID WINAPI DECLSPEC_HOTPATCH GetThreadUILanguage(void)
331 LANGID lang;
333 FIXME(": stub, returning default language.\n");
334 NtQueryDefaultUILanguage( &lang );
335 return lang;
339 /***********************************************************************
340 * OpenThread (kernelbase.@)
342 HANDLE WINAPI DECLSPEC_HOTPATCH OpenThread( DWORD access, BOOL inherit, DWORD id )
344 HANDLE handle;
345 OBJECT_ATTRIBUTES attr;
346 CLIENT_ID cid;
348 attr.Length = sizeof(attr);
349 attr.RootDirectory = 0;
350 attr.Attributes = inherit ? OBJ_INHERIT : 0;
351 attr.ObjectName = NULL;
352 attr.SecurityDescriptor = NULL;
353 attr.SecurityQualityOfService = NULL;
355 cid.UniqueProcess = 0;
356 cid.UniqueThread = ULongToHandle( id );
358 if (!set_ntstatus( NtOpenThread( &handle, access, &attr, &cid ))) handle = 0;
359 return handle;
363 /* callback for QueueUserAPC */
364 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
366 PAPCFUNC func = (PAPCFUNC)arg1;
367 func( arg2 );
370 /***********************************************************************
371 * QueueUserAPC (kernelbase.@)
373 DWORD WINAPI DECLSPEC_HOTPATCH QueueUserAPC( PAPCFUNC func, HANDLE thread, ULONG_PTR data )
375 return set_ntstatus( NtQueueApcThread( thread, call_user_apc, (ULONG_PTR)func, data, 0 ));
379 /***********************************************************************
380 * QueryThreadCycleTime (kernelbase.@)
382 BOOL WINAPI DECLSPEC_HOTPATCH QueryThreadCycleTime( HANDLE thread, ULONG64 *cycle )
384 static int once;
385 if (!once++) FIXME( "(%p,%p): stub!\n", thread, cycle );
386 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
387 return FALSE;
391 /**********************************************************************
392 * ResumeThread (kernelbase.@)
394 DWORD WINAPI DECLSPEC_HOTPATCH ResumeThread( HANDLE thread )
396 DWORD ret;
398 if (!set_ntstatus( NtResumeThread( thread, &ret ))) ret = ~0U;
399 return ret;
403 /***********************************************************************
404 * SetThreadContext (kernelbase.@)
406 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadContext( HANDLE thread, const CONTEXT *context )
408 return set_ntstatus( NtSetContextThread( thread, context ));
412 /***********************************************************************
413 * SetThreadDescription (kernelbase.@)
415 HRESULT WINAPI DECLSPEC_HOTPATCH SetThreadDescription( HANDLE thread, PCWSTR description )
417 THREAD_NAME_INFORMATION info;
418 int length;
420 TRACE( "(%p, %s)\n", thread, debugstr_w( description ));
422 length = description ? lstrlenW( description ) * sizeof(WCHAR) : 0;
424 if (length > USHRT_MAX)
425 return HRESULT_FROM_NT(STATUS_INVALID_PARAMETER);
427 info.ThreadName.Length = info.ThreadName.MaximumLength = length;
428 info.ThreadName.Buffer = (WCHAR *)description;
430 return HRESULT_FROM_NT(NtSetInformationThread( thread, ThreadNameInformation, &info, sizeof(info) ));
433 /***********************************************************************
434 * GetThreadDescription (kernelbase.@)
436 HRESULT WINAPI DECLSPEC_HOTPATCH GetThreadDescription( HANDLE thread, WCHAR **description )
438 THREAD_NAME_INFORMATION *info;
439 NTSTATUS status;
440 ULONG length;
442 TRACE( "(%p, %p)\n", thread, description );
444 *description = NULL;
446 length = 0;
447 status = NtQueryInformationThread( thread, ThreadNameInformation, NULL, 0, &length );
448 if (status != STATUS_BUFFER_TOO_SMALL)
449 return HRESULT_FROM_NT(status);
451 if (!(info = heap_alloc( length )))
452 return HRESULT_FROM_NT(STATUS_NO_MEMORY);
454 status = NtQueryInformationThread( thread, ThreadNameInformation, info, length, &length );
455 if (!status)
457 if (!(*description = LocalAlloc( 0, info->ThreadName.Length + sizeof(WCHAR))))
458 status = STATUS_NO_MEMORY;
459 else
461 if (info->ThreadName.Length)
462 memcpy(*description, info->ThreadName.Buffer, info->ThreadName.Length);
463 (*description)[info->ThreadName.Length / sizeof(WCHAR)] = 0;
467 heap_free(info);
469 return HRESULT_FROM_NT(status);
472 /***********************************************************************
473 * SetThreadErrorMode (kernelbase.@)
475 BOOL WINAPI SetThreadErrorMode( DWORD mode, DWORD *old )
477 NTSTATUS status;
478 DWORD new = 0;
480 if (mode & ~(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX))
482 SetLastError( ERROR_INVALID_PARAMETER );
483 return FALSE;
486 if (mode & SEM_FAILCRITICALERRORS) new |= 0x10;
487 if (mode & SEM_NOGPFAULTERRORBOX) new |= 0x20;
488 if (mode & SEM_NOOPENFILEERRORBOX) new |= 0x40;
490 status = RtlSetThreadErrorMode( new, old );
491 if (!status && old) *old = rtlmode_to_win32mode( *old );
492 return set_ntstatus( status );
496 /***********************************************************************
497 * SetThreadGroupAffinity (kernelbase.@)
499 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadGroupAffinity( HANDLE thread, const GROUP_AFFINITY *new,
500 GROUP_AFFINITY *old )
502 if (old && !GetThreadGroupAffinity( thread, old )) return FALSE;
503 return set_ntstatus( NtSetInformationThread( thread, ThreadGroupInformation, new, sizeof(*new) ));
507 /**********************************************************************
508 * SetThreadIdealProcessor (kernelbase.@)
510 DWORD WINAPI DECLSPEC_HOTPATCH SetThreadIdealProcessor( HANDLE thread, DWORD proc )
512 NTSTATUS status;
514 status = NtSetInformationThread( thread, ThreadIdealProcessor, &proc, sizeof(proc) );
515 if (NT_SUCCESS(status)) return status;
517 SetLastError( RtlNtStatusToDosError( status ));
518 return ~0u;
522 /***********************************************************************
523 * SetThreadIdealProcessorEx (kernelbase.@)
525 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadIdealProcessorEx( HANDLE thread, PROCESSOR_NUMBER *ideal,
526 PROCESSOR_NUMBER *previous )
528 FIXME( "(%p %p %p): stub\n", thread, ideal, previous );
529 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
530 return FALSE;
534 /**********************************************************************
535 * SetThreadLocale (kernelbase.@)
537 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadLocale( LCID lcid )
539 lcid = ConvertDefaultLocale( lcid );
540 if (lcid != GetThreadLocale())
542 if (!IsValidLocale( lcid, LCID_SUPPORTED ))
544 SetLastError( ERROR_INVALID_PARAMETER );
545 return FALSE;
547 NtCurrentTeb()->CurrentLocale = lcid;
549 return TRUE;
553 /**********************************************************************
554 * SetThreadPriority (kernelbase.@)
556 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadPriority( HANDLE thread, INT priority )
558 DWORD prio = priority;
559 return set_ntstatus( NtSetInformationThread( thread, ThreadBasePriority, &prio, sizeof(prio) ));
563 /**********************************************************************
564 * SetThreadPriorityBoost (kernelbase.@)
566 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadPriorityBoost( HANDLE thread, BOOL disable )
568 return set_ntstatus( NtSetInformationThread( thread, ThreadPriorityBoost, &disable, sizeof(disable) ));
572 /**********************************************************************
573 * SetThreadStackGuarantee (kernelbase.@)
575 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadStackGuarantee( ULONG *size )
577 ULONG prev_size = NtCurrentTeb()->GuaranteedStackBytes;
578 ULONG new_size = (*size + 4095) & ~4095;
580 /* at least 2 pages on 64-bit */
581 if (sizeof(void *) > sizeof(int) && new_size) new_size = max( new_size, 8192 );
583 *size = prev_size;
584 if (new_size >= (char *)NtCurrentTeb()->Tib.StackBase - (char *)NtCurrentTeb()->DeallocationStack)
586 SetLastError( ERROR_INVALID_PARAMETER );
587 return FALSE;
589 if (new_size > prev_size) NtCurrentTeb()->GuaranteedStackBytes = (new_size + 4095) & ~4095;
590 return TRUE;
594 /**********************************************************************
595 * SetThreadUILanguage (kernelbase.@)
597 LANGID WINAPI DECLSPEC_HOTPATCH SetThreadUILanguage( LANGID langid )
599 TRACE( "(0x%04x) stub - returning success\n", langid );
601 if (!langid) langid = GetThreadUILanguage();
602 return langid;
606 /**********************************************************************
607 * SetThreadInformation (kernelbase.@)
609 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadInformation( HANDLE thread, THREAD_INFORMATION_CLASS info_class,
610 VOID *info, DWORD size )
612 switch (info_class)
614 case ThreadMemoryPriority:
615 return set_ntstatus( NtSetInformationThread( thread, ThreadPagePriority, info, size ));
616 case ThreadPowerThrottling:
617 return set_ntstatus( NtSetInformationThread( thread, ThreadPowerThrottlingState, info, size ));
618 default:
619 FIXME("Unsupported class %u.\n", info_class);
620 return FALSE;
625 /**********************************************************************
626 * SuspendThread (kernelbase.@)
628 DWORD WINAPI DECLSPEC_HOTPATCH SuspendThread( HANDLE thread )
630 DWORD ret;
632 if (!set_ntstatus( NtSuspendThread( thread, &ret ))) ret = ~0U;
633 return ret;
637 /***********************************************************************
638 * SwitchToThread (kernelbase.@)
640 BOOL WINAPI DECLSPEC_HOTPATCH SwitchToThread(void)
642 return (NtYieldExecution() != STATUS_NO_YIELD_PERFORMED);
646 /**********************************************************************
647 * TerminateThread (kernelbase.@)
649 BOOL WINAPI DECLSPEC_HOTPATCH TerminateThread( HANDLE handle, DWORD exit_code )
651 return set_ntstatus( NtTerminateThread( handle, exit_code ));
655 /**********************************************************************
656 * TlsAlloc (kernelbase.@)
658 DWORD WINAPI DECLSPEC_HOTPATCH TlsAlloc(void)
660 DWORD index;
661 PEB * const peb = NtCurrentTeb()->Peb;
663 RtlAcquirePebLock();
664 index = RtlFindClearBitsAndSet( peb->TlsBitmap, 1, 1 );
665 if (index != ~0U) NtCurrentTeb()->TlsSlots[index] = 0; /* clear the value */
666 else
668 index = RtlFindClearBitsAndSet( peb->TlsExpansionBitmap, 1, 0 );
669 if (index != ~0U)
671 if (!NtCurrentTeb()->TlsExpansionSlots &&
672 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
673 8 * sizeof(peb->TlsExpansionBitmapBits) * sizeof(void*) )))
675 RtlClearBits( peb->TlsExpansionBitmap, index, 1 );
676 index = ~0U;
677 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
679 else
681 NtCurrentTeb()->TlsExpansionSlots[index] = 0; /* clear the value */
682 index += TLS_MINIMUM_AVAILABLE;
685 else SetLastError( ERROR_NO_MORE_ITEMS );
687 RtlReleasePebLock();
688 return index;
692 /**********************************************************************
693 * TlsFree (kernelbase.@)
695 BOOL WINAPI DECLSPEC_HOTPATCH TlsFree( DWORD index )
697 BOOL ret;
699 RtlAcquirePebLock();
700 if (index >= TLS_MINIMUM_AVAILABLE)
702 ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
703 if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
705 else
707 ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
708 if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
710 if (ret) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
711 else SetLastError( ERROR_INVALID_PARAMETER );
712 RtlReleasePebLock();
713 return ret;
717 /**********************************************************************
718 * TlsGetValue (kernelbase.@)
720 LPVOID WINAPI DECLSPEC_HOTPATCH TlsGetValue( DWORD index )
722 SetLastError( ERROR_SUCCESS );
723 if (index < TLS_MINIMUM_AVAILABLE) return NtCurrentTeb()->TlsSlots[index];
725 index -= TLS_MINIMUM_AVAILABLE;
726 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
728 SetLastError( ERROR_INVALID_PARAMETER );
729 return NULL;
731 if (!NtCurrentTeb()->TlsExpansionSlots) return NULL;
732 return NtCurrentTeb()->TlsExpansionSlots[index];
736 /**********************************************************************
737 * TlsSetValue (kernelbase.@)
739 BOOL WINAPI DECLSPEC_HOTPATCH TlsSetValue( DWORD index, LPVOID value )
741 if (index < TLS_MINIMUM_AVAILABLE)
743 NtCurrentTeb()->TlsSlots[index] = value;
745 else
747 index -= TLS_MINIMUM_AVAILABLE;
748 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
750 SetLastError( ERROR_INVALID_PARAMETER );
751 return FALSE;
753 if (!NtCurrentTeb()->TlsExpansionSlots &&
754 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
755 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits) * sizeof(void*) )))
757 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
758 return FALSE;
760 NtCurrentTeb()->TlsExpansionSlots[index] = value;
762 return TRUE;
766 /***********************************************************************
767 * Fibers
768 ***********************************************************************/
771 struct fiber_data
773 LPVOID param; /* 00/00 fiber param */
774 void *except; /* 04/08 saved exception handlers list */
775 void *stack_base; /* 08/10 top of fiber stack */
776 void *stack_limit; /* 0c/18 fiber stack low-water mark */
777 void *stack_allocation; /* 10/20 base of the fiber stack allocation */
778 CONTEXT context; /* 14/30 fiber context */
779 DWORD flags; /* fiber flags */
780 LPFIBER_START_ROUTINE start; /* start routine */
781 void *fls_slots; /* fiber storage slots */
784 extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new );
785 #ifdef __i386__
786 __ASM_STDCALL_FUNC( switch_fiber, 8,
787 "movl 4(%esp),%ecx\n\t" /* old */
788 "movl %edi,0x9c(%ecx)\n\t" /* old->Edi */
789 "movl %esi,0xa0(%ecx)\n\t" /* old->Esi */
790 "movl %ebx,0xa4(%ecx)\n\t" /* old->Ebx */
791 "movl %ebp,0xb4(%ecx)\n\t" /* old->Ebp */
792 "movl 0(%esp),%eax\n\t"
793 "movl %eax,0xb8(%ecx)\n\t" /* old->Eip */
794 "leal 12(%esp),%eax\n\t"
795 "movl %eax,0xc4(%ecx)\n\t" /* old->Esp */
796 "movl 8(%esp),%ecx\n\t" /* new */
797 "movl 0x9c(%ecx),%edi\n\t" /* new->Edi */
798 "movl 0xa0(%ecx),%esi\n\t" /* new->Esi */
799 "movl 0xa4(%ecx),%ebx\n\t" /* new->Ebx */
800 "movl 0xb4(%ecx),%ebp\n\t" /* new->Ebp */
801 "movl 0xc4(%ecx),%esp\n\t" /* new->Esp */
802 "jmp *0xb8(%ecx)" ) /* new->Eip */
803 #elif defined(__x86_64__)
804 __ASM_STDCALL_FUNC( switch_fiber, 8,
805 "movq %rbx,0x90(%rcx)\n\t" /* old->Rbx */
806 "leaq 0x8(%rsp),%rax\n\t"
807 "movq %rax,0x98(%rcx)\n\t" /* old->Rsp */
808 "movq %rbp,0xa0(%rcx)\n\t" /* old->Rbp */
809 "movq %rsi,0xa8(%rcx)\n\t" /* old->Rsi */
810 "movq %rdi,0xb0(%rcx)\n\t" /* old->Rdi */
811 "movq %r12,0xd8(%rcx)\n\t" /* old->R12 */
812 "movq %r13,0xe0(%rcx)\n\t" /* old->R13 */
813 "movq %r14,0xe8(%rcx)\n\t" /* old->R14 */
814 "movq %r15,0xf0(%rcx)\n\t" /* old->R15 */
815 "movq (%rsp),%rax\n\t"
816 "movq %rax,0xf8(%rcx)\n\t" /* old->Rip */
817 "movdqa %xmm6,0x200(%rcx)\n\t" /* old->Xmm6 */
818 "movdqa %xmm7,0x210(%rcx)\n\t" /* old->Xmm7 */
819 "movdqa %xmm8,0x220(%rcx)\n\t" /* old->Xmm8 */
820 "movdqa %xmm9,0x230(%rcx)\n\t" /* old->Xmm9 */
821 "movdqa %xmm10,0x240(%rcx)\n\t" /* old->Xmm10 */
822 "movdqa %xmm11,0x250(%rcx)\n\t" /* old->Xmm11 */
823 "movdqa %xmm12,0x260(%rcx)\n\t" /* old->Xmm12 */
824 "movdqa %xmm13,0x270(%rcx)\n\t" /* old->Xmm13 */
825 "movdqa %xmm14,0x280(%rcx)\n\t" /* old->Xmm14 */
826 "movdqa %xmm15,0x290(%rcx)\n\t" /* old->Xmm15 */
827 "movq 0x90(%rdx),%rbx\n\t" /* new->Rbx */
828 "movq 0xa0(%rdx),%rbp\n\t" /* new->Rbp */
829 "movq 0xa8(%rdx),%rsi\n\t" /* new->Rsi */
830 "movq 0xb0(%rdx),%rdi\n\t" /* new->Rdi */
831 "movq 0xd8(%rdx),%r12\n\t" /* new->R12 */
832 "movq 0xe0(%rdx),%r13\n\t" /* new->R13 */
833 "movq 0xe8(%rdx),%r14\n\t" /* new->R14 */
834 "movq 0xf0(%rdx),%r15\n\t" /* new->R15 */
835 "movdqa 0x200(%rdx),%xmm6\n\t" /* new->Xmm6 */
836 "movdqa 0x210(%rdx),%xmm7\n\t" /* new->Xmm7 */
837 "movdqa 0x220(%rdx),%xmm8\n\t" /* new->Xmm8 */
838 "movdqa 0x230(%rdx),%xmm9\n\t" /* new->Xmm9 */
839 "movdqa 0x240(%rdx),%xmm10\n\t" /* new->Xmm10 */
840 "movdqa 0x250(%rdx),%xmm11\n\t" /* new->Xmm11 */
841 "movdqa 0x260(%rdx),%xmm12\n\t" /* new->Xmm12 */
842 "movdqa 0x270(%rdx),%xmm13\n\t" /* new->Xmm13 */
843 "movdqa 0x280(%rdx),%xmm14\n\t" /* new->Xmm14 */
844 "movdqa 0x290(%rdx),%xmm15\n\t" /* new->Xmm15 */
845 "movq 0x98(%rdx),%rsp\n\t" /* new->Rsp */
846 "jmp *0xf8(%rdx)" ) /* new->Rip */
847 #elif defined(__arm__)
848 __ASM_STDCALL_FUNC( switch_fiber, 8,
849 "str r4, [r0, #0x14]\n\t" /* old->R4 */
850 "str r5, [r0, #0x18]\n\t" /* old->R5 */
851 "str r6, [r0, #0x1c]\n\t" /* old->R6 */
852 "str r7, [r0, #0x20]\n\t" /* old->R7 */
853 "str r8, [r0, #0x24]\n\t" /* old->R8 */
854 "str r9, [r0, #0x28]\n\t" /* old->R9 */
855 "str r10, [r0, #0x2c]\n\t" /* old->R10 */
856 "str r11, [r0, #0x30]\n\t" /* old->R11 */
857 "str sp, [r0, #0x38]\n\t" /* old->Sp */
858 "str lr, [r0, #0x40]\n\t" /* old->Pc */
859 "ldr r4, [r1, #0x14]\n\t" /* new->R4 */
860 "ldr r5, [r1, #0x18]\n\t" /* new->R5 */
861 "ldr r6, [r1, #0x1c]\n\t" /* new->R6 */
862 "ldr r7, [r1, #0x20]\n\t" /* new->R7 */
863 "ldr r8, [r1, #0x24]\n\t" /* new->R8 */
864 "ldr r9, [r1, #0x28]\n\t" /* new->R9 */
865 "ldr r10, [r1, #0x2c]\n\t" /* new->R10 */
866 "ldr r11, [r1, #0x30]\n\t" /* new->R11 */
867 "ldr sp, [r1, #0x38]\n\t" /* new->Sp */
868 "ldr r2, [r1, #0x40]\n\t" /* new->Pc */
869 "bx r2" )
870 #elif defined(__aarch64__)
871 __ASM_STDCALL_FUNC( switch_fiber, 8,
872 "stp x19, x20, [x0, #0xa0]\n\t" /* old->X19,X20 */
873 "stp x21, x22, [x0, #0xb0]\n\t" /* old->X21,X22 */
874 "stp x23, x24, [x0, #0xc0]\n\t" /* old->X23,X24 */
875 "stp x25, x26, [x0, #0xd0]\n\t" /* old->X25,X26 */
876 "stp x27, x28, [x0, #0xe0]\n\t" /* old->X27,X28 */
877 "str x29, [x0, #0xf0]\n\t" /* old->Fp */
878 "mov x2, sp\n\t"
879 "str x2, [x0, #0x100]\n\t" /* old->Sp */
880 "str x30, [x0, #0x108]\n\t" /* old->Pc */
881 "ldp x19, x20, [x1, #0xa0]\n\t" /* new->X19,X20 */
882 "ldp x21, x22, [x1, #0xb0]\n\t" /* new->X21,X22 */
883 "ldp x23, x24, [x1, #0xc0]\n\t" /* new->X23,X24 */
884 "ldp x25, x26, [x1, #0xd0]\n\t" /* new->X25,X26 */
885 "ldp x27, x28, [x1, #0xe0]\n\t" /* new->X27,X28 */
886 "ldr x29, [x1, #0xf0]\n\t" /* new->Fp */
887 "ldr x2, [x1, #0x100]\n\t" /* new->Sp */
888 "ldr x30, [x1, #0x108]\n\t" /* new->Pc */
889 "mov sp, x2\n\t"
890 "ret" )
891 #else
892 void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new )
894 FIXME( "not implemented\n" );
895 DbgBreakPoint();
897 #endif
899 /* call the fiber initial function once we have switched stack */
900 static void CDECL start_fiber(void)
902 struct fiber_data *fiber = NtCurrentTeb()->Tib.u.FiberData;
903 LPFIBER_START_ROUTINE start = fiber->start;
905 __TRY
907 start( fiber->param );
908 RtlExitUserThread( 1 );
910 __EXCEPT(UnhandledExceptionFilter)
912 TerminateThread( GetCurrentThread(), GetExceptionCode() );
914 __ENDTRY
917 static void init_fiber_context( struct fiber_data *fiber )
919 #ifdef __i386__
920 fiber->context.Esp = (ULONG_PTR)fiber->stack_base - 4;
921 fiber->context.Eip = (ULONG_PTR)start_fiber;
922 #elif defined(__x86_64__)
923 fiber->context.Rsp = (ULONG_PTR)fiber->stack_base - 0x28;
924 fiber->context.Rip = (ULONG_PTR)start_fiber;
925 #elif defined(__arm__)
926 fiber->context.Sp = (ULONG_PTR)fiber->stack_base;
927 fiber->context.Pc = (ULONG_PTR)start_fiber;
928 #elif defined(__aarch64__)
929 fiber->context.Sp = (ULONG_PTR)fiber->stack_base;
930 fiber->context.Pc = (ULONG_PTR)start_fiber;
931 #endif
935 /***********************************************************************
936 * CreateFiber (kernelbase.@)
938 LPVOID WINAPI DECLSPEC_HOTPATCH CreateFiber( SIZE_T stack, LPFIBER_START_ROUTINE start, LPVOID param )
940 return CreateFiberEx( stack, 0, 0, start, param );
944 /***********************************************************************
945 * CreateFiberEx (kernelbase.@)
947 LPVOID WINAPI DECLSPEC_HOTPATCH CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD flags,
948 LPFIBER_START_ROUTINE start, LPVOID param )
950 struct fiber_data *fiber;
951 INITIAL_TEB stack;
953 if (!(fiber = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fiber) )))
955 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
956 return NULL;
959 if (!set_ntstatus( RtlCreateUserStack( stack_commit, stack_reserve, 0, 1, 1, &stack )))
961 HeapFree( GetProcessHeap(), 0, fiber );
962 return NULL;
965 fiber->stack_allocation = stack.DeallocationStack;
966 fiber->stack_base = stack.StackBase;
967 fiber->stack_limit = stack.StackLimit;
968 fiber->param = param;
969 fiber->except = (void *)-1;
970 fiber->start = start;
971 fiber->flags = flags;
972 init_fiber_context( fiber );
973 return fiber;
977 /***********************************************************************
978 * ConvertFiberToThread (kernelbase.@)
980 BOOL WINAPI DECLSPEC_HOTPATCH ConvertFiberToThread(void)
982 struct fiber_data *fiber = NtCurrentTeb()->Tib.u.FiberData;
984 if (fiber)
986 NtCurrentTeb()->Tib.u.FiberData = NULL;
987 HeapFree( GetProcessHeap(), 0, fiber );
989 return TRUE;
993 /***********************************************************************
994 * ConvertThreadToFiber (kernelbase.@)
996 LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiber( LPVOID param )
998 return ConvertThreadToFiberEx( param, 0 );
1002 /***********************************************************************
1003 * ConvertThreadToFiberEx (kernelbase.@)
1005 LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flags )
1007 struct fiber_data *fiber;
1009 if (NtCurrentTeb()->Tib.u.FiberData)
1011 SetLastError( ERROR_ALREADY_FIBER );
1012 return NULL;
1015 if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) )))
1017 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1018 return NULL;
1020 fiber->param = param;
1021 fiber->except = NtCurrentTeb()->Tib.ExceptionList;
1022 fiber->stack_base = NtCurrentTeb()->Tib.StackBase;
1023 fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit;
1024 fiber->stack_allocation = NtCurrentTeb()->DeallocationStack;
1025 fiber->start = NULL;
1026 fiber->flags = flags;
1027 fiber->fls_slots = NtCurrentTeb()->FlsSlots;
1028 NtCurrentTeb()->Tib.u.FiberData = fiber;
1029 return fiber;
1033 /***********************************************************************
1034 * DeleteFiber (kernelbase.@)
1036 void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr )
1038 struct fiber_data *fiber = fiber_ptr;
1040 if (!fiber) return;
1041 if (fiber == NtCurrentTeb()->Tib.u.FiberData)
1043 HeapFree( GetProcessHeap(), 0, fiber );
1044 RtlExitUserThread( 1 );
1046 RtlFreeUserStack( fiber->stack_allocation );
1047 RtlProcessFlsData( fiber->fls_slots, 3 );
1048 HeapFree( GetProcessHeap(), 0, fiber );
1052 /***********************************************************************
1053 * IsThreadAFiber (kernelbase.@)
1055 BOOL WINAPI DECLSPEC_HOTPATCH IsThreadAFiber(void)
1057 return NtCurrentTeb()->Tib.u.FiberData != NULL;
1061 /***********************************************************************
1062 * SwitchToFiber (kernelbase.@)
1064 void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber )
1066 struct fiber_data *new_fiber = fiber;
1067 struct fiber_data *current_fiber = NtCurrentTeb()->Tib.u.FiberData;
1069 current_fiber->except = NtCurrentTeb()->Tib.ExceptionList;
1070 current_fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit;
1071 current_fiber->fls_slots = NtCurrentTeb()->FlsSlots;
1072 /* stack_allocation and stack_base never change */
1074 /* FIXME: should save floating point context if requested in fiber->flags */
1075 NtCurrentTeb()->Tib.u.FiberData = new_fiber;
1076 NtCurrentTeb()->Tib.ExceptionList = new_fiber->except;
1077 NtCurrentTeb()->Tib.StackBase = new_fiber->stack_base;
1078 NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit;
1079 NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
1080 NtCurrentTeb()->FlsSlots = new_fiber->fls_slots;
1081 switch_fiber( &current_fiber->context, &new_fiber->context );
1085 /***********************************************************************
1086 * FlsAlloc (kernelbase.@)
1088 DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback )
1090 DWORD index;
1092 if (!set_ntstatus( RtlFlsAlloc( callback, &index ))) return FLS_OUT_OF_INDEXES;
1093 return index;
1097 /***********************************************************************
1098 * FlsFree (kernelbase.@)
1100 BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index )
1102 return set_ntstatus( RtlFlsFree( index ));
1106 /***********************************************************************
1107 * FlsGetValue (kernelbase.@)
1109 PVOID WINAPI DECLSPEC_HOTPATCH FlsGetValue( DWORD index )
1111 void *data;
1113 if (!set_ntstatus( RtlFlsGetValue( index, &data ))) return NULL;
1114 SetLastError( ERROR_SUCCESS );
1115 return data;
1119 /***********************************************************************
1120 * FlsSetValue (kernelbase.@)
1122 BOOL WINAPI DECLSPEC_HOTPATCH FlsSetValue( DWORD index, PVOID data )
1124 return set_ntstatus( RtlFlsSetValue( index, data ));
1128 /***********************************************************************
1129 * Thread pool
1130 ***********************************************************************/
1133 /***********************************************************************
1134 * CallbackMayRunLong (kernelbase.@)
1136 BOOL WINAPI DECLSPEC_HOTPATCH CallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
1138 return set_ntstatus( TpCallbackMayRunLong( instance ));
1142 /***********************************************************************
1143 * CreateThreadpool (kernelbase.@)
1145 PTP_POOL WINAPI DECLSPEC_HOTPATCH CreateThreadpool( void *reserved )
1147 TP_POOL *pool;
1149 if (!set_ntstatus( TpAllocPool( &pool, reserved ))) pool = NULL;
1150 return pool;
1154 /***********************************************************************
1155 * CreateThreadpoolCleanupGroup (kernelbase.@)
1157 PTP_CLEANUP_GROUP WINAPI DECLSPEC_HOTPATCH CreateThreadpoolCleanupGroup(void)
1159 TP_CLEANUP_GROUP *group;
1161 if (!set_ntstatus( TpAllocCleanupGroup( &group ))) return NULL;
1162 return group;
1166 static void WINAPI tp_io_callback( TP_CALLBACK_INSTANCE *instance, void *userdata, void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io )
1168 PTP_WIN32_IO_CALLBACK callback = *(void **)io;
1169 callback( instance, userdata, cvalue, RtlNtStatusToDosError( iosb->u.Status ), iosb->Information, io );
1173 /***********************************************************************
1174 * CreateThreadpoolIo (kernelbase.@)
1176 PTP_IO WINAPI DECLSPEC_HOTPATCH CreateThreadpoolIo( HANDLE handle, PTP_WIN32_IO_CALLBACK callback,
1177 PVOID userdata, TP_CALLBACK_ENVIRON *environment )
1179 TP_IO *io;
1180 if (!set_ntstatus( TpAllocIoCompletion( &io, handle, tp_io_callback, userdata, environment ))) return NULL;
1181 *(void **)io = callback; /* ntdll leaves us space to store our callback at the beginning of TP_IO struct */
1182 return io;
1186 /***********************************************************************
1187 * CreateThreadpoolTimer (kernelbase.@)
1189 PTP_TIMER WINAPI DECLSPEC_HOTPATCH CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userdata,
1190 TP_CALLBACK_ENVIRON *environment )
1192 TP_TIMER *timer;
1194 if (!set_ntstatus( TpAllocTimer( &timer, callback, userdata, environment ))) return NULL;
1195 return timer;
1199 /***********************************************************************
1200 * CreateThreadpoolWait (kernelbase.@)
1202 PTP_WAIT WINAPI DECLSPEC_HOTPATCH CreateThreadpoolWait( PTP_WAIT_CALLBACK callback, PVOID userdata,
1203 TP_CALLBACK_ENVIRON *environment )
1205 TP_WAIT *wait;
1207 if (!set_ntstatus( TpAllocWait( &wait, callback, userdata, environment ))) return NULL;
1208 return wait;
1212 /***********************************************************************
1213 * CreateThreadpoolWork (kernelbase.@)
1215 PTP_WORK WINAPI DECLSPEC_HOTPATCH CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata,
1216 TP_CALLBACK_ENVIRON *environment )
1218 TP_WORK *work;
1220 if (!set_ntstatus( TpAllocWork( &work, callback, userdata, environment ))) return NULL;
1221 return work;
1225 /***********************************************************************
1226 * TrySubmitThreadpoolCallback (kernelbase.@)
1228 BOOL WINAPI DECLSPEC_HOTPATCH TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
1229 TP_CALLBACK_ENVIRON *environment )
1231 return set_ntstatus( TpSimpleTryPost( callback, userdata, environment ));
1235 /***********************************************************************
1236 * QueueUserWorkItem (kernelbase.@)
1238 BOOL WINAPI DECLSPEC_HOTPATCH QueueUserWorkItem( LPTHREAD_START_ROUTINE func, PVOID context, ULONG flags )
1240 return set_ntstatus( RtlQueueWorkItem( func, context, flags ));
1243 /***********************************************************************
1244 * SetThreadpoolStackInformation (kernelbase.@)
1246 BOOL WINAPI DECLSPEC_HOTPATCH SetThreadpoolStackInformation( PTP_POOL pool, PTP_POOL_STACK_INFORMATION stack_info )
1248 return set_ntstatus( TpSetPoolStackInformation( pool, stack_info ));
1251 /***********************************************************************
1252 * QueryThreadpoolStackInformation (kernelbase.@)
1254 BOOL WINAPI DECLSPEC_HOTPATCH QueryThreadpoolStackInformation( PTP_POOL pool, PTP_POOL_STACK_INFORMATION stack_info )
1256 return set_ntstatus( TpQueryPoolStackInformation( pool, stack_info ));