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
26 #define WIN32_NO_STATUS
27 #define NONAMELESSUNION
33 #include "kernelbase.h"
34 #include "wine/exception.h"
36 #include "wine/debug.h"
37 #include "wine/heap.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(thread
);
42 /***********************************************************************
44 ***********************************************************************/
47 static DWORD
rtlmode_to_win32mode( DWORD rtlmode
)
51 if (rtlmode
& 0x10) win32mode
|= SEM_FAILCRITICALERRORS
;
52 if (rtlmode
& 0x20) win32mode
|= SEM_NOGPFAULTERRORBOX
;
53 if (rtlmode
& 0x40) win32mode
|= SEM_NOOPENFILEERRORBOX
;
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
)
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
)))
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
))
97 if (NtResumeThread( handle
, &ret
))
100 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
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
)))
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
)
217 SetLastError( ERROR_INVALID_PARAMETER
);
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
)))
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();
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
, ×
, sizeof(times
), NULL
)))
304 creationtime
->dwLowDateTime
= times
.CreateTime
.u
.LowPart
;
305 creationtime
->dwHighDateTime
= times
.CreateTime
.u
.HighPart
;
309 exittime
->dwLowDateTime
= times
.ExitTime
.u
.LowPart
;
310 exittime
->dwHighDateTime
= times
.ExitTime
.u
.HighPart
;
314 kerneltime
->dwLowDateTime
= times
.KernelTime
.u
.LowPart
;
315 kerneltime
->dwHighDateTime
= times
.KernelTime
.u
.HighPart
;
319 usertime
->dwLowDateTime
= times
.UserTime
.u
.LowPart
;
320 usertime
->dwHighDateTime
= times
.UserTime
.u
.HighPart
;
326 /***********************************************************************
327 * GetThreadUILanguage (kernelbase.@)
329 LANGID WINAPI DECLSPEC_HOTPATCH
GetThreadUILanguage(void)
333 FIXME(": stub, returning default language.\n");
334 NtQueryDefaultUILanguage( &lang
);
339 /***********************************************************************
340 * OpenThread (kernelbase.@)
342 HANDLE WINAPI DECLSPEC_HOTPATCH
OpenThread( DWORD access
, BOOL inherit
, DWORD id
)
345 OBJECT_ATTRIBUTES attr
;
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;
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
;
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
)
385 if (!once
++) FIXME( "(%p,%p): stub!\n", thread
, cycle
);
386 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
391 /**********************************************************************
392 * ResumeThread (kernelbase.@)
394 DWORD WINAPI DECLSPEC_HOTPATCH
ResumeThread( HANDLE thread
)
398 if (!set_ntstatus( NtResumeThread( thread
, &ret
))) ret
= ~0U;
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
;
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
;
442 TRACE( "(%p, %p)\n", thread
, description
);
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
);
457 if (!(*description
= LocalAlloc( 0, info
->ThreadName
.Length
+ sizeof(WCHAR
))))
458 status
= STATUS_NO_MEMORY
;
461 if (info
->ThreadName
.Length
)
462 memcpy(*description
, info
->ThreadName
.Buffer
, info
->ThreadName
.Length
);
463 (*description
)[info
->ThreadName
.Length
/ sizeof(WCHAR
)] = 0;
469 return HRESULT_FROM_NT(status
);
472 /***********************************************************************
473 * SetThreadErrorMode (kernelbase.@)
475 BOOL WINAPI
SetThreadErrorMode( DWORD mode
, DWORD
*old
)
480 if (mode
& ~(SEM_FAILCRITICALERRORS
| SEM_NOGPFAULTERRORBOX
| SEM_NOOPENFILEERRORBOX
))
482 SetLastError( ERROR_INVALID_PARAMETER
);
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
)
514 status
= NtSetInformationThread( thread
, ThreadIdealProcessor
, &proc
, sizeof(proc
) );
515 if (NT_SUCCESS(status
)) return status
;
517 SetLastError( RtlNtStatusToDosError( status
));
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
);
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
);
547 NtCurrentTeb()->CurrentLocale
= lcid
;
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 );
584 if (new_size
>= (char *)NtCurrentTeb()->Tib
.StackBase
- (char *)NtCurrentTeb()->DeallocationStack
)
586 SetLastError( ERROR_INVALID_PARAMETER
);
589 if (new_size
> prev_size
) NtCurrentTeb()->GuaranteedStackBytes
= (new_size
+ 4095) & ~4095;
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();
606 /**********************************************************************
607 * SetThreadInformation (kernelbase.@)
609 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadInformation( HANDLE thread
, THREAD_INFORMATION_CLASS info_class
,
610 VOID
*info
, DWORD size
)
614 case ThreadMemoryPriority
:
615 return set_ntstatus( NtSetInformationThread( thread
, ThreadPagePriority
, info
, size
));
616 case ThreadPowerThrottling
:
617 return set_ntstatus( NtSetInformationThread( thread
, ThreadPowerThrottlingState
, info
, size
));
619 FIXME("Unsupported class %u.\n", info_class
);
625 /**********************************************************************
626 * SuspendThread (kernelbase.@)
628 DWORD WINAPI DECLSPEC_HOTPATCH
SuspendThread( HANDLE thread
)
632 if (!set_ntstatus( NtSuspendThread( thread
, &ret
))) ret
= ~0U;
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)
661 PEB
* const peb
= NtCurrentTeb()->Peb
;
664 index
= RtlFindClearBitsAndSet( peb
->TlsBitmap
, 1, 1 );
665 if (index
!= ~0U) NtCurrentTeb()->TlsSlots
[index
] = 0; /* clear the value */
668 index
= RtlFindClearBitsAndSet( peb
->TlsExpansionBitmap
, 1, 0 );
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 );
677 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
681 NtCurrentTeb()->TlsExpansionSlots
[index
] = 0; /* clear the value */
682 index
+= TLS_MINIMUM_AVAILABLE
;
685 else SetLastError( ERROR_NO_MORE_ITEMS
);
692 /**********************************************************************
693 * TlsFree (kernelbase.@)
695 BOOL WINAPI DECLSPEC_HOTPATCH
TlsFree( DWORD index
)
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 );
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
);
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
);
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
;
747 index
-= TLS_MINIMUM_AVAILABLE
;
748 if (index
>= 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
))
750 SetLastError( ERROR_INVALID_PARAMETER
);
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
);
760 NtCurrentTeb()->TlsExpansionSlots
[index
] = value
;
766 /***********************************************************************
768 ***********************************************************************/
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 );
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 */
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 */
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 */
892 void WINAPI
switch_fiber( CONTEXT
*old
, CONTEXT
*new )
894 FIXME( "not implemented\n" );
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
;
907 start( fiber
->param
);
908 RtlExitUserThread( 1 );
910 __EXCEPT(UnhandledExceptionFilter
)
912 TerminateThread( GetCurrentThread(), GetExceptionCode() );
917 static void init_fiber_context( struct fiber_data
*fiber
)
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
;
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
;
953 if (!(fiber
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*fiber
) )))
955 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
959 if (!set_ntstatus( RtlCreateUserStack( stack_commit
, stack_reserve
, 0, 1, 1, &stack
)))
961 HeapFree( GetProcessHeap(), 0, fiber
);
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
);
977 /***********************************************************************
978 * ConvertFiberToThread (kernelbase.@)
980 BOOL WINAPI DECLSPEC_HOTPATCH
ConvertFiberToThread(void)
982 struct fiber_data
*fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
986 NtCurrentTeb()->Tib
.u
.FiberData
= NULL
;
987 HeapFree( GetProcessHeap(), 0, fiber
);
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
);
1015 if (!(fiber
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber
) )))
1017 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
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
;
1033 /***********************************************************************
1034 * DeleteFiber (kernelbase.@)
1036 void WINAPI DECLSPEC_HOTPATCH
DeleteFiber( LPVOID fiber_ptr
)
1038 struct fiber_data
*fiber
= fiber_ptr
;
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( ¤t_fiber
->context
, &new_fiber
->context
);
1085 /***********************************************************************
1086 * FlsAlloc (kernelbase.@)
1088 DWORD WINAPI DECLSPEC_HOTPATCH
FlsAlloc( PFLS_CALLBACK_FUNCTION callback
)
1092 if (!set_ntstatus( RtlFlsAlloc( callback
, &index
))) return FLS_OUT_OF_INDEXES
;
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
)
1113 if (!set_ntstatus( RtlFlsGetValue( index
, &data
))) return NULL
;
1114 SetLastError( ERROR_SUCCESS
);
1119 /***********************************************************************
1120 * FlsSetValue (kernelbase.@)
1122 BOOL WINAPI DECLSPEC_HOTPATCH
FlsSetValue( DWORD index
, PVOID data
)
1124 return set_ntstatus( RtlFlsSetValue( index
, data
));
1128 /***********************************************************************
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
)
1149 if (!set_ntstatus( TpAllocPool( &pool
, reserved
))) pool
= NULL
;
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
;
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
)
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 */
1186 /***********************************************************************
1187 * CreateThreadpoolTimer (kernelbase.@)
1189 PTP_TIMER WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback
, PVOID userdata
,
1190 TP_CALLBACK_ENVIRON
*environment
)
1194 if (!set_ntstatus( TpAllocTimer( &timer
, callback
, userdata
, environment
))) return NULL
;
1199 /***********************************************************************
1200 * CreateThreadpoolWait (kernelbase.@)
1202 PTP_WAIT WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolWait( PTP_WAIT_CALLBACK callback
, PVOID userdata
,
1203 TP_CALLBACK_ENVIRON
*environment
)
1207 if (!set_ntstatus( TpAllocWait( &wait
, callback
, userdata
, environment
))) return NULL
;
1212 /***********************************************************************
1213 * CreateThreadpoolWork (kernelbase.@)
1215 PTP_WORK WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolWork( PTP_WORK_CALLBACK callback
, PVOID userdata
,
1216 TP_CALLBACK_ENVIRON
*environment
)
1220 if (!set_ntstatus( TpAllocWork( &work
, callback
, userdata
, environment
))) return NULL
;
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
));