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_DESCRIPTION_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
.Description
.Length
= info
.Description
.MaximumLength
= length
;
431 info
.Description
.Buffer
= (WCHAR
*)description
;
433 return HRESULT_FROM_NT(NtSetInformationThread( thread
, ThreadDescription
, &info
, sizeof(info
) ));
436 /***********************************************************************
437 * GetThreadDescription (kernelbase.@)
439 HRESULT WINAPI DECLSPEC_HOTPATCH
GetThreadDescription( HANDLE thread
, WCHAR
**description
)
441 THREAD_DESCRIPTION_INFORMATION
*info
;
445 TRACE( "(%p, %p)\n", thread
, description
);
450 status
= NtQueryInformationThread( thread
, ThreadDescription
, 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
, ThreadDescription
, info
, length
, &length
);
460 if (!(*description
= LocalAlloc( 0, info
->Description
.Length
+ sizeof(WCHAR
))))
461 status
= STATUS_NO_MEMORY
;
464 if (info
->Description
.Length
)
465 memcpy(*description
, info
->Description
.Buffer
, info
->Description
.Length
);
466 (*description
)[info
->Description
.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 %u): 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 * SuspendThread (kernelbase.@)
612 DWORD WINAPI DECLSPEC_HOTPATCH
SuspendThread( HANDLE thread
)
616 if (!set_ntstatus( NtSuspendThread( thread
, &ret
))) ret
= ~0U;
621 /***********************************************************************
622 * SwitchToThread (kernelbase.@)
624 BOOL WINAPI DECLSPEC_HOTPATCH
SwitchToThread(void)
626 return (NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
);
630 /**********************************************************************
631 * TerminateThread (kernelbase.@)
633 BOOL WINAPI DECLSPEC_HOTPATCH
TerminateThread( HANDLE handle
, DWORD exit_code
)
635 return set_ntstatus( NtTerminateThread( handle
, exit_code
));
639 /**********************************************************************
640 * TlsAlloc (kernelbase.@)
642 DWORD WINAPI DECLSPEC_HOTPATCH
TlsAlloc(void)
645 PEB
* const peb
= NtCurrentTeb()->Peb
;
648 index
= RtlFindClearBitsAndSet( peb
->TlsBitmap
, 1, 1 );
649 if (index
!= ~0U) NtCurrentTeb()->TlsSlots
[index
] = 0; /* clear the value */
652 index
= RtlFindClearBitsAndSet( peb
->TlsExpansionBitmap
, 1, 0 );
655 if (!NtCurrentTeb()->TlsExpansionSlots
&&
656 !(NtCurrentTeb()->TlsExpansionSlots
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
657 8 * sizeof(peb
->TlsExpansionBitmapBits
) * sizeof(void*) )))
659 RtlClearBits( peb
->TlsExpansionBitmap
, index
, 1 );
661 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
665 NtCurrentTeb()->TlsExpansionSlots
[index
] = 0; /* clear the value */
666 index
+= TLS_MINIMUM_AVAILABLE
;
669 else SetLastError( ERROR_NO_MORE_ITEMS
);
676 /**********************************************************************
677 * TlsFree (kernelbase.@)
679 BOOL WINAPI DECLSPEC_HOTPATCH
TlsFree( DWORD index
)
684 if (index
>= TLS_MINIMUM_AVAILABLE
)
686 ret
= RtlAreBitsSet( NtCurrentTeb()->Peb
->TlsExpansionBitmap
, index
- TLS_MINIMUM_AVAILABLE
, 1 );
687 if (ret
) RtlClearBits( NtCurrentTeb()->Peb
->TlsExpansionBitmap
, index
- TLS_MINIMUM_AVAILABLE
, 1 );
691 ret
= RtlAreBitsSet( NtCurrentTeb()->Peb
->TlsBitmap
, index
, 1 );
692 if (ret
) RtlClearBits( NtCurrentTeb()->Peb
->TlsBitmap
, index
, 1 );
694 if (ret
) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell
, &index
, sizeof(index
) );
695 else SetLastError( ERROR_INVALID_PARAMETER
);
701 /**********************************************************************
702 * TlsGetValue (kernelbase.@)
704 LPVOID WINAPI DECLSPEC_HOTPATCH
TlsGetValue( DWORD index
)
706 SetLastError( ERROR_SUCCESS
);
707 if (index
< TLS_MINIMUM_AVAILABLE
) return NtCurrentTeb()->TlsSlots
[index
];
709 index
-= TLS_MINIMUM_AVAILABLE
;
710 if (index
>= 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
))
712 SetLastError( ERROR_INVALID_PARAMETER
);
715 if (!NtCurrentTeb()->TlsExpansionSlots
) return NULL
;
716 return NtCurrentTeb()->TlsExpansionSlots
[index
];
720 /**********************************************************************
721 * TlsSetValue (kernelbase.@)
723 BOOL WINAPI DECLSPEC_HOTPATCH
TlsSetValue( DWORD index
, LPVOID value
)
725 if (index
< TLS_MINIMUM_AVAILABLE
)
727 NtCurrentTeb()->TlsSlots
[index
] = value
;
731 index
-= TLS_MINIMUM_AVAILABLE
;
732 if (index
>= 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
))
734 SetLastError( ERROR_INVALID_PARAMETER
);
737 if (!NtCurrentTeb()->TlsExpansionSlots
&&
738 !(NtCurrentTeb()->TlsExpansionSlots
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
739 8 * sizeof(NtCurrentTeb()->Peb
->TlsExpansionBitmapBits
) * sizeof(void*) )))
741 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
744 NtCurrentTeb()->TlsExpansionSlots
[index
] = value
;
750 /***********************************************************************
752 ***********************************************************************/
757 LPVOID param
; /* 00/00 fiber param */
758 void *except
; /* 04/08 saved exception handlers list */
759 void *stack_base
; /* 08/10 top of fiber stack */
760 void *stack_limit
; /* 0c/18 fiber stack low-water mark */
761 void *stack_allocation
; /* 10/20 base of the fiber stack allocation */
762 CONTEXT context
; /* 14/30 fiber context */
763 DWORD flags
; /* fiber flags */
764 LPFIBER_START_ROUTINE start
; /* start routine */
765 void *fls_slots
; /* fiber storage slots */
768 extern void WINAPI
switch_fiber( CONTEXT
*old
, CONTEXT
*new );
770 __ASM_STDCALL_FUNC( switch_fiber
, 8,
771 "movl 4(%esp),%ecx\n\t" /* old */
772 "movl %edi,0x9c(%ecx)\n\t" /* old->Edi */
773 "movl %esi,0xa0(%ecx)\n\t" /* old->Esi */
774 "movl %ebx,0xa4(%ecx)\n\t" /* old->Ebx */
775 "movl %ebp,0xb4(%ecx)\n\t" /* old->Ebp */
776 "movl 0(%esp),%eax\n\t"
777 "movl %eax,0xb8(%ecx)\n\t" /* old->Eip */
778 "leal 12(%esp),%eax\n\t"
779 "movl %eax,0xc4(%ecx)\n\t" /* old->Esp */
780 "movl 8(%esp),%ecx\n\t" /* new */
781 "movl 0x9c(%ecx),%edi\n\t" /* new->Edi */
782 "movl 0xa0(%ecx),%esi\n\t" /* new->Esi */
783 "movl 0xa4(%ecx),%ebx\n\t" /* new->Ebx */
784 "movl 0xb4(%ecx),%ebp\n\t" /* new->Ebp */
785 "movl 0xc4(%ecx),%esp\n\t" /* new->Esp */
786 "jmp *0xb8(%ecx)" ) /* new->Eip */
787 #elif defined(__x86_64__)
788 __ASM_STDCALL_FUNC( switch_fiber
, 8,
789 "movq %rbx,0x90(%rcx)\n\t" /* old->Rbx */
790 "leaq 0x8(%rsp),%rax\n\t"
791 "movq %rax,0x98(%rcx)\n\t" /* old->Rsp */
792 "movq %rbp,0xa0(%rcx)\n\t" /* old->Rbp */
793 "movq %rsi,0xa8(%rcx)\n\t" /* old->Rsi */
794 "movq %rdi,0xb0(%rcx)\n\t" /* old->Rdi */
795 "movq %r12,0xd8(%rcx)\n\t" /* old->R12 */
796 "movq %r13,0xe0(%rcx)\n\t" /* old->R13 */
797 "movq %r14,0xe8(%rcx)\n\t" /* old->R14 */
798 "movq %r15,0xf0(%rcx)\n\t" /* old->R15 */
799 "movq (%rsp),%rax\n\t"
800 "movq %rax,0xf8(%rcx)\n\t" /* old->Rip */
801 "movdqa %xmm6,0x200(%rcx)\n\t" /* old->Xmm6 */
802 "movdqa %xmm7,0x210(%rcx)\n\t" /* old->Xmm7 */
803 "movdqa %xmm8,0x220(%rcx)\n\t" /* old->Xmm8 */
804 "movdqa %xmm9,0x230(%rcx)\n\t" /* old->Xmm9 */
805 "movdqa %xmm10,0x240(%rcx)\n\t" /* old->Xmm10 */
806 "movdqa %xmm11,0x250(%rcx)\n\t" /* old->Xmm11 */
807 "movdqa %xmm12,0x260(%rcx)\n\t" /* old->Xmm12 */
808 "movdqa %xmm13,0x270(%rcx)\n\t" /* old->Xmm13 */
809 "movdqa %xmm14,0x280(%rcx)\n\t" /* old->Xmm14 */
810 "movdqa %xmm15,0x290(%rcx)\n\t" /* old->Xmm15 */
811 "movq 0x90(%rdx),%rbx\n\t" /* new->Rbx */
812 "movq 0xa0(%rdx),%rbp\n\t" /* new->Rbp */
813 "movq 0xa8(%rdx),%rsi\n\t" /* new->Rsi */
814 "movq 0xb0(%rdx),%rdi\n\t" /* new->Rdi */
815 "movq 0xd8(%rdx),%r12\n\t" /* new->R12 */
816 "movq 0xe0(%rdx),%r13\n\t" /* new->R13 */
817 "movq 0xe8(%rdx),%r14\n\t" /* new->R14 */
818 "movq 0xf0(%rdx),%r15\n\t" /* new->R15 */
819 "movdqa 0x200(%rdx),%xmm6\n\t" /* new->Xmm6 */
820 "movdqa 0x210(%rdx),%xmm7\n\t" /* new->Xmm7 */
821 "movdqa 0x220(%rdx),%xmm8\n\t" /* new->Xmm8 */
822 "movdqa 0x230(%rdx),%xmm9\n\t" /* new->Xmm9 */
823 "movdqa 0x240(%rdx),%xmm10\n\t" /* new->Xmm10 */
824 "movdqa 0x250(%rdx),%xmm11\n\t" /* new->Xmm11 */
825 "movdqa 0x260(%rdx),%xmm12\n\t" /* new->Xmm12 */
826 "movdqa 0x270(%rdx),%xmm13\n\t" /* new->Xmm13 */
827 "movdqa 0x280(%rdx),%xmm14\n\t" /* new->Xmm14 */
828 "movdqa 0x290(%rdx),%xmm15\n\t" /* new->Xmm15 */
829 "movq 0x98(%rdx),%rsp\n\t" /* new->Rsp */
830 "jmp *0xf8(%rdx)" ) /* new->Rip */
831 #elif defined(__arm__)
832 __ASM_STDCALL_FUNC( switch_fiber
, 8,
833 "str r4, [r0, #0x14]\n\t" /* old->R4 */
834 "str r5, [r0, #0x18]\n\t" /* old->R5 */
835 "str r6, [r0, #0x1c]\n\t" /* old->R6 */
836 "str r7, [r0, #0x20]\n\t" /* old->R7 */
837 "str r8, [r0, #0x24]\n\t" /* old->R8 */
838 "str r9, [r0, #0x28]\n\t" /* old->R9 */
839 "str r10, [r0, #0x2c]\n\t" /* old->R10 */
840 "str r11, [r0, #0x30]\n\t" /* old->R11 */
841 "str sp, [r0, #0x38]\n\t" /* old->Sp */
842 "str lr, [r0, #0x40]\n\t" /* old->Pc */
843 "ldr r4, [r1, #0x14]\n\t" /* new->R4 */
844 "ldr r5, [r1, #0x18]\n\t" /* new->R5 */
845 "ldr r6, [r1, #0x1c]\n\t" /* new->R6 */
846 "ldr r7, [r1, #0x20]\n\t" /* new->R7 */
847 "ldr r8, [r1, #0x24]\n\t" /* new->R8 */
848 "ldr r9, [r1, #0x28]\n\t" /* new->R9 */
849 "ldr r10, [r1, #0x2c]\n\t" /* new->R10 */
850 "ldr r11, [r1, #0x30]\n\t" /* new->R11 */
851 "ldr sp, [r1, #0x38]\n\t" /* new->Sp */
852 "ldr r2, [r1, #0x40]\n\t" /* new->Pc */
854 #elif defined(__aarch64__)
855 __ASM_STDCALL_FUNC( switch_fiber
, 8,
856 "stp x19, x20, [x0, #0xa0]\n\t" /* old->X19,X20 */
857 "stp x21, x22, [x0, #0xb0]\n\t" /* old->X21,X22 */
858 "stp x23, x24, [x0, #0xc0]\n\t" /* old->X23,X24 */
859 "stp x25, x26, [x0, #0xd0]\n\t" /* old->X25,X26 */
860 "stp x27, x28, [x0, #0xe0]\n\t" /* old->X27,X28 */
861 "str x29, [x0, #0xf0]\n\t" /* old->Fp */
863 "str x2, [x0, #0x100]\n\t" /* old->Sp */
864 "str x30, [x0, #0x108]\n\t" /* old->Pc */
865 "ldp x19, x20, [x1, #0xa0]\n\t" /* new->X19,X20 */
866 "ldp x21, x22, [x1, #0xb0]\n\t" /* new->X21,X22 */
867 "ldp x23, x24, [x1, #0xc0]\n\t" /* new->X23,X24 */
868 "ldp x25, x26, [x1, #0xd0]\n\t" /* new->X25,X26 */
869 "ldp x27, x28, [x1, #0xe0]\n\t" /* new->X27,X28 */
870 "ldr x29, [x1, #0xf0]\n\t" /* new->Fp */
871 "ldr x2, [x1, #0x100]\n\t" /* new->Sp */
872 "ldr x30, [x1, #0x108]\n\t" /* new->Pc */
876 void WINAPI
switch_fiber( CONTEXT
*old
, CONTEXT
*new )
878 FIXME( "not implemented\n" );
883 /* call the fiber initial function once we have switched stack */
884 static void CDECL
start_fiber(void)
886 struct fiber_data
*fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
887 LPFIBER_START_ROUTINE start
= fiber
->start
;
891 start( fiber
->param
);
892 RtlExitUserThread( 1 );
894 __EXCEPT(UnhandledExceptionFilter
)
896 TerminateThread( GetCurrentThread(), GetExceptionCode() );
901 static void init_fiber_context( struct fiber_data
*fiber
)
904 fiber
->context
.Esp
= (ULONG_PTR
)fiber
->stack_base
- 4;
905 fiber
->context
.Eip
= (ULONG_PTR
)start_fiber
;
906 #elif defined(__x86_64__)
907 fiber
->context
.Rsp
= (ULONG_PTR
)fiber
->stack_base
- 0x28;
908 fiber
->context
.Rip
= (ULONG_PTR
)start_fiber
;
909 #elif defined(__arm__)
910 fiber
->context
.Sp
= (ULONG_PTR
)fiber
->stack_base
;
911 fiber
->context
.Pc
= (ULONG_PTR
)start_fiber
;
912 #elif defined(__aarch64__)
913 fiber
->context
.Sp
= (ULONG_PTR
)fiber
->stack_base
;
914 fiber
->context
.Pc
= (ULONG_PTR
)start_fiber
;
919 /***********************************************************************
920 * CreateFiber (kernelbase.@)
922 LPVOID WINAPI DECLSPEC_HOTPATCH
CreateFiber( SIZE_T stack
, LPFIBER_START_ROUTINE start
, LPVOID param
)
924 return CreateFiberEx( stack
, 0, 0, start
, param
);
928 /***********************************************************************
929 * CreateFiberEx (kernelbase.@)
931 LPVOID WINAPI DECLSPEC_HOTPATCH
CreateFiberEx( SIZE_T stack_commit
, SIZE_T stack_reserve
, DWORD flags
,
932 LPFIBER_START_ROUTINE start
, LPVOID param
)
934 struct fiber_data
*fiber
;
937 if (!(fiber
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*fiber
) )))
939 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
943 if (!set_ntstatus( RtlCreateUserStack( stack_commit
, stack_reserve
, 0, 1, 1, &stack
)))
945 HeapFree( GetProcessHeap(), 0, fiber
);
949 fiber
->stack_allocation
= stack
.DeallocationStack
;
950 fiber
->stack_base
= stack
.StackBase
;
951 fiber
->stack_limit
= stack
.StackLimit
;
952 fiber
->param
= param
;
953 fiber
->except
= (void *)-1;
954 fiber
->start
= start
;
955 fiber
->flags
= flags
;
956 init_fiber_context( fiber
);
961 /***********************************************************************
962 * ConvertFiberToThread (kernelbase.@)
964 BOOL WINAPI DECLSPEC_HOTPATCH
ConvertFiberToThread(void)
966 struct fiber_data
*fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
970 NtCurrentTeb()->Tib
.u
.FiberData
= NULL
;
971 HeapFree( GetProcessHeap(), 0, fiber
);
977 /***********************************************************************
978 * ConvertThreadToFiber (kernelbase.@)
980 LPVOID WINAPI DECLSPEC_HOTPATCH
ConvertThreadToFiber( LPVOID param
)
982 return ConvertThreadToFiberEx( param
, 0 );
986 /***********************************************************************
987 * ConvertThreadToFiberEx (kernelbase.@)
989 LPVOID WINAPI DECLSPEC_HOTPATCH
ConvertThreadToFiberEx( LPVOID param
, DWORD flags
)
991 struct fiber_data
*fiber
;
993 if (NtCurrentTeb()->Tib
.u
.FiberData
)
995 SetLastError( ERROR_ALREADY_FIBER
);
999 if (!(fiber
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber
) )))
1001 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1004 fiber
->param
= param
;
1005 fiber
->except
= NtCurrentTeb()->Tib
.ExceptionList
;
1006 fiber
->stack_base
= NtCurrentTeb()->Tib
.StackBase
;
1007 fiber
->stack_limit
= NtCurrentTeb()->Tib
.StackLimit
;
1008 fiber
->stack_allocation
= NtCurrentTeb()->DeallocationStack
;
1009 fiber
->start
= NULL
;
1010 fiber
->flags
= flags
;
1011 fiber
->fls_slots
= NtCurrentTeb()->FlsSlots
;
1012 NtCurrentTeb()->Tib
.u
.FiberData
= fiber
;
1017 /***********************************************************************
1018 * DeleteFiber (kernelbase.@)
1020 void WINAPI DECLSPEC_HOTPATCH
DeleteFiber( LPVOID fiber_ptr
)
1022 struct fiber_data
*fiber
= fiber_ptr
;
1025 if (fiber
== NtCurrentTeb()->Tib
.u
.FiberData
)
1027 HeapFree( GetProcessHeap(), 0, fiber
);
1028 RtlExitUserThread( 1 );
1030 RtlFreeUserStack( fiber
->stack_allocation
);
1031 RtlProcessFlsData( fiber
->fls_slots
, 3 );
1032 HeapFree( GetProcessHeap(), 0, fiber
);
1036 /***********************************************************************
1037 * IsThreadAFiber (kernelbase.@)
1039 BOOL WINAPI DECLSPEC_HOTPATCH
IsThreadAFiber(void)
1041 return NtCurrentTeb()->Tib
.u
.FiberData
!= NULL
;
1045 /***********************************************************************
1046 * SwitchToFiber (kernelbase.@)
1048 void WINAPI DECLSPEC_HOTPATCH
SwitchToFiber( LPVOID fiber
)
1050 struct fiber_data
*new_fiber
= fiber
;
1051 struct fiber_data
*current_fiber
= NtCurrentTeb()->Tib
.u
.FiberData
;
1053 current_fiber
->except
= NtCurrentTeb()->Tib
.ExceptionList
;
1054 current_fiber
->stack_limit
= NtCurrentTeb()->Tib
.StackLimit
;
1055 current_fiber
->fls_slots
= NtCurrentTeb()->FlsSlots
;
1056 /* stack_allocation and stack_base never change */
1058 /* FIXME: should save floating point context if requested in fiber->flags */
1059 NtCurrentTeb()->Tib
.u
.FiberData
= new_fiber
;
1060 NtCurrentTeb()->Tib
.ExceptionList
= new_fiber
->except
;
1061 NtCurrentTeb()->Tib
.StackBase
= new_fiber
->stack_base
;
1062 NtCurrentTeb()->Tib
.StackLimit
= new_fiber
->stack_limit
;
1063 NtCurrentTeb()->DeallocationStack
= new_fiber
->stack_allocation
;
1064 NtCurrentTeb()->FlsSlots
= new_fiber
->fls_slots
;
1065 switch_fiber( ¤t_fiber
->context
, &new_fiber
->context
);
1069 /***********************************************************************
1070 * FlsAlloc (kernelbase.@)
1072 DWORD WINAPI DECLSPEC_HOTPATCH
FlsAlloc( PFLS_CALLBACK_FUNCTION callback
)
1076 if (!set_ntstatus( RtlFlsAlloc( callback
, &index
))) return FLS_OUT_OF_INDEXES
;
1081 /***********************************************************************
1082 * FlsFree (kernelbase.@)
1084 BOOL WINAPI DECLSPEC_HOTPATCH
FlsFree( DWORD index
)
1086 return set_ntstatus( RtlFlsFree( index
));
1090 /***********************************************************************
1091 * FlsGetValue (kernelbase.@)
1093 PVOID WINAPI DECLSPEC_HOTPATCH
FlsGetValue( DWORD index
)
1097 if (!set_ntstatus( RtlFlsGetValue( index
, &data
))) return NULL
;
1098 SetLastError( ERROR_SUCCESS
);
1103 /***********************************************************************
1104 * FlsSetValue (kernelbase.@)
1106 BOOL WINAPI DECLSPEC_HOTPATCH
FlsSetValue( DWORD index
, PVOID data
)
1108 return set_ntstatus( RtlFlsSetValue( index
, data
));
1112 /***********************************************************************
1114 ***********************************************************************/
1117 /***********************************************************************
1118 * CallbackMayRunLong (kernelbase.@)
1120 BOOL WINAPI DECLSPEC_HOTPATCH
CallbackMayRunLong( TP_CALLBACK_INSTANCE
*instance
)
1122 return set_ntstatus( TpCallbackMayRunLong( instance
));
1126 /***********************************************************************
1127 * CreateThreadpool (kernelbase.@)
1129 PTP_POOL WINAPI DECLSPEC_HOTPATCH
CreateThreadpool( void *reserved
)
1133 if (!set_ntstatus( TpAllocPool( &pool
, reserved
))) pool
= NULL
;
1138 /***********************************************************************
1139 * CreateThreadpoolCleanupGroup (kernelbase.@)
1141 PTP_CLEANUP_GROUP WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolCleanupGroup(void)
1143 TP_CLEANUP_GROUP
*group
;
1145 if (!set_ntstatus( TpAllocCleanupGroup( &group
))) return NULL
;
1150 static void WINAPI
tp_io_callback( TP_CALLBACK_INSTANCE
*instance
, void *userdata
, void *cvalue
, IO_STATUS_BLOCK
*iosb
, TP_IO
*io
)
1152 PTP_WIN32_IO_CALLBACK callback
= *(void **)io
;
1153 callback( instance
, userdata
, cvalue
, RtlNtStatusToDosError( iosb
->u
.Status
), iosb
->Information
, io
);
1157 /***********************************************************************
1158 * CreateThreadpoolIo (kernelbase.@)
1160 PTP_IO WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolIo( HANDLE handle
, PTP_WIN32_IO_CALLBACK callback
,
1161 PVOID userdata
, TP_CALLBACK_ENVIRON
*environment
)
1164 if (!set_ntstatus( TpAllocIoCompletion( &io
, handle
, tp_io_callback
, userdata
, environment
))) return NULL
;
1165 *(void **)io
= callback
; /* ntdll leaves us space to store our callback at the beginning of TP_IO struct */
1170 /***********************************************************************
1171 * CreateThreadpoolTimer (kernelbase.@)
1173 PTP_TIMER WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback
, PVOID userdata
,
1174 TP_CALLBACK_ENVIRON
*environment
)
1178 if (!set_ntstatus( TpAllocTimer( &timer
, callback
, userdata
, environment
))) return NULL
;
1183 /***********************************************************************
1184 * CreateThreadpoolWait (kernelbase.@)
1186 PTP_WAIT WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolWait( PTP_WAIT_CALLBACK callback
, PVOID userdata
,
1187 TP_CALLBACK_ENVIRON
*environment
)
1191 if (!set_ntstatus( TpAllocWait( &wait
, callback
, userdata
, environment
))) return NULL
;
1196 /***********************************************************************
1197 * CreateThreadpoolWork (kernelbase.@)
1199 PTP_WORK WINAPI DECLSPEC_HOTPATCH
CreateThreadpoolWork( PTP_WORK_CALLBACK callback
, PVOID userdata
,
1200 TP_CALLBACK_ENVIRON
*environment
)
1204 if (!set_ntstatus( TpAllocWork( &work
, callback
, userdata
, environment
))) return NULL
;
1209 /***********************************************************************
1210 * TrySubmitThreadpoolCallback (kernelbase.@)
1212 BOOL WINAPI DECLSPEC_HOTPATCH
TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback
, PVOID userdata
,
1213 TP_CALLBACK_ENVIRON
*environment
)
1215 return set_ntstatus( TpSimpleTryPost( callback
, userdata
, environment
));
1219 /***********************************************************************
1220 * QueueUserWorkItem (kernelbase.@)
1222 BOOL WINAPI DECLSPEC_HOTPATCH
QueueUserWorkItem( LPTHREAD_START_ROUTINE func
, PVOID context
, ULONG flags
)
1224 return set_ntstatus( RtlQueueWorkItem( func
, context
, flags
));
1227 /***********************************************************************
1228 * SetThreadpoolStackInformation (kernelbase.@)
1230 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadpoolStackInformation( PTP_POOL pool
, PTP_POOL_STACK_INFORMATION stack_info
)
1232 return set_ntstatus( TpSetPoolStackInformation( pool
, stack_info
));
1235 /***********************************************************************
1236 * QueryThreadpoolStackInformation (kernelbase.@)
1238 BOOL WINAPI DECLSPEC_HOTPATCH
QueryThreadpoolStackInformation( PTP_POOL pool
, PTP_POOL_STACK_INFORMATION stack_info
)
1240 return set_ntstatus( TpQueryPoolStackInformation( pool
, stack_info
));