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 FIXME( "(%p %p): stub\n", thread
, ideal
);
254 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
259 /***********************************************************************
260 * GetThreadLocale (kernelbase.@)
262 LCID WINAPI
/* DECLSPEC_HOTPATCH */ GetThreadLocale(void)
264 LCID ret
= NtCurrentTeb()->CurrentLocale
;
265 if (!ret
) NtCurrentTeb()->CurrentLocale
= ret
= GetUserDefaultLCID();
270 /**********************************************************************
271 * GetThreadPriority (kernelbase.@)
273 INT WINAPI DECLSPEC_HOTPATCH
GetThreadPriority( HANDLE thread
)
275 THREAD_BASIC_INFORMATION info
;
277 if (!set_ntstatus( NtQueryInformationThread( thread
, ThreadBasicInformation
,
278 &info
, sizeof(info
), NULL
)))
279 return THREAD_PRIORITY_ERROR_RETURN
;
280 return info
.Priority
;
284 /**********************************************************************
285 * GetThreadPriorityBoost (kernelbase.@)
287 BOOL WINAPI DECLSPEC_HOTPATCH
GetThreadPriorityBoost( HANDLE thread
, BOOL
*state
)
289 if (state
) *state
= FALSE
;
294 /**********************************************************************
295 * GetThreadTimes (kernelbase.@)
297 BOOL WINAPI DECLSPEC_HOTPATCH
GetThreadTimes( HANDLE thread
, LPFILETIME creationtime
, LPFILETIME exittime
,
298 LPFILETIME kerneltime
, LPFILETIME usertime
)
300 KERNEL_USER_TIMES times
;
302 if (!set_ntstatus( NtQueryInformationThread( thread
, ThreadTimes
, ×
, sizeof(times
), NULL
)))
307 creationtime
->dwLowDateTime
= times
.CreateTime
.u
.LowPart
;
308 creationtime
->dwHighDateTime
= times
.CreateTime
.u
.HighPart
;
312 exittime
->dwLowDateTime
= times
.ExitTime
.u
.LowPart
;
313 exittime
->dwHighDateTime
= times
.ExitTime
.u
.HighPart
;
317 kerneltime
->dwLowDateTime
= times
.KernelTime
.u
.LowPart
;
318 kerneltime
->dwHighDateTime
= times
.KernelTime
.u
.HighPart
;
322 usertime
->dwLowDateTime
= times
.UserTime
.u
.LowPart
;
323 usertime
->dwHighDateTime
= times
.UserTime
.u
.HighPart
;
329 /***********************************************************************
330 * GetThreadUILanguage (kernelbase.@)
332 LANGID WINAPI DECLSPEC_HOTPATCH
GetThreadUILanguage(void)
336 FIXME(": stub, returning default language.\n");
337 NtQueryDefaultUILanguage( &lang
);
342 /***********************************************************************
343 * OpenThread (kernelbase.@)
345 HANDLE WINAPI DECLSPEC_HOTPATCH
OpenThread( DWORD access
, BOOL inherit
, DWORD id
)
348 OBJECT_ATTRIBUTES attr
;
351 attr
.Length
= sizeof(attr
);
352 attr
.RootDirectory
= 0;
353 attr
.Attributes
= inherit
? OBJ_INHERIT
: 0;
354 attr
.ObjectName
= NULL
;
355 attr
.SecurityDescriptor
= NULL
;
356 attr
.SecurityQualityOfService
= NULL
;
358 cid
.UniqueProcess
= 0;
359 cid
.UniqueThread
= ULongToHandle( id
);
361 if (!set_ntstatus( NtOpenThread( &handle
, access
, &attr
, &cid
))) handle
= 0;
366 /* callback for QueueUserAPC */
367 static void CALLBACK
call_user_apc( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG_PTR arg3
)
369 PAPCFUNC func
= (PAPCFUNC
)arg1
;
373 /***********************************************************************
374 * QueueUserAPC (kernelbase.@)
376 DWORD WINAPI DECLSPEC_HOTPATCH
QueueUserAPC( PAPCFUNC func
, HANDLE thread
, ULONG_PTR data
)
378 return set_ntstatus( NtQueueApcThread( thread
, call_user_apc
, (ULONG_PTR
)func
, data
, 0 ));
382 /***********************************************************************
383 * QueryThreadCycleTime (kernelbase.@)
385 BOOL WINAPI DECLSPEC_HOTPATCH
QueryThreadCycleTime( HANDLE thread
, ULONG64
*cycle
)
388 if (!once
++) FIXME( "(%p,%p): stub!\n", thread
, cycle
);
389 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
394 /**********************************************************************
395 * ResumeThread (kernelbase.@)
397 DWORD WINAPI DECLSPEC_HOTPATCH
ResumeThread( HANDLE thread
)
401 if (!set_ntstatus( NtResumeThread( thread
, &ret
))) ret
= ~0U;
406 /***********************************************************************
407 * SetThreadContext (kernelbase.@)
409 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadContext( HANDLE thread
, const CONTEXT
*context
)
411 return set_ntstatus( NtSetContextThread( thread
, context
));
415 /***********************************************************************
416 * SetThreadDescription (kernelbase.@)
418 HRESULT WINAPI DECLSPEC_HOTPATCH
SetThreadDescription( HANDLE thread
, PCWSTR description
)
420 THREAD_NAME_INFORMATION info
;
423 TRACE( "(%p, %s)\n", thread
, debugstr_w( description
));
425 length
= description
? lstrlenW( description
) * sizeof(WCHAR
) : 0;
427 if (length
> USHRT_MAX
)
428 return HRESULT_FROM_NT(STATUS_INVALID_PARAMETER
);
430 info
.ThreadName
.Length
= info
.ThreadName
.MaximumLength
= length
;
431 info
.ThreadName
.Buffer
= (WCHAR
*)description
;
433 return HRESULT_FROM_NT(NtSetInformationThread( thread
, ThreadNameInformation
, &info
, sizeof(info
) ));
436 /***********************************************************************
437 * GetThreadDescription (kernelbase.@)
439 HRESULT WINAPI DECLSPEC_HOTPATCH
GetThreadDescription( HANDLE thread
, WCHAR
**description
)
441 THREAD_NAME_INFORMATION
*info
;
445 TRACE( "(%p, %p)\n", thread
, description
);
450 status
= NtQueryInformationThread( thread
, ThreadNameInformation
, NULL
, 0, &length
);
451 if (status
!= STATUS_BUFFER_TOO_SMALL
)
452 return HRESULT_FROM_NT(status
);
454 if (!(info
= heap_alloc( length
)))
455 return HRESULT_FROM_NT(STATUS_NO_MEMORY
);
457 status
= NtQueryInformationThread( thread
, ThreadNameInformation
, info
, length
, &length
);
460 if (!(*description
= LocalAlloc( 0, info
->ThreadName
.Length
+ sizeof(WCHAR
))))
461 status
= STATUS_NO_MEMORY
;
464 if (info
->ThreadName
.Length
)
465 memcpy(*description
, info
->ThreadName
.Buffer
, info
->ThreadName
.Length
);
466 (*description
)[info
->ThreadName
.Length
/ sizeof(WCHAR
)] = 0;
472 return HRESULT_FROM_NT(status
);
475 /***********************************************************************
476 * SetThreadErrorMode (kernelbase.@)
478 BOOL WINAPI
SetThreadErrorMode( DWORD mode
, DWORD
*old
)
483 if (mode
& ~(SEM_FAILCRITICALERRORS
| SEM_NOGPFAULTERRORBOX
| SEM_NOOPENFILEERRORBOX
))
485 SetLastError( ERROR_INVALID_PARAMETER
);
489 if (mode
& SEM_FAILCRITICALERRORS
) new |= 0x10;
490 if (mode
& SEM_NOGPFAULTERRORBOX
) new |= 0x20;
491 if (mode
& SEM_NOOPENFILEERRORBOX
) new |= 0x40;
493 status
= RtlSetThreadErrorMode( new, old
);
494 if (!status
&& old
) *old
= rtlmode_to_win32mode( *old
);
495 return set_ntstatus( status
);
499 /***********************************************************************
500 * SetThreadGroupAffinity (kernelbase.@)
502 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadGroupAffinity( HANDLE thread
, const GROUP_AFFINITY
*new,
503 GROUP_AFFINITY
*old
)
505 if (old
&& !GetThreadGroupAffinity( thread
, old
)) return FALSE
;
506 return set_ntstatus( NtSetInformationThread( thread
, ThreadGroupInformation
, new, sizeof(*new) ));
510 /**********************************************************************
511 * SetThreadIdealProcessor (kernelbase.@)
513 DWORD WINAPI DECLSPEC_HOTPATCH
SetThreadIdealProcessor( HANDLE thread
, DWORD proc
)
515 FIXME( "(%p %lu): stub\n", thread
, proc
);
516 if (proc
> MAXIMUM_PROCESSORS
)
518 SetLastError( ERROR_INVALID_PARAMETER
);
525 /***********************************************************************
526 * SetThreadIdealProcessorEx (kernelbase.@)
528 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadIdealProcessorEx( HANDLE thread
, PROCESSOR_NUMBER
*ideal
,
529 PROCESSOR_NUMBER
*previous
)
531 FIXME( "(%p %p %p): stub\n", thread
, ideal
, previous
);
532 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
537 /**********************************************************************
538 * SetThreadLocale (kernelbase.@)
540 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadLocale( LCID lcid
)
542 lcid
= ConvertDefaultLocale( lcid
);
543 if (lcid
!= GetThreadLocale())
545 if (!IsValidLocale( lcid
, LCID_SUPPORTED
))
547 SetLastError( ERROR_INVALID_PARAMETER
);
550 NtCurrentTeb()->CurrentLocale
= lcid
;
556 /**********************************************************************
557 * SetThreadPriority (kernelbase.@)
559 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadPriority( HANDLE thread
, INT priority
)
561 DWORD prio
= priority
;
562 return set_ntstatus( NtSetInformationThread( thread
, ThreadBasePriority
, &prio
, sizeof(prio
) ));
566 /**********************************************************************
567 * SetThreadPriorityBoost (kernelbase.@)
569 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadPriorityBoost( HANDLE thread
, BOOL disable
)
575 /**********************************************************************
576 * SetThreadStackGuarantee (kernelbase.@)
578 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadStackGuarantee( ULONG
*size
)
580 ULONG prev_size
= NtCurrentTeb()->GuaranteedStackBytes
;
581 ULONG new_size
= (*size
+ 4095) & ~4095;
583 /* at least 2 pages on 64-bit */
584 if (sizeof(void *) > sizeof(int) && new_size
) new_size
= max( new_size
, 8192 );
587 if (new_size
>= (char *)NtCurrentTeb()->Tib
.StackBase
- (char *)NtCurrentTeb()->DeallocationStack
)
589 SetLastError( ERROR_INVALID_PARAMETER
);
592 if (new_size
> prev_size
) NtCurrentTeb()->GuaranteedStackBytes
= (new_size
+ 4095) & ~4095;
597 /**********************************************************************
598 * SetThreadUILanguage (kernelbase.@)
600 LANGID WINAPI DECLSPEC_HOTPATCH
SetThreadUILanguage( LANGID langid
)
602 TRACE( "(0x%04x) stub - returning success\n", langid
);
604 if (!langid
) langid
= GetThreadUILanguage();
609 /**********************************************************************
610 * SetThreadInformation (kernelbase.@)
612 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadInformation( HANDLE thread
, THREAD_INFORMATION_CLASS info_class
,
613 VOID
*info
, DWORD size
)
617 case ThreadMemoryPriority
:
618 return set_ntstatus( NtSetInformationThread( thread
, ThreadPagePriority
, info
, size
));
619 case ThreadPowerThrottling
:
620 return set_ntstatus( NtSetInformationThread( thread
, ThreadPowerThrottlingState
, info
, size
));
622 FIXME("Unsupported class %u.\n", info_class
);
628 /**********************************************************************
629 * SuspendThread (kernelbase.@)
631 DWORD WINAPI DECLSPEC_HOTPATCH
SuspendThread( HANDLE thread
)
635 if (!set_ntstatus( NtSuspendThread( thread
, &ret
))) ret
= ~0U;
640 /***********************************************************************
641 * SwitchToThread (kernelbase.@)
643 BOOL WINAPI DECLSPEC_HOTPATCH
SwitchToThread(void)
645 return (NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
);
649 /**********************************************************************
650 * TerminateThread (kernelbase.@)
652 BOOL WINAPI DECLSPEC_HOTPATCH
TerminateThread( HANDLE handle
, DWORD exit_code
)
654 return set_ntstatus( NtTerminateThread( handle
, exit_code
));
658 /**********************************************************************
659 * TlsAlloc (kernelbase.@)
661 DWORD WINAPI DECLSPEC_HOTPATCH
TlsAlloc(void)
664 PEB
* const peb
= NtCurrentTeb()->Peb
;
667 index
= RtlFindClearBitsAndSet( peb
->TlsBitmap
, 1, 1 );
668 if (index
!= ~0U) NtCurrentTeb()->TlsSlots
[index
] = 0; /* clear the value */
671 index
= RtlFindClearBitsAndSet( peb
->TlsExpansionBitmap
, 1, 0 );
674 if (!NtCurrentTeb()->TlsExpansionSlots
&&
675 !(NtCurrentTeb()->TlsExpansionSlots
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
676 8 * sizeof(peb
->TlsExpansionBitmapBits
) * sizeof(void*) )))
678 RtlClearBits( peb
->TlsExpansionBitmap
, index
, 1 );
680 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
684 NtCurrentTeb()->TlsExpansionSlots
[index
] = 0; /* clear the value */
685 index
+= TLS_MINIMUM_AVAILABLE
;
688 else SetLastError( ERROR_NO_MORE_ITEMS
);
695 /**********************************************************************
696 * TlsFree (kernelbase.@)
698 BOOL WINAPI DECLSPEC_HOTPATCH
TlsFree( DWORD index
)
703 if (index
>= TLS_MINIMUM_AVAILABLE
)
705 ret
= RtlAreBitsSet( NtCurrentTeb()->Peb
->TlsExpansionBitmap
, index
- TLS_MINIMUM_AVAILABLE
, 1 );
706 if (ret
) RtlClearBits( NtCurrentTeb()->Peb
->TlsExpansionBitmap
, index
- TLS_MINIMUM_AVAILABLE
, 1 );
710 ret
= RtlAreBitsSet( NtCurrentTeb()->Peb
->TlsBitmap
, index
, 1 );
711 if (ret
) RtlClearBits( NtCurrentTeb()->Peb
->TlsBitmap
, index
, 1 );
713 if (ret
) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell
, &index
, sizeof(index
) );
714 else SetLastError( ERROR_INVALID_PARAMETER
);
720 /**********************************************************************
721 * TlsGetValue (kernelbase.@)
723 LPVOID WINAPI DECLSPEC_HOTPATCH
TlsGetValue( DWORD index
)
725 SetLastError( ERROR_SUCCESS
);
726 if (index
< TLS_MINIMUM_AVAILABLE
) return NtCurrentTeb()->TlsSlots
[index
];
728 index
-= TLS_MINIMUM_AVAILABLE
;
729 if (index
>= 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
))
731 SetLastError( ERROR_INVALID_PARAMETER
);
734 if (!NtCurrentTeb()->TlsExpansionSlots
) return NULL
;
735 return NtCurrentTeb()->TlsExpansionSlots
[index
];
739 /**********************************************************************
740 * TlsSetValue (kernelbase.@)
742 BOOL WINAPI DECLSPEC_HOTPATCH
TlsSetValue( DWORD index
, LPVOID value
)
744 if (index
< TLS_MINIMUM_AVAILABLE
)
746 NtCurrentTeb()->TlsSlots
[index
] = value
;
750 index
-= TLS_MINIMUM_AVAILABLE
;
751 if (index
>= 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
))
753 SetLastError( ERROR_INVALID_PARAMETER
);
756 if (!NtCurrentTeb()->TlsExpansionSlots
&&
757 !(NtCurrentTeb()->TlsExpansionSlots
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
758 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
) * sizeof(void*) )))
760 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
763 NtCurrentTeb()->TlsExpansionSlots
[index
] = value
;
769 /***********************************************************************
771 ***********************************************************************/
776 LPVOID param
; /* 00/00 fiber param */
777 void *except
; /* 04/08 saved exception handlers list */
778 void *stack_base
; /* 08/10 top of fiber stack */
779 void *stack_limit
; /* 0c/18 fiber stack low-water mark */
780 void *stack_allocation
; /* 10/20 base of the fiber stack allocation */
781 CONTEXT context
; /* 14/30 fiber context */
782 DWORD flags
; /* fiber flags */
783 LPFIBER_START_ROUTINE start
; /* start routine */
784 void *fls_slots
; /* fiber storage slots */
787 extern void WINAPI
switch_fiber( CONTEXT
*old
, CONTEXT
*new );
789 __ASM_STDCALL_FUNC( switch_fiber
, 8,
790 "movl 4(%esp),%ecx\n\t" /* old */
791 "movl %edi,0x9c(%ecx)\n\t" /* old->Edi */
792 "movl %esi,0xa0(%ecx)\n\t" /* old->Esi */
793 "movl %ebx,0xa4(%ecx)\n\t" /* old->Ebx */
794 "movl %ebp,0xb4(%ecx)\n\t" /* old->Ebp */
795 "movl 0(%esp),%eax\n\t"
796 "movl %eax,0xb8(%ecx)\n\t" /* old->Eip */
797 "leal 12(%esp),%eax\n\t"
798 "movl %eax,0xc4(%ecx)\n\t" /* old->Esp */
799 "movl 8(%esp),%ecx\n\t" /* new */
800 "movl 0x9c(%ecx),%edi\n\t" /* new->Edi */
801 "movl 0xa0(%ecx),%esi\n\t" /* new->Esi */
802 "movl 0xa4(%ecx),%ebx\n\t" /* new->Ebx */
803 "movl 0xb4(%ecx),%ebp\n\t" /* new->Ebp */
804 "movl 0xc4(%ecx),%esp\n\t" /* new->Esp */
805 "jmp *0xb8(%ecx)" ) /* new->Eip */
806 #elif defined(__x86_64__)
807 __ASM_STDCALL_FUNC( switch_fiber
, 8,
808 "movq %rbx,0x90(%rcx)\n\t" /* old->Rbx */
809 "leaq 0x8(%rsp),%rax\n\t"
810 "movq %rax,0x98(%rcx)\n\t" /* old->Rsp */
811 "movq %rbp,0xa0(%rcx)\n\t" /* old->Rbp */
812 "movq %rsi,0xa8(%rcx)\n\t" /* old->Rsi */
813 "movq %rdi,0xb0(%rcx)\n\t" /* old->Rdi */
814 "movq %r12,0xd8(%rcx)\n\t" /* old->R12 */
815 "movq %r13,0xe0(%rcx)\n\t" /* old->R13 */
816 "movq %r14,0xe8(%rcx)\n\t" /* old->R14 */
817 "movq %r15,0xf0(%rcx)\n\t" /* old->R15 */
818 "movq (%rsp),%rax\n\t"
819 "movq %rax,0xf8(%rcx)\n\t" /* old->Rip */
820 "movdqa %xmm6,0x200(%rcx)\n\t" /* old->Xmm6 */
821 "movdqa %xmm7,0x210(%rcx)\n\t" /* old->Xmm7 */
822 "movdqa %xmm8,0x220(%rcx)\n\t" /* old->Xmm8 */
823 "movdqa %xmm9,0x230(%rcx)\n\t" /* old->Xmm9 */
824 "movdqa %xmm10,0x240(%rcx)\n\t" /* old->Xmm10 */
825 "movdqa %xmm11,0x250(%rcx)\n\t" /* old->Xmm11 */
826 "movdqa %xmm12,0x260(%rcx)\n\t" /* old->Xmm12 */
827 "movdqa %xmm13,0x270(%rcx)\n\t" /* old->Xmm13 */
828 "movdqa %xmm14,0x280(%rcx)\n\t" /* old->Xmm14 */
829 "movdqa %xmm15,0x290(%rcx)\n\t" /* old->Xmm15 */
830 "movq 0x90(%rdx),%rbx\n\t" /* new->Rbx */
831 "movq 0xa0(%rdx),%rbp\n\t" /* new->Rbp */
832 "movq 0xa8(%rdx),%rsi\n\t" /* new->Rsi */
833 "movq 0xb0(%rdx),%rdi\n\t" /* new->Rdi */
834 "movq 0xd8(%rdx),%r12\n\t" /* new->R12 */
835 "movq 0xe0(%rdx),%r13\n\t" /* new->R13 */
836 "movq 0xe8(%rdx),%r14\n\t" /* new->R14 */
837 "movq 0xf0(%rdx),%r15\n\t" /* new->R15 */
838 "movdqa 0x200(%rdx),%xmm6\n\t" /* new->Xmm6 */
839 "movdqa 0x210(%rdx),%xmm7\n\t" /* new->Xmm7 */
840 "movdqa 0x220(%rdx),%xmm8\n\t" /* new->Xmm8 */
841 "movdqa 0x230(%rdx),%xmm9\n\t" /* new->Xmm9 */
842 "movdqa 0x240(%rdx),%xmm10\n\t" /* new->Xmm10 */
843 "movdqa 0x250(%rdx),%xmm11\n\t" /* new->Xmm11 */
844 "movdqa 0x260(%rdx),%xmm12\n\t" /* new->Xmm12 */
845 "movdqa 0x270(%rdx),%xmm13\n\t" /* new->Xmm13 */
846 "movdqa 0x280(%rdx),%xmm14\n\t" /* new->Xmm14 */
847 "movdqa 0x290(%rdx),%xmm15\n\t" /* new->Xmm15 */
848 "movq 0x98(%rdx),%rsp\n\t" /* new->Rsp */
849 "jmp *0xf8(%rdx)" ) /* new->Rip */
850 #elif defined(__arm__)
851 __ASM_STDCALL_FUNC( switch_fiber
, 8,
852 "str r4, [r0, #0x14]\n\t" /* old->R4 */
853 "str r5, [r0, #0x18]\n\t" /* old->R5 */
854 "str r6, [r0, #0x1c]\n\t" /* old->R6 */
855 "str r7, [r0, #0x20]\n\t" /* old->R7 */
856 "str r8, [r0, #0x24]\n\t" /* old->R8 */
857 "str r9, [r0, #0x28]\n\t" /* old->R9 */
858 "str r10, [r0, #0x2c]\n\t" /* old->R10 */
859 "str r11, [r0, #0x30]\n\t" /* old->R11 */
860 "str sp, [r0, #0x38]\n\t" /* old->Sp */
861 "str lr, [r0, #0x40]\n\t" /* old->Pc */
862 "ldr r4, [r1, #0x14]\n\t" /* new->R4 */
863 "ldr r5, [r1, #0x18]\n\t" /* new->R5 */
864 "ldr r6, [r1, #0x1c]\n\t" /* new->R6 */
865 "ldr r7, [r1, #0x20]\n\t" /* new->R7 */
866 "ldr r8, [r1, #0x24]\n\t" /* new->R8 */
867 "ldr r9, [r1, #0x28]\n\t" /* new->R9 */
868 "ldr r10, [r1, #0x2c]\n\t" /* new->R10 */
869 "ldr r11, [r1, #0x30]\n\t" /* new->R11 */
870 "ldr sp, [r1, #0x38]\n\t" /* new->Sp */
871 "ldr r2, [r1, #0x40]\n\t" /* new->Pc */
873 #elif defined(__aarch64__)
874 __ASM_STDCALL_FUNC( switch_fiber
, 8,
875 "stp x19, x20, [x0, #0xa0]\n\t" /* old->X19,X20 */
876 "stp x21, x22, [x0, #0xb0]\n\t" /* old->X21,X22 */
877 "stp x23, x24, [x0, #0xc0]\n\t" /* old->X23,X24 */
878 "stp x25, x26, [x0, #0xd0]\n\t" /* old->X25,X26 */
879 "stp x27, x28, [x0, #0xe0]\n\t" /* old->X27,X28 */
880 "str x29, [x0, #0xf0]\n\t" /* old->Fp */
882 "str x2, [x0, #0x100]\n\t" /* old->Sp */
883 "str x30, [x0, #0x108]\n\t" /* old->Pc */
884 "ldp x19, x20, [x1, #0xa0]\n\t" /* new->X19,X20 */
885 "ldp x21, x22, [x1, #0xb0]\n\t" /* new->X21,X22 */
886 "ldp x23, x24, [x1, #0xc0]\n\t" /* new->X23,X24 */
887 "ldp x25, x26, [x1, #0xd0]\n\t" /* new->X25,X26 */
888 "ldp x27, x28, [x1, #0xe0]\n\t" /* new->X27,X28 */
889 "ldr x29, [x1, #0xf0]\n\t" /* new->Fp */
890 "ldr x2, [x1, #0x100]\n\t" /* new->Sp */
891 "ldr x30, [x1, #0x108]\n\t" /* new->Pc */
895 void WINAPI
switch_fiber( CONTEXT
*old
, CONTEXT
*new )
897 FIXME( "not implemented\n" );
902 /* call the fiber initial function once we have switched stack */
903 static void CDECL
start_fiber(void)
905 struct fiber_data
*fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
906 LPFIBER_START_ROUTINE start
= fiber
->start
;
910 start( fiber
->param
);
911 RtlExitUserThread( 1 );
913 __EXCEPT(UnhandledExceptionFilter
)
915 TerminateThread( GetCurrentThread(), GetExceptionCode() );
920 static void init_fiber_context( struct fiber_data
*fiber
)
923 fiber
->context
.Esp
= (ULONG_PTR
)fiber
->stack_base
- 4;
924 fiber
->context
.Eip
= (ULONG_PTR
)start_fiber
;
925 #elif defined(__x86_64__)
926 fiber
->context
.Rsp
= (ULONG_PTR
)fiber
->stack_base
- 0x28;
927 fiber
->context
.Rip
= (ULONG_PTR
)start_fiber
;
928 #elif defined(__arm__)
929 fiber
->context
.Sp
= (ULONG_PTR
)fiber
->stack_base
;
930 fiber
->context
.Pc
= (ULONG_PTR
)start_fiber
;
931 #elif defined(__aarch64__)
932 fiber
->context
.Sp
= (ULONG_PTR
)fiber
->stack_base
;
933 fiber
->context
.Pc
= (ULONG_PTR
)start_fiber
;
938 /***********************************************************************
939 * CreateFiber (kernelbase.@)
941 LPVOID WINAPI DECLSPEC_HOTPATCH
CreateFiber( SIZE_T stack
, LPFIBER_START_ROUTINE start
, LPVOID param
)
943 return CreateFiberEx( stack
, 0, 0, start
, param
);
947 /***********************************************************************
948 * CreateFiberEx (kernelbase.@)
950 LPVOID WINAPI DECLSPEC_HOTPATCH
CreateFiberEx( SIZE_T stack_commit
, SIZE_T stack_reserve
, DWORD flags
,
951 LPFIBER_START_ROUTINE start
, LPVOID param
)
953 struct fiber_data
*fiber
;
956 if (!(fiber
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*fiber
) )))
958 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
962 if (!set_ntstatus( RtlCreateUserStack( stack_commit
, stack_reserve
, 0, 1, 1, &stack
)))
964 HeapFree( GetProcessHeap(), 0, fiber
);
968 fiber
->stack_allocation
= stack
.DeallocationStack
;
969 fiber
->stack_base
= stack
.StackBase
;
970 fiber
->stack_limit
= stack
.StackLimit
;
971 fiber
->param
= param
;
972 fiber
->except
= (void *)-1;
973 fiber
->start
= start
;
974 fiber
->flags
= flags
;
975 init_fiber_context( fiber
);
980 /***********************************************************************
981 * ConvertFiberToThread (kernelbase.@)
983 BOOL WINAPI DECLSPEC_HOTPATCH
ConvertFiberToThread(void)
985 struct fiber_data
*fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
989 NtCurrentTeb()->Tib
.u
.FiberData
= NULL
;
990 HeapFree( GetProcessHeap(), 0, fiber
);
996 /***********************************************************************
997 * ConvertThreadToFiber (kernelbase.@)
999 LPVOID WINAPI DECLSPEC_HOTPATCH
ConvertThreadToFiber( LPVOID param
)
1001 return ConvertThreadToFiberEx( param
, 0 );
1005 /***********************************************************************
1006 * ConvertThreadToFiberEx (kernelbase.@)
1008 LPVOID WINAPI DECLSPEC_HOTPATCH
ConvertThreadToFiberEx( LPVOID param
, DWORD flags
)
1010 struct fiber_data
*fiber
;
1012 if (NtCurrentTeb()->Tib
.u
.FiberData
)
1014 SetLastError( ERROR_ALREADY_FIBER
);
1018 if (!(fiber
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber
) )))
1020 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1023 fiber
->param
= param
;
1024 fiber
->except
= NtCurrentTeb()->Tib
.ExceptionList
;
1025 fiber
->stack_base
= NtCurrentTeb()->Tib
.StackBase
;
1026 fiber
->stack_limit
= NtCurrentTeb()->Tib
.StackLimit
;
1027 fiber
->stack_allocation
= NtCurrentTeb()->DeallocationStack
;
1028 fiber
->start
= NULL
;
1029 fiber
->flags
= flags
;
1030 fiber
->fls_slots
= NtCurrentTeb()->FlsSlots
;
1031 NtCurrentTeb()->Tib
.u
.FiberData
= fiber
;
1036 /***********************************************************************
1037 * DeleteFiber (kernelbase.@)
1039 void WINAPI DECLSPEC_HOTPATCH
DeleteFiber( LPVOID fiber_ptr
)
1041 struct fiber_data
*fiber
= fiber_ptr
;
1044 if (fiber
== NtCurrentTeb()->Tib
.u
.FiberData
)
1046 HeapFree( GetProcessHeap(), 0, fiber
);
1047 RtlExitUserThread( 1 );
1049 RtlFreeUserStack( fiber
->stack_allocation
);
1050 RtlProcessFlsData( fiber
->fls_slots
, 3 );
1051 HeapFree( GetProcessHeap(), 0, fiber
);
1055 /***********************************************************************
1056 * IsThreadAFiber (kernelbase.@)
1058 BOOL WINAPI DECLSPEC_HOTPATCH
IsThreadAFiber(void)
1060 return NtCurrentTeb()->Tib
.u
.FiberData
!= NULL
;
1064 /***********************************************************************
1065 * SwitchToFiber (kernelbase.@)
1067 void WINAPI DECLSPEC_HOTPATCH
SwitchToFiber( LPVOID fiber
)
1069 struct fiber_data
*new_fiber
= fiber
;
1070 struct fiber_data
*current_fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
1072 current_fiber
->except
= NtCurrentTeb()->Tib
.ExceptionList
;
1073 current_fiber
->stack_limit
= NtCurrentTeb()->Tib
.StackLimit
;
1074 current_fiber
->fls_slots
= NtCurrentTeb()->FlsSlots
;
1075 /* stack_allocation and stack_base never change */
1077 /* FIXME: should save floating point context if requested in fiber->flags */
1078 NtCurrentTeb()->Tib
.u
.FiberData
= new_fiber
;
1079 NtCurrentTeb()->Tib
.ExceptionList
= new_fiber
->except
;
1080 NtCurrentTeb()->Tib
.StackBase
= new_fiber
->stack_base
;
1081 NtCurrentTeb()->Tib
.StackLimit
= new_fiber
->stack_limit
;
1082 NtCurrentTeb()->DeallocationStack
= new_fiber
->stack_allocation
;
1083 NtCurrentTeb()->FlsSlots
= new_fiber
->fls_slots
;
1084 switch_fiber( ¤t_fiber
->context
, &new_fiber
->context
);
1088 /***********************************************************************
1089 * FlsAlloc (kernelbase.@)
1091 DWORD WINAPI DECLSPEC_HOTPATCH
FlsAlloc( PFLS_CALLBACK_FUNCTION callback
)
1095 if (!set_ntstatus( RtlFlsAlloc( callback
, &index
))) return FLS_OUT_OF_INDEXES
;
1100 /***********************************************************************
1101 * FlsFree (kernelbase.@)
1103 BOOL WINAPI DECLSPEC_HOTPATCH
FlsFree( DWORD index
)
1105 return set_ntstatus( RtlFlsFree( index
));
1109 /***********************************************************************
1110 * FlsGetValue (kernelbase.@)
1112 PVOID WINAPI DECLSPEC_HOTPATCH
FlsGetValue( DWORD index
)
1116 if (!set_ntstatus( RtlFlsGetValue( index
, &data
))) return NULL
;
1117 SetLastError( ERROR_SUCCESS
);
1122 /***********************************************************************
1123 * FlsSetValue (kernelbase.@)
1125 BOOL WINAPI DECLSPEC_HOTPATCH
FlsSetValue( DWORD index
, PVOID data
)
1127 return set_ntstatus( RtlFlsSetValue( index
, data
));
1131 /***********************************************************************
1133 ***********************************************************************/
1136 /***********************************************************************
1137 * CallbackMayRunLong (kernelbase.@)
1139 BOOL WINAPI DECLSPEC_HOTPATCH
CallbackMayRunLong( TP_CALLBACK_INSTANCE
*instance
)
1141 return set_ntstatus( TpCallbackMayRunLong( instance
));
1145 /***********************************************************************
1146 * CreateThreadpool (kernelbase.@)
1148 PTP_POOL WINAPI DECLSPEC_HOTPATCH
CreateThreadpool( void *reserved
)
1152 if (!set_ntstatus( TpAllocPool( &pool
, reserved
))) pool
= NULL
;
1157 /***********************************************************************
1158 * CreateThreadpoolCleanupGroup (kernelbase.@)
1160 PTP_CLEANUP_GROUP WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolCleanupGroup(void)
1162 TP_CLEANUP_GROUP
*group
;
1164 if (!set_ntstatus( TpAllocCleanupGroup( &group
))) return NULL
;
1169 static void WINAPI
tp_io_callback( TP_CALLBACK_INSTANCE
*instance
, void *userdata
, void *cvalue
, IO_STATUS_BLOCK
*iosb
, TP_IO
*io
)
1171 PTP_WIN32_IO_CALLBACK callback
= *(void **)io
;
1172 callback( instance
, userdata
, cvalue
, RtlNtStatusToDosError( iosb
->u
.Status
), iosb
->Information
, io
);
1176 /***********************************************************************
1177 * CreateThreadpoolIo (kernelbase.@)
1179 PTP_IO WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolIo( HANDLE handle
, PTP_WIN32_IO_CALLBACK callback
,
1180 PVOID userdata
, TP_CALLBACK_ENVIRON
*environment
)
1183 if (!set_ntstatus( TpAllocIoCompletion( &io
, handle
, tp_io_callback
, userdata
, environment
))) return NULL
;
1184 *(void **)io
= callback
; /* ntdll leaves us space to store our callback at the beginning of TP_IO struct */
1189 /***********************************************************************
1190 * CreateThreadpoolTimer (kernelbase.@)
1192 PTP_TIMER WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback
, PVOID userdata
,
1193 TP_CALLBACK_ENVIRON
*environment
)
1197 if (!set_ntstatus( TpAllocTimer( &timer
, callback
, userdata
, environment
))) return NULL
;
1202 /***********************************************************************
1203 * CreateThreadpoolWait (kernelbase.@)
1205 PTP_WAIT WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolWait( PTP_WAIT_CALLBACK callback
, PVOID userdata
,
1206 TP_CALLBACK_ENVIRON
*environment
)
1210 if (!set_ntstatus( TpAllocWait( &wait
, callback
, userdata
, environment
))) return NULL
;
1215 /***********************************************************************
1216 * CreateThreadpoolWork (kernelbase.@)
1218 PTP_WORK WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolWork( PTP_WORK_CALLBACK callback
, PVOID userdata
,
1219 TP_CALLBACK_ENVIRON
*environment
)
1223 if (!set_ntstatus( TpAllocWork( &work
, callback
, userdata
, environment
))) return NULL
;
1228 /***********************************************************************
1229 * TrySubmitThreadpoolCallback (kernelbase.@)
1231 BOOL WINAPI DECLSPEC_HOTPATCH
TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback
, PVOID userdata
,
1232 TP_CALLBACK_ENVIRON
*environment
)
1234 return set_ntstatus( TpSimpleTryPost( callback
, userdata
, environment
));
1238 /***********************************************************************
1239 * QueueUserWorkItem (kernelbase.@)
1241 BOOL WINAPI DECLSPEC_HOTPATCH
QueueUserWorkItem( LPTHREAD_START_ROUTINE func
, PVOID context
, ULONG flags
)
1243 return set_ntstatus( RtlQueueWorkItem( func
, context
, flags
));
1246 /***********************************************************************
1247 * SetThreadpoolStackInformation (kernelbase.@)
1249 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadpoolStackInformation( PTP_POOL pool
, PTP_POOL_STACK_INFORMATION stack_info
)
1251 return set_ntstatus( TpSetPoolStackInformation( pool
, stack_info
));
1254 /***********************************************************************
1255 * QueryThreadpoolStackInformation (kernelbase.@)
1257 BOOL WINAPI DECLSPEC_HOTPATCH
QueryThreadpoolStackInformation( PTP_POOL pool
, PTP_POOL_STACK_INFORMATION stack_info
)
1259 return set_ntstatus( TpQueryPoolStackInformation( pool
, stack_info
));