Reactos
1/*
2 * Win32 threads
3 *
4 * Copyright 1996, 2002, 2019 Alexandre Julliard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <stdarg.h>
22#include <string.h>
23#include <limits.h>
24
25#include "ntstatus.h"
26#define WIN32_NO_STATUS
27#include "windef.h"
28#include "winbase.h"
29#include "winnls.h"
30#include "winternl.h"
31
32#include "kernelbase.h"
33#include "wine/exception.h"
34#include "wine/asm.h"
35#include "wine/debug.h"
36#include "wine/heap.h"
37
38WINE_DEFAULT_DEBUG_CHANNEL(thread);
39
40
41/***********************************************************************
42 * Threads
43 ***********************************************************************/
44
45
46static DWORD rtlmode_to_win32mode( DWORD rtlmode )
47{
48 DWORD win32mode = 0;
49
50 if (rtlmode & 0x10) win32mode |= SEM_FAILCRITICALERRORS;
51 if (rtlmode & 0x20) win32mode |= SEM_NOGPFAULTERRORBOX;
52 if (rtlmode & 0x40) win32mode |= SEM_NOOPENFILEERRORBOX;
53 return win32mode;
54}
55
56
57/***************************************************************************
58 * CreateRemoteThread (kernelbase.@)
59 */
60HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThread( HANDLE process, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
61 LPTHREAD_START_ROUTINE start, LPVOID param,
62 DWORD flags, DWORD *id )
63{
64 return CreateRemoteThreadEx( process, sa, stack, start, param, flags, NULL, id );
65}
66
67
68/***************************************************************************
69 * CreateRemoteThreadEx (kernelbase.@)
70 */
71HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThreadEx( HANDLE process, SECURITY_ATTRIBUTES *sa,
72 SIZE_T stack, LPTHREAD_START_ROUTINE start,
73 LPVOID param, DWORD flags,
74 LPPROC_THREAD_ATTRIBUTE_LIST attributes, DWORD *id )
75{
76 HANDLE handle;
77 CLIENT_ID client_id;
78 SIZE_T stack_reserve = 0, stack_commit = 0;
79
80 if (attributes) FIXME("thread attributes ignored\n");
81
82 if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
83 else stack_commit = stack;
84
85 if (!set_ntstatus( RtlCreateUserThread( process, sa ? sa->lpSecurityDescriptor : NULL, TRUE,
86 0, stack_reserve, stack_commit,
87 (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id )))
88 return 0;
89
90 if (id) *id = HandleToULong( client_id.UniqueThread );
91 if (sa && sa->nLength >= sizeof(*sa) && sa->bInheritHandle)
92 SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
93 if (!(flags & CREATE_SUSPENDED))
94 {
95 ULONG ret;
96 if (NtResumeThread( handle, &ret ))
97 {
98 NtClose( handle );
99 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
100 handle = 0;
101 }
102 }
103 return handle;
104}
105
106
107/***********************************************************************
108 * CreateThread (kernelbase.@)
109 */
110HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
111 LPTHREAD_START_ROUTINE start, LPVOID param,
112 DWORD flags, LPDWORD id )
113{
114 return CreateRemoteThread( GetCurrentProcess(), sa, stack, start, param, flags, id );
115}
116
117
118/***********************************************************************
119 * FreeLibraryAndExitThread (kernelbase.@)
120 */
121void WINAPI DECLSPEC_HOTPATCH FreeLibraryAndExitThread( HINSTANCE module, DWORD exit_code )
122{
123 FreeLibrary( module );
124 RtlExitUserThread( exit_code );
125}
126
127
128/***********************************************************************
129 * GetCurrentThreadStackLimits (kernelbase.@)
130 */
131void WINAPI DECLSPEC_HOTPATCH GetCurrentThreadStackLimits( ULONG_PTR *low, ULONG_PTR *high )
132{
133 *low = (ULONG_PTR)NtCurrentTeb()->DeallocationStack;
134 *high = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase;
135}
136
137
138/***********************************************************************
139 * GetCurrentThread (kernelbase.@)
140 */
141HANDLE WINAPI kernelbase_GetCurrentThread(void)
142{
143 return (HANDLE)~(ULONG_PTR)1;
144}
145
146
147/***********************************************************************
148 * GetCurrentThreadId (kernelbase.@)
149 */
150DWORD WINAPI kernelbase_GetCurrentThreadId(void)
151{
152 return HandleToULong( NtCurrentTeb()->ClientId.UniqueThread );
153}
154
155
156/**********************************************************************
157 * GetExitCodeThread (kernelbase.@)
158 */
159BOOL WINAPI DECLSPEC_HOTPATCH GetExitCodeThread( HANDLE thread, LPDWORD exit_code )
160{
161 THREAD_BASIC_INFORMATION info;
162 NTSTATUS status = NtQueryInformationThread( thread, ThreadBasicInformation,
163 &info, sizeof(info), NULL );
164 if (!status && exit_code) *exit_code = info.ExitStatus;
165 return set_ntstatus( status );
166}
167
168
169/**********************************************************************
170 * GetLastError (kernelbase.@)
171 */
172DWORD WINAPI kernelbase_GetLastError(void)
173{
174 return NtCurrentTeb()->LastErrorValue;
175}
176
177
178/**********************************************************************
179 * GetProcessIdOfThread (kernelbase.@)
180 */
181DWORD WINAPI DECLSPEC_HOTPATCH GetProcessIdOfThread( HANDLE thread )
182{
183 THREAD_BASIC_INFORMATION tbi;
184
185 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL)))
186 return 0;
187 return HandleToULong( tbi.ClientId.UniqueProcess );
188}
189
190
191/***********************************************************************
192 * GetThreadContext (kernelbase.@)
193 */
194BOOL WINAPI DECLSPEC_HOTPATCH GetThreadContext( HANDLE thread, CONTEXT *context )
195{
196 return set_ntstatus( NtGetContextThread( thread, context ));
197}
198
199
200/***********************************************************************
201 * GetThreadErrorMode (kernelbase.@)
202 */
203DWORD WINAPI DECLSPEC_HOTPATCH GetThreadErrorMode(void)
204{
205 return rtlmode_to_win32mode( RtlGetThreadErrorMode() );
206}
207
208
209/***********************************************************************
210 * GetThreadGroupAffinity (kernelbase.@)
211 */
212BOOL WINAPI DECLSPEC_HOTPATCH GetThreadGroupAffinity( HANDLE thread, GROUP_AFFINITY *affinity )
213{
214 if (!affinity)
215 {
216 SetLastError( ERROR_INVALID_PARAMETER );
217 return FALSE;
218 }
219 return set_ntstatus( NtQueryInformationThread( thread, ThreadGroupInformation,
220 affinity, sizeof(*affinity), NULL ));
221}
222
223
224/***********************************************************************
225 * GetThreadIOPendingFlag (kernelbase.@)
226 */
227BOOL WINAPI DECLSPEC_HOTPATCH GetThreadIOPendingFlag( HANDLE thread, PBOOL pending )
228{
229 return set_ntstatus( NtQueryInformationThread( thread, ThreadIsIoPending,
230 pending, sizeof(*pending), NULL ));
231}
232
233
234/**********************************************************************
235 * GetThreadId (kernelbase.@)
236 */
237DWORD WINAPI DECLSPEC_HOTPATCH GetThreadId( HANDLE thread )
238{
239 THREAD_BASIC_INFORMATION tbi;
240
241 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL)))
242 return 0;
243 return HandleToULong( tbi.ClientId.UniqueThread );
244}
245
246
247/***********************************************************************
248 * GetThreadIdealProcessorEx (kernelbase.@)
249 */
250BOOL WINAPI DECLSPEC_HOTPATCH GetThreadIdealProcessorEx( HANDLE thread, PROCESSOR_NUMBER *ideal )
251{
252 return set_ntstatus( NtQueryInformationThread( thread, ThreadIdealProcessorEx, ideal, sizeof(*ideal), NULL));
253}
254
255
256/***********************************************************************
257 * GetThreadLocale (kernelbase.@)
258 */
259LCID WINAPI /* DECLSPEC_HOTPATCH */ GetThreadLocale(void)
260{
261 LCID ret = NtCurrentTeb()->CurrentLocale;
262 if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
263 return ret;
264}
265
266
267/**********************************************************************
268 * GetThreadPriority (kernelbase.@)
269 */
270INT WINAPI DECLSPEC_HOTPATCH GetThreadPriority( HANDLE thread )
271{
272 THREAD_BASIC_INFORMATION info;
273
274 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadBasicInformation,
275 &info, sizeof(info), NULL )))
276 return THREAD_PRIORITY_ERROR_RETURN;
277 return info.Priority;
278}
279
280
281/**********************************************************************
282 * GetThreadPriorityBoost (kernelbase.@)
283 */
284BOOL WINAPI DECLSPEC_HOTPATCH GetThreadPriorityBoost( HANDLE thread, BOOL *state )
285{
286 return set_ntstatus( NtQueryInformationThread( thread, ThreadPriorityBoost, state, sizeof(*state), NULL ));
287}
288
289
290/**********************************************************************
291 * GetThreadTimes (kernelbase.@)
292 */
293BOOL WINAPI DECLSPEC_HOTPATCH GetThreadTimes( HANDLE thread, LPFILETIME creationtime, LPFILETIME exittime,
294 LPFILETIME kerneltime, LPFILETIME usertime )
295{
296 KERNEL_USER_TIMES times;
297
298 if (!set_ntstatus( NtQueryInformationThread( thread, ThreadTimes, ×, sizeof(times), NULL )))
299 return FALSE;
300
301 if (creationtime)
302 {
303 creationtime->dwLowDateTime = times.CreateTime.u.LowPart;
304 creationtime->dwHighDateTime = times.CreateTime.u.HighPart;
305 }
306 if (exittime)
307 {
308 exittime->dwLowDateTime = times.ExitTime.u.LowPart;
309 exittime->dwHighDateTime = times.ExitTime.u.HighPart;
310 }
311 if (kerneltime)
312 {
313 kerneltime->dwLowDateTime = times.KernelTime.u.LowPart;
314 kerneltime->dwHighDateTime = times.KernelTime.u.HighPart;
315 }
316 if (usertime)
317 {
318 usertime->dwLowDateTime = times.UserTime.u.LowPart;
319 usertime->dwHighDateTime = times.UserTime.u.HighPart;
320 }
321 return TRUE;
322}
323
324
325/***********************************************************************
326 * GetThreadUILanguage (kernelbase.@)
327 */
328LANGID WINAPI DECLSPEC_HOTPATCH GetThreadUILanguage(void)
329{
330 LANGID lang;
331
332 FIXME(": stub, returning default language.\n");
333 NtQueryDefaultUILanguage( &lang );
334 return lang;
335}
336
337
338/***********************************************************************
339 * OpenThread (kernelbase.@)
340 */
341HANDLE WINAPI DECLSPEC_HOTPATCH OpenThread( DWORD access, BOOL inherit, DWORD id )
342{
343 HANDLE handle;
344 OBJECT_ATTRIBUTES attr;
345 CLIENT_ID cid;
346
347 attr.Length = sizeof(attr);
348 attr.RootDirectory = 0;
349 attr.Attributes = inherit ? OBJ_INHERIT : 0;
350 attr.ObjectName = NULL;
351 attr.SecurityDescriptor = NULL;
352 attr.SecurityQualityOfService = NULL;
353
354 cid.UniqueProcess = 0;
355 cid.UniqueThread = ULongToHandle( id );
356
357 if (!set_ntstatus( NtOpenThread( &handle, access, &attr, &cid ))) handle = 0;
358 return handle;
359}
360
361
362/* callback for QueueUserAPC */
363static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
364{
365 PAPCFUNC func = (PAPCFUNC)arg1;
366 func( arg2 );
367}
368
369/***********************************************************************
370 * QueueUserAPC (kernelbase.@)
371 */
372DWORD WINAPI DECLSPEC_HOTPATCH QueueUserAPC( PAPCFUNC func, HANDLE thread, ULONG_PTR data )
373{
374 return set_ntstatus( NtQueueApcThread( thread, call_user_apc, (ULONG_PTR)func, data, 0 ));
375}
376
377
378/***********************************************************************
379 * QueryThreadCycleTime (kernelbase.@)
380 */
381BOOL WINAPI DECLSPEC_HOTPATCH QueryThreadCycleTime( HANDLE thread, ULONG64 *cycle )
382{
383 static int once;
384 if (!once++) FIXME( "(%p,%p): stub!\n", thread, cycle );
385 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
386 return FALSE;
387}
388
389
390/**********************************************************************
391 * ResumeThread (kernelbase.@)
392 */
393DWORD WINAPI DECLSPEC_HOTPATCH ResumeThread( HANDLE thread )
394{
395 DWORD ret;
396
397 if (!set_ntstatus( NtResumeThread( thread, &ret ))) ret = ~0U;
398 return ret;
399}
400
401
402/***********************************************************************
403 * SetThreadContext (kernelbase.@)
404 */
405BOOL WINAPI DECLSPEC_HOTPATCH SetThreadContext( HANDLE thread, const CONTEXT *context )
406{
407 return set_ntstatus( NtSetContextThread( thread, context ));
408}
409
410
411/***********************************************************************
412 * SetThreadDescription (kernelbase.@)
413 */
414HRESULT WINAPI DECLSPEC_HOTPATCH SetThreadDescription( HANDLE thread, PCWSTR description )
415{
416 THREAD_NAME_INFORMATION info;
417 int length;
418
419 TRACE( "(%p, %s)\n", thread, debugstr_w( description ));
420
421 length = description ? lstrlenW( description ) * sizeof(WCHAR) : 0;
422
423 if (length > USHRT_MAX)
424 return HRESULT_FROM_NT(STATUS_INVALID_PARAMETER);
425
426 info.ThreadName.Length = info.ThreadName.MaximumLength = length;
427 info.ThreadName.Buffer = (WCHAR *)description;
428
429 return HRESULT_FROM_NT(NtSetInformationThread( thread, ThreadNameInformation, &info, sizeof(info) ));
430}
431
432/***********************************************************************
433 * GetThreadDescription (kernelbase.@)
434 */
435HRESULT WINAPI DECLSPEC_HOTPATCH GetThreadDescription( HANDLE thread, WCHAR **description )
436{
437 THREAD_NAME_INFORMATION *info;
438 NTSTATUS status;
439 ULONG length;
440
441 TRACE( "(%p, %p)\n", thread, description );
442
443 *description = NULL;
444
445 length = 0;
446 status = NtQueryInformationThread( thread, ThreadNameInformation, NULL, 0, &length );
447 if (status != STATUS_BUFFER_TOO_SMALL)
448 return HRESULT_FROM_NT(status);
449
450 if (!(info = heap_alloc( length )))
451 return HRESULT_FROM_NT(STATUS_NO_MEMORY);
452
453 status = NtQueryInformationThread( thread, ThreadNameInformation, info, length, &length );
454 if (!status)
455 {
456 if (!(*description = LocalAlloc( 0, info->ThreadName.Length + sizeof(WCHAR))))
457 status = STATUS_NO_MEMORY;
458 else
459 {
460 if (info->ThreadName.Length)
461 memcpy(*description, info->ThreadName.Buffer, info->ThreadName.Length);
462 (*description)[info->ThreadName.Length / sizeof(WCHAR)] = 0;
463 }
464 }
465
466 heap_free(info);
467
468 return HRESULT_FROM_NT(status);
469}
470
471/***********************************************************************
472 * SetThreadErrorMode (kernelbase.@)
473 */
474BOOL WINAPI SetThreadErrorMode( DWORD mode, DWORD *old )
475{
476 NTSTATUS status;
477 DWORD new = 0;
478
479 if (mode & ~(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX))
480 {
481 SetLastError( ERROR_INVALID_PARAMETER );
482 return FALSE;
483 }
484
485 if (mode & SEM_FAILCRITICALERRORS) new |= 0x10;
486 if (mode & SEM_NOGPFAULTERRORBOX) new |= 0x20;
487 if (mode & SEM_NOOPENFILEERRORBOX) new |= 0x40;
488
489 status = RtlSetThreadErrorMode( new, old );
490 if (!status && old) *old = rtlmode_to_win32mode( *old );
491 return set_ntstatus( status );
492}
493
494
495/***********************************************************************
496 * SetThreadGroupAffinity (kernelbase.@)
497 */
498BOOL WINAPI DECLSPEC_HOTPATCH SetThreadGroupAffinity( HANDLE thread, const GROUP_AFFINITY *new,
499 GROUP_AFFINITY *old )
500{
501 if (old && !GetThreadGroupAffinity( thread, old )) return FALSE;
502 return set_ntstatus( NtSetInformationThread( thread, ThreadGroupInformation, new, sizeof(*new) ));
503}
504
505
506/**********************************************************************
507 * SetThreadIdealProcessor (kernelbase.@)
508 */
509DWORD WINAPI DECLSPEC_HOTPATCH SetThreadIdealProcessor( HANDLE thread, DWORD proc )
510{
511 NTSTATUS status;
512
513 status = NtSetInformationThread( thread, ThreadIdealProcessor, &proc, sizeof(proc) );
514 if (NT_SUCCESS(status)) return status;
515
516 SetLastError( RtlNtStatusToDosError( status ));
517 return ~0u;
518}
519
520
521/***********************************************************************
522 * SetThreadIdealProcessorEx (kernelbase.@)
523 */
524BOOL WINAPI DECLSPEC_HOTPATCH SetThreadIdealProcessorEx( HANDLE thread, PROCESSOR_NUMBER *ideal,
525 PROCESSOR_NUMBER *previous )
526{
527 FIXME( "(%p %p %p): stub\n", thread, ideal, previous );
528 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
529 return FALSE;
530}
531
532
533/**********************************************************************
534 * SetThreadLocale (kernelbase.@)
535 */
536BOOL WINAPI DECLSPEC_HOTPATCH SetThreadLocale( LCID lcid )
537{
538 lcid = ConvertDefaultLocale( lcid );
539 if (lcid != GetThreadLocale())
540 {
541 if (!IsValidLocale( lcid, LCID_SUPPORTED ))
542 {
543 SetLastError( ERROR_INVALID_PARAMETER );
544 return FALSE;
545 }
546 NtCurrentTeb()->CurrentLocale = lcid;
547 }
548 return TRUE;
549}
550
551
552/**********************************************************************
553 * SetThreadPriority (kernelbase.@)
554 */
555BOOL WINAPI DECLSPEC_HOTPATCH SetThreadPriority( HANDLE thread, INT priority )
556{
557 DWORD prio = priority;
558 return set_ntstatus( NtSetInformationThread( thread, ThreadBasePriority, &prio, sizeof(prio) ));
559}
560
561
562/**********************************************************************
563 * SetThreadPriorityBoost (kernelbase.@)
564 */
565BOOL WINAPI DECLSPEC_HOTPATCH SetThreadPriorityBoost( HANDLE thread, BOOL disable )
566{
567 return set_ntstatus( NtSetInformationThread( thread, ThreadPriorityBoost, &disable, sizeof(disable) ));
568}
569
570
571/**********************************************************************
572 * SetThreadStackGuarantee (kernelbase.@)
573 */
574BOOL WINAPI DECLSPEC_HOTPATCH SetThreadStackGuarantee( ULONG *size )
575{
576 ULONG prev_size = NtCurrentTeb()->GuaranteedStackBytes;
577 ULONG new_size = (*size + 4095) & ~4095;
578
579 /* at least 2 pages on 64-bit */
580 if (sizeof(void *) > sizeof(int) && new_size) new_size = max( new_size, 8192 );
581
582 *size = prev_size;
583 if (new_size >= (char *)NtCurrentTeb()->Tib.StackBase - (char *)NtCurrentTeb()->DeallocationStack)
584 {
585 SetLastError( ERROR_INVALID_PARAMETER );
586 return FALSE;
587 }
588 if (new_size > prev_size) NtCurrentTeb()->GuaranteedStackBytes = (new_size + 4095) & ~4095;
589 return TRUE;
590}
591
592
593/**********************************************************************
594 * SetThreadUILanguage (kernelbase.@)
595 */
596LANGID WINAPI DECLSPEC_HOTPATCH SetThreadUILanguage( LANGID langid )
597{
598 TRACE( "(0x%04x) stub - returning success\n", langid );
599
600 if (!langid) langid = GetThreadUILanguage();
601 return langid;
602}
603
604
605/**********************************************************************
606 * SetThreadInformation (kernelbase.@)
607 */
608BOOL WINAPI DECLSPEC_HOTPATCH SetThreadInformation( HANDLE thread, THREAD_INFORMATION_CLASS info_class,
609 VOID *info, DWORD size )
610{
611 switch (info_class)
612 {
613 case ThreadMemoryPriority:
614 return set_ntstatus( NtSetInformationThread( thread, ThreadPagePriority, info, size ));
615 case ThreadPowerThrottling:
616 return set_ntstatus( NtSetInformationThread( thread, ThreadPowerThrottlingState, info, size ));
617 default:
618 FIXME("Unsupported class %u.\n", info_class);
619 return FALSE;
620 }
621}
622
623
624/**********************************************************************
625 * SuspendThread (kernelbase.@)
626 */
627DWORD WINAPI DECLSPEC_HOTPATCH SuspendThread( HANDLE thread )
628{
629 DWORD ret;
630
631 if (!set_ntstatus( NtSuspendThread( thread, &ret ))) ret = ~0U;
632 return ret;
633}
634
635
636/***********************************************************************
637 * SwitchToThread (kernelbase.@)
638 */
639BOOL WINAPI DECLSPEC_HOTPATCH SwitchToThread(void)
640{
641 return (NtYieldExecution() != STATUS_NO_YIELD_PERFORMED);
642}
643
644
645/**********************************************************************
646 * TerminateThread (kernelbase.@)
647 */
648BOOL WINAPI DECLSPEC_HOTPATCH TerminateThread( HANDLE handle, DWORD exit_code )
649{
650 return set_ntstatus( NtTerminateThread( handle, exit_code ));
651}
652
653
654/**********************************************************************
655 * TlsAlloc (kernelbase.@)
656 */
657DWORD WINAPI DECLSPEC_HOTPATCH TlsAlloc(void)
658{
659 DWORD index;
660 PEB * const peb = NtCurrentTeb()->Peb;
661
662 RtlAcquirePebLock();
663 index = RtlFindClearBitsAndSet( peb->TlsBitmap, 1, 1 );
664 if (index != ~0U) NtCurrentTeb()->TlsSlots[index] = 0; /* clear the value */
665 else
666 {
667 index = RtlFindClearBitsAndSet( peb->TlsExpansionBitmap, 1, 0 );
668 if (index != ~0U)
669 {
670 if (!NtCurrentTeb()->TlsExpansionSlots &&
671 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
672 8 * sizeof(peb->TlsExpansionBitmapBits) * sizeof(void*) )))
673 {
674 RtlClearBits( peb->TlsExpansionBitmap, index, 1 );
675 index = ~0U;
676 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
677 }
678 else
679 {
680 NtCurrentTeb()->TlsExpansionSlots[index] = 0; /* clear the value */
681 index += TLS_MINIMUM_AVAILABLE;
682 }
683 }
684 else SetLastError( ERROR_NO_MORE_ITEMS );
685 }
686 RtlReleasePebLock();
687 return index;
688}
689
690
691/**********************************************************************
692 * TlsFree (kernelbase.@)
693 */
694BOOL WINAPI DECLSPEC_HOTPATCH TlsFree( DWORD index )
695{
696 BOOL ret;
697
698 RtlAcquirePebLock();
699 if (index >= TLS_MINIMUM_AVAILABLE)
700 {
701 ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
702 if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
703 }
704 else
705 {
706 ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
707 if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
708 }
709 if (ret) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
710 else SetLastError( ERROR_INVALID_PARAMETER );
711 RtlReleasePebLock();
712 return ret;
713}
714
715
716/**********************************************************************
717 * TlsGetValue (kernelbase.@)
718 */
719LPVOID WINAPI DECLSPEC_HOTPATCH TlsGetValue( DWORD index )
720{
721 SetLastError( ERROR_SUCCESS );
722 if (index < TLS_MINIMUM_AVAILABLE) return NtCurrentTeb()->TlsSlots[index];
723
724 index -= TLS_MINIMUM_AVAILABLE;
725 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
726 {
727 SetLastError( ERROR_INVALID_PARAMETER );
728 return NULL;
729 }
730 if (!NtCurrentTeb()->TlsExpansionSlots) return NULL;
731 return NtCurrentTeb()->TlsExpansionSlots[index];
732}
733
734
735/**********************************************************************
736 * TlsSetValue (kernelbase.@)
737 */
738BOOL WINAPI DECLSPEC_HOTPATCH TlsSetValue( DWORD index, LPVOID value )
739{
740 if (index < TLS_MINIMUM_AVAILABLE)
741 {
742 NtCurrentTeb()->TlsSlots[index] = value;
743 }
744 else
745 {
746 index -= TLS_MINIMUM_AVAILABLE;
747 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
748 {
749 SetLastError( ERROR_INVALID_PARAMETER );
750 return FALSE;
751 }
752 if (!NtCurrentTeb()->TlsExpansionSlots &&
753 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
754 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits) * sizeof(void*) )))
755 {
756 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
757 return FALSE;
758 }
759 NtCurrentTeb()->TlsExpansionSlots[index] = value;
760 }
761 return TRUE;
762}
763
764
765/***********************************************************************
766 * Wow64GetThreadContext (kernelbase.@)
767 */
768BOOL WINAPI Wow64GetThreadContext( HANDLE handle, WOW64_CONTEXT *context)
769{
770#ifdef __i386__
771 return set_ntstatus( NtGetContextThread( handle, (CONTEXT *)context ));
772#elif defined(__x86_64__)
773 return set_ntstatus( RtlWow64GetThreadContext( handle, context ));
774#else
775 return set_ntstatus( STATUS_NOT_IMPLEMENTED );
776#endif
777}
778
779
780/***********************************************************************
781 * Wow64SetThreadContext (kernelbase.@)
782 */
783BOOL WINAPI Wow64SetThreadContext( HANDLE handle, const WOW64_CONTEXT *context)
784{
785#ifdef __i386__
786 return set_ntstatus( NtSetContextThread( handle, (const CONTEXT *)context ));
787#elif defined(__x86_64__)
788 return set_ntstatus( RtlWow64SetThreadContext( handle, context ));
789#else
790 return set_ntstatus( STATUS_NOT_IMPLEMENTED );
791#endif
792}
793
794
795/***********************************************************************
796 * Fibers
797 ***********************************************************************/
798
799
800struct fiber_actctx
801{
802 ACTIVATION_CONTEXT_STACK stack_space; /* activation context stack space */
803 ACTIVATION_CONTEXT_STACK *stack_ptr; /* last value of ActivationContextStackPointer */
804};
805
806struct fiber_data
807{
808 LPVOID param; /* 00/00 fiber param */
809 void *except; /* 04/08 saved exception handlers list */
810 void *stack_base; /* 08/10 top of fiber stack */
811 void *stack_limit; /* 0c/18 fiber stack low-water mark */
812 void *stack_allocation; /* 10/20 base of the fiber stack allocation */
813 CONTEXT context; /* 14/30 fiber context */
814 DWORD flags; /* fiber flags */
815 LPFIBER_START_ROUTINE start; /* start routine */
816 void *fls_slots; /* fiber storage slots */
817 struct fiber_actctx actctx; /* activation context state */
818};
819
820#ifdef __i386__
821extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new );
822__ASM_STDCALL_FUNC( switch_fiber, 8,
823 "movl 4(%esp),%ecx\n\t" /* old */
824 "movl %edi,0x9c(%ecx)\n\t" /* old->Edi */
825 "movl %esi,0xa0(%ecx)\n\t" /* old->Esi */
826 "movl %ebx,0xa4(%ecx)\n\t" /* old->Ebx */
827 "movl %ebp,0xb4(%ecx)\n\t" /* old->Ebp */
828 "movl 0(%esp),%eax\n\t"
829 "movl %eax,0xb8(%ecx)\n\t" /* old->Eip */
830 "leal 12(%esp),%eax\n\t"
831 "movl %eax,0xc4(%ecx)\n\t" /* old->Esp */
832 "movl 8(%esp),%ecx\n\t" /* new */
833 "movl 0x9c(%ecx),%edi\n\t" /* new->Edi */
834 "movl 0xa0(%ecx),%esi\n\t" /* new->Esi */
835 "movl 0xa4(%ecx),%ebx\n\t" /* new->Ebx */
836 "movl 0xb4(%ecx),%ebp\n\t" /* new->Ebp */
837 "movl 0xc4(%ecx),%esp\n\t" /* new->Esp */
838 "jmp *0xb8(%ecx)" ) /* new->Eip */
839#elif defined(__arm64ec__)
840static void __attribute__((naked)) WINAPI switch_fiber( CONTEXT *old, CONTEXT *new )
841{
842 asm( "mov x2, sp\n\t"
843 "stp x27, x2, [x0, #0x90]\n\t" /* old->Rbx,Rsp */
844 "str x29, [x0, #0xa0]\n\t" /* old->Rbp */
845 "stp x25, x26, [x0, #0xa8]\n\t" /* old->Rsi,Rdi */
846 "stp x19, x20, [x0, #0xd8]\n\t" /* old->R12,R13 */
847 "stp x21, x22, [x0, #0xe8]\n\t" /* old->R14,R15 */
848 "str x30, [x0, #0xf8]\n\t" /* old->Rip */
849 "stp q8, q9, [x0, #0x220]\n\t" /* old->Xmm8,Xmm9 */
850 "stp q10, q11, [x0, #0x240]\n\t" /* old->Xmm10,Xmm11 */
851 "stp q12, q13, [x0, #0x260]\n\t" /* old->Xmm12,Xmm13 */
852 "stp q14, q15, [x0, #0x280]\n\t" /* old->Xmm14,Xmm15 */
853 /* FIXME: MxCsr */
854 "ldp x27, x2, [x1, #0x90]\n\t" /* old->Rbx,Rsp */
855 "ldr x29, [x1, #0xa0]\n\t" /* old->Rbp */
856 "ldp x25, x26, [x1, #0xa8]\n\t" /* old->Rsi,Rdi */
857 "ldp x19, x20, [x1, #0xd8]\n\t" /* old->R12,R13 */
858 "ldp x21, x22, [x1, #0xe8]\n\t" /* old->R14,R15 */
859 "ldr x30, [x1, #0xf8]\n\t" /* old->Rip */
860 "ldp q8, q9, [x1, #0x220]\n\t" /* old->Xmm8,Xmm9 */
861 "ldp q10, q11, [x1, #0x240]\n\t" /* old->Xmm10,Xmm11 */
862 "ldp q12, q13, [x1, #0x260]\n\t" /* old->Xmm12,Xmm13 */
863 "ldp q14, q15, [x1, #0x280]\n\t" /* old->Xmm14,Xmm15 */
864 "mov sp, x2\n\t"
865 "ret" );
866}
867#elif defined(__x86_64__)
868extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new );
869__ASM_GLOBAL_FUNC( switch_fiber,
870 "movq %rbx,0x90(%rcx)\n\t" /* old->Rbx */
871 "leaq 0x8(%rsp),%rax\n\t"
872 "movq %rax,0x98(%rcx)\n\t" /* old->Rsp */
873 "movq %rbp,0xa0(%rcx)\n\t" /* old->Rbp */
874 "movq %rsi,0xa8(%rcx)\n\t" /* old->Rsi */
875 "movq %rdi,0xb0(%rcx)\n\t" /* old->Rdi */
876 "movq %r12,0xd8(%rcx)\n\t" /* old->R12 */
877 "movq %r13,0xe0(%rcx)\n\t" /* old->R13 */
878 "movq %r14,0xe8(%rcx)\n\t" /* old->R14 */
879 "movq %r15,0xf0(%rcx)\n\t" /* old->R15 */
880 "movq (%rsp),%rax\n\t"
881 "movq %rax,0xf8(%rcx)\n\t" /* old->Rip */
882 "movdqa %xmm6,0x200(%rcx)\n\t" /* old->Xmm6 */
883 "movdqa %xmm7,0x210(%rcx)\n\t" /* old->Xmm7 */
884 "movdqa %xmm8,0x220(%rcx)\n\t" /* old->Xmm8 */
885 "movdqa %xmm9,0x230(%rcx)\n\t" /* old->Xmm9 */
886 "movdqa %xmm10,0x240(%rcx)\n\t" /* old->Xmm10 */
887 "movdqa %xmm11,0x250(%rcx)\n\t" /* old->Xmm11 */
888 "movdqa %xmm12,0x260(%rcx)\n\t" /* old->Xmm12 */
889 "movdqa %xmm13,0x270(%rcx)\n\t" /* old->Xmm13 */
890 "movdqa %xmm14,0x280(%rcx)\n\t" /* old->Xmm14 */
891 "movdqa %xmm15,0x290(%rcx)\n\t" /* old->Xmm15 */
892 "movq 0x90(%rdx),%rbx\n\t" /* new->Rbx */
893 "movq 0xa0(%rdx),%rbp\n\t" /* new->Rbp */
894 "movq 0xa8(%rdx),%rsi\n\t" /* new->Rsi */
895 "movq 0xb0(%rdx),%rdi\n\t" /* new->Rdi */
896 "movq 0xd8(%rdx),%r12\n\t" /* new->R12 */
897 "movq 0xe0(%rdx),%r13\n\t" /* new->R13 */
898 "movq 0xe8(%rdx),%r14\n\t" /* new->R14 */
899 "movq 0xf0(%rdx),%r15\n\t" /* new->R15 */
900 "movdqa 0x200(%rdx),%xmm6\n\t" /* new->Xmm6 */
901 "movdqa 0x210(%rdx),%xmm7\n\t" /* new->Xmm7 */
902 "movdqa 0x220(%rdx),%xmm8\n\t" /* new->Xmm8 */
903 "movdqa 0x230(%rdx),%xmm9\n\t" /* new->Xmm9 */
904 "movdqa 0x240(%rdx),%xmm10\n\t" /* new->Xmm10 */
905 "movdqa 0x250(%rdx),%xmm11\n\t" /* new->Xmm11 */
906 "movdqa 0x260(%rdx),%xmm12\n\t" /* new->Xmm12 */
907 "movdqa 0x270(%rdx),%xmm13\n\t" /* new->Xmm13 */
908 "movdqa 0x280(%rdx),%xmm14\n\t" /* new->Xmm14 */
909 "movdqa 0x290(%rdx),%xmm15\n\t" /* new->Xmm15 */
910 "movq 0x98(%rdx),%rsp\n\t" /* new->Rsp */
911 "jmp *0xf8(%rdx)" ) /* new->Rip */
912#elif defined(__arm__)
913extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new );
914__ASM_GLOBAL_FUNC( switch_fiber,
915 "str r4, [r0, #0x14]\n\t" /* old->R4 */
916 "str r5, [r0, #0x18]\n\t" /* old->R5 */
917 "str r6, [r0, #0x1c]\n\t" /* old->R6 */
918 "str r7, [r0, #0x20]\n\t" /* old->R7 */
919 "str r8, [r0, #0x24]\n\t" /* old->R8 */
920 "str r9, [r0, #0x28]\n\t" /* old->R9 */
921 "str r10, [r0, #0x2c]\n\t" /* old->R10 */
922 "str r11, [r0, #0x30]\n\t" /* old->R11 */
923 "str sp, [r0, #0x38]\n\t" /* old->Sp */
924 "str lr, [r0, #0x40]\n\t" /* old->Pc */
925 "ldr r4, [r1, #0x14]\n\t" /* new->R4 */
926 "ldr r5, [r1, #0x18]\n\t" /* new->R5 */
927 "ldr r6, [r1, #0x1c]\n\t" /* new->R6 */
928 "ldr r7, [r1, #0x20]\n\t" /* new->R7 */
929 "ldr r8, [r1, #0x24]\n\t" /* new->R8 */
930 "ldr r9, [r1, #0x28]\n\t" /* new->R9 */
931 "ldr r10, [r1, #0x2c]\n\t" /* new->R10 */
932 "ldr r11, [r1, #0x30]\n\t" /* new->R11 */
933 "ldr sp, [r1, #0x38]\n\t" /* new->Sp */
934 "ldr r2, [r1, #0x40]\n\t" /* new->Pc */
935 "bx r2" )
936#elif defined(__aarch64__)
937extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new );
938__ASM_GLOBAL_FUNC( switch_fiber,
939 "stp x19, x20, [x0, #0xa0]\n\t" /* old->X19,X20 */
940 "stp x21, x22, [x0, #0xb0]\n\t" /* old->X21,X22 */
941 "stp x23, x24, [x0, #0xc0]\n\t" /* old->X23,X24 */
942 "stp x25, x26, [x0, #0xd0]\n\t" /* old->X25,X26 */
943 "stp x27, x28, [x0, #0xe0]\n\t" /* old->X27,X28 */
944 "str x29, [x0, #0xf0]\n\t" /* old->Fp */
945 "mov x2, sp\n\t"
946 "str x2, [x0, #0x100]\n\t" /* old->Sp */
947 "str x30, [x0, #0x108]\n\t" /* old->Pc */
948 "ldp x19, x20, [x1, #0xa0]\n\t" /* new->X19,X20 */
949 "ldp x21, x22, [x1, #0xb0]\n\t" /* new->X21,X22 */
950 "ldp x23, x24, [x1, #0xc0]\n\t" /* new->X23,X24 */
951 "ldp x25, x26, [x1, #0xd0]\n\t" /* new->X25,X26 */
952 "ldp x27, x28, [x1, #0xe0]\n\t" /* new->X27,X28 */
953 "ldr x29, [x1, #0xf0]\n\t" /* new->Fp */
954 "ldr x2, [x1, #0x100]\n\t" /* new->Sp */
955 "ldr x30, [x1, #0x108]\n\t" /* new->Pc */
956 "mov sp, x2\n\t"
957 "ret" )
958#else
959static void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new )
960{
961 FIXME( "not implemented\n" );
962 DbgBreakPoint();
963}
964#endif
965
966/* call the fiber initial function once we have switched stack */
967static void CDECL start_fiber(void)
968{
969 struct fiber_data *fiber = NtCurrentTeb()->Tib.FiberData;
970 LPFIBER_START_ROUTINE start = fiber->start;
971
972 __TRY
973 {
974 start( fiber->param );
975 RtlExitUserThread( 1 );
976 }
977 __EXCEPT(UnhandledExceptionFilter)
978 {
979 TerminateThread( GetCurrentThread(), GetExceptionCode() );
980 }
981 __ENDTRY
982}
983
984static void init_fiber_context( struct fiber_data *fiber )
985{
986#ifdef __i386__
987 fiber->context.Esp = (ULONG_PTR)fiber->stack_base - 4;
988 fiber->context.Eip = (ULONG_PTR)start_fiber;
989#elif defined(__arm64ec__)
990 fiber->context.Rsp = (ULONG_PTR)fiber->stack_base;
991 fiber->context.Rip = (ULONG_PTR)start_fiber;
992#elif defined(__x86_64__)
993 fiber->context.Rsp = (ULONG_PTR)fiber->stack_base - 0x28;
994 fiber->context.Rip = (ULONG_PTR)start_fiber;
995#elif defined(__arm__)
996 fiber->context.Sp = (ULONG_PTR)fiber->stack_base;
997 fiber->context.Pc = (ULONG_PTR)start_fiber;
998#elif defined(__aarch64__)
999 fiber->context.Sp = (ULONG_PTR)fiber->stack_base;
1000 fiber->context.Pc = (ULONG_PTR)start_fiber;
1001#endif
1002}
1003
1004static void move_list( LIST_ENTRY *dest, LIST_ENTRY *src )
1005{
1006 LIST_ENTRY *head = src->Flink;
1007 LIST_ENTRY *tail = src->Blink;
1008
1009 if (src != head)
1010 {
1011 dest->Flink = head;
1012 dest->Blink = tail;
1013 head->Blink = dest;
1014 tail->Flink = dest;
1015 }
1016 else InitializeListHead( dest );
1017}
1018
1019static void relocate_thread_actctx_stack( ACTIVATION_CONTEXT_STACK *dest )
1020{
1021 ACTIVATION_CONTEXT_STACK *src = NtCurrentTeb()->ActivationContextStackPointer;
1022
1023 C_ASSERT(sizeof(*dest) == sizeof(dest->ActiveFrame) + sizeof(dest->FrameListCache) +
1024 sizeof(dest->Flags) + sizeof(dest->NextCookieSequenceNumber) +
1025 sizeof(dest->StackId));
1026
1027 dest->ActiveFrame = src->ActiveFrame;
1028 move_list( &dest->FrameListCache, &src->FrameListCache );
1029 dest->Flags = src->Flags;
1030 dest->NextCookieSequenceNumber = src->NextCookieSequenceNumber;
1031 dest->StackId = src->StackId;
1032
1033 NtCurrentTeb()->ActivationContextStackPointer = dest;
1034}
1035
1036
1037/***********************************************************************
1038 * CreateFiber (kernelbase.@)
1039 */
1040LPVOID WINAPI DECLSPEC_HOTPATCH CreateFiber( SIZE_T stack, LPFIBER_START_ROUTINE start, LPVOID param )
1041{
1042 return CreateFiberEx( stack, 0, 0, start, param );
1043}
1044
1045
1046/***********************************************************************
1047 * CreateFiberEx (kernelbase.@)
1048 */
1049LPVOID WINAPI DECLSPEC_HOTPATCH CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD flags,
1050 LPFIBER_START_ROUTINE start, LPVOID param )
1051{
1052 struct fiber_data *fiber;
1053 INITIAL_TEB stack;
1054
1055 if (!(fiber = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fiber) )))
1056 {
1057 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1058 return NULL;
1059 }
1060
1061 if (!set_ntstatus( RtlCreateUserStack( stack_commit, stack_reserve, 0, 1, 1, &stack )))
1062 {
1063 HeapFree( GetProcessHeap(), 0, fiber );
1064 return NULL;
1065 }
1066
1067 fiber->stack_allocation = stack.DeallocationStack;
1068 fiber->stack_base = stack.StackBase;
1069 fiber->stack_limit = stack.StackLimit;
1070 fiber->param = param;
1071 fiber->except = (void *)-1;
1072 fiber->start = start;
1073 fiber->flags = flags;
1074 InitializeListHead( &fiber->actctx.stack_space.FrameListCache );
1075 fiber->actctx.stack_ptr = &fiber->actctx.stack_space;
1076 init_fiber_context( fiber );
1077 return fiber;
1078}
1079
1080
1081/***********************************************************************
1082 * ConvertFiberToThread (kernelbase.@)
1083 */
1084BOOL WINAPI DECLSPEC_HOTPATCH ConvertFiberToThread(void)
1085{
1086 struct fiber_data *fiber = NtCurrentTeb()->Tib.FiberData;
1087
1088 if (fiber)
1089 {
1090 relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack );
1091 NtCurrentTeb()->Tib.FiberData = NULL;
1092 HeapFree( GetProcessHeap(), 0, fiber );
1093 }
1094 return TRUE;
1095}
1096
1097
1098/***********************************************************************
1099 * ConvertThreadToFiber (kernelbase.@)
1100 */
1101LPVOID WINAPI /* DECLSPEC_HOTPATCH */ ConvertThreadToFiber( LPVOID param )
1102{
1103 return ConvertThreadToFiberEx( param, 0 );
1104}
1105
1106
1107/***********************************************************************
1108 * ConvertThreadToFiberEx (kernelbase.@)
1109 */
1110LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flags )
1111{
1112 struct fiber_data *fiber;
1113
1114 if (NtCurrentTeb()->Tib.FiberData)
1115 {
1116 SetLastError( ERROR_ALREADY_FIBER );
1117 return NULL;
1118 }
1119
1120 if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) )))
1121 {
1122 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1123 return NULL;
1124 }
1125 fiber->param = param;
1126 fiber->except = NtCurrentTeb()->Tib.ExceptionList;
1127 fiber->stack_base = NtCurrentTeb()->Tib.StackBase;
1128 fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit;
1129 fiber->stack_allocation = NtCurrentTeb()->DeallocationStack;
1130 fiber->start = NULL;
1131 fiber->flags = flags;
1132 fiber->fls_slots = NtCurrentTeb()->FlsSlots;
1133 relocate_thread_actctx_stack( &fiber->actctx.stack_space );
1134 NtCurrentTeb()->Tib.FiberData = fiber;
1135 return fiber;
1136}
1137
1138
1139/***********************************************************************
1140 * DeleteFiber (kernelbase.@)
1141 */
1142void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr )
1143{
1144 struct fiber_data *fiber = fiber_ptr;
1145
1146 if (!fiber) return;
1147 if (fiber == NtCurrentTeb()->Tib.FiberData)
1148 {
1149 relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack );
1150 HeapFree( GetProcessHeap(), 0, fiber );
1151 RtlExitUserThread( 1 );
1152 }
1153 RtlFreeUserStack( fiber->stack_allocation );
1154 RtlProcessFlsData( fiber->fls_slots, 3 );
1155 RtlFreeActivationContextStack( &fiber->actctx.stack_space );
1156 HeapFree( GetProcessHeap(), 0, fiber );
1157}
1158
1159
1160/***********************************************************************
1161 * IsThreadAFiber (kernelbase.@)
1162 */
1163BOOL WINAPI DECLSPEC_HOTPATCH IsThreadAFiber(void)
1164{
1165 return NtCurrentTeb()->Tib.FiberData != NULL;
1166}
1167
1168
1169/***********************************************************************
1170 * SwitchToFiber (kernelbase.@)
1171 */
1172void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber )
1173{
1174 struct fiber_data *new_fiber = fiber;
1175 struct fiber_data *current_fiber = NtCurrentTeb()->Tib.FiberData;
1176
1177 current_fiber->except = NtCurrentTeb()->Tib.ExceptionList;
1178 current_fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit;
1179 current_fiber->fls_slots = NtCurrentTeb()->FlsSlots;
1180 current_fiber->actctx.stack_ptr = NtCurrentTeb()->ActivationContextStackPointer;
1181 /* stack_allocation and stack_base never change */
1182
1183 /* FIXME: should save floating point context if requested in fiber->flags */
1184 NtCurrentTeb()->Tib.FiberData = new_fiber;
1185 NtCurrentTeb()->Tib.ExceptionList = new_fiber->except;
1186 NtCurrentTeb()->Tib.StackBase = new_fiber->stack_base;
1187 NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit;
1188 NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
1189 NtCurrentTeb()->FlsSlots = new_fiber->fls_slots;
1190 NtCurrentTeb()->ActivationContextStackPointer = new_fiber->actctx.stack_ptr;
1191 switch_fiber( ¤t_fiber->context, &new_fiber->context );
1192}
1193
1194
1195/***********************************************************************
1196 * FlsAlloc (kernelbase.@)
1197 */
1198DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback )
1199{
1200 DWORD index;
1201
1202 if (!set_ntstatus( RtlFlsAlloc( callback, &index ))) return FLS_OUT_OF_INDEXES;
1203 return index;
1204}
1205
1206
1207/***********************************************************************
1208 * FlsFree (kernelbase.@)
1209 */
1210BOOL WINAPI DECLSPEC_HOTPATCH FlsFree( DWORD index )
1211{
1212 return set_ntstatus( RtlFlsFree( index ));
1213}
1214
1215
1216/***********************************************************************
1217 * FlsGetValue (kernelbase.@)
1218 */
1219PVOID WINAPI DECLSPEC_HOTPATCH FlsGetValue( DWORD index )
1220{
1221 void *data;
1222
1223 if (!set_ntstatus( RtlFlsGetValue( index, &data ))) return NULL;
1224 SetLastError( ERROR_SUCCESS );
1225 return data;
1226}
1227
1228
1229/***********************************************************************
1230 * FlsSetValue (kernelbase.@)
1231 */
1232BOOL WINAPI DECLSPEC_HOTPATCH FlsSetValue( DWORD index, PVOID data )
1233{
1234 return set_ntstatus( RtlFlsSetValue( index, data ));
1235}
1236
1237
1238/***********************************************************************
1239 * Thread pool
1240 ***********************************************************************/
1241
1242
1243/***********************************************************************
1244 * CallbackMayRunLong (kernelbase.@)
1245 */
1246BOOL WINAPI DECLSPEC_HOTPATCH CallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
1247{
1248 return set_ntstatus( TpCallbackMayRunLong( instance ));
1249}
1250
1251
1252/***********************************************************************
1253 * CreateThreadpool (kernelbase.@)
1254 */
1255PTP_POOL WINAPI DECLSPEC_HOTPATCH CreateThreadpool( void *reserved )
1256{
1257 TP_POOL *pool;
1258
1259 if (!set_ntstatus( TpAllocPool( &pool, reserved ))) pool = NULL;
1260 return pool;
1261}
1262
1263
1264/***********************************************************************
1265 * CreateThreadpoolCleanupGroup (kernelbase.@)
1266 */
1267PTP_CLEANUP_GROUP WINAPI DECLSPEC_HOTPATCH CreateThreadpoolCleanupGroup(void)
1268{
1269 TP_CLEANUP_GROUP *group;
1270
1271 if (!set_ntstatus( TpAllocCleanupGroup( &group ))) return NULL;
1272 return group;
1273}
1274
1275
1276static void WINAPI tp_io_callback( TP_CALLBACK_INSTANCE *instance, void *userdata, void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io )
1277{
1278 PTP_WIN32_IO_CALLBACK callback = *(void **)io;
1279 callback( instance, userdata, cvalue, RtlNtStatusToDosError( iosb->Status ), iosb->Information, io );
1280}
1281
1282
1283/***********************************************************************
1284 * CreateThreadpoolIo (kernelbase.@)
1285 */
1286PTP_IO WINAPI DECLSPEC_HOTPATCH CreateThreadpoolIo( HANDLE handle, PTP_WIN32_IO_CALLBACK callback,
1287 PVOID userdata, TP_CALLBACK_ENVIRON *environment )
1288{
1289 TP_IO *io;
1290 if (!set_ntstatus( TpAllocIoCompletion( &io, handle, tp_io_callback, userdata, environment ))) return NULL;
1291 *(void **)io = callback; /* ntdll leaves us space to store our callback at the beginning of TP_IO struct */
1292 return io;
1293}
1294
1295
1296/***********************************************************************
1297 * CreateThreadpoolTimer (kernelbase.@)
1298 */
1299PTP_TIMER WINAPI DECLSPEC_HOTPATCH CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userdata,
1300 TP_CALLBACK_ENVIRON *environment )
1301{
1302 TP_TIMER *timer;
1303
1304 if (!set_ntstatus( TpAllocTimer( &timer, callback, userdata, environment ))) return NULL;
1305 return timer;
1306}
1307
1308
1309/***********************************************************************
1310 * CreateThreadpoolWait (kernelbase.@)
1311 */
1312PTP_WAIT WINAPI DECLSPEC_HOTPATCH CreateThreadpoolWait( PTP_WAIT_CALLBACK callback, PVOID userdata,
1313 TP_CALLBACK_ENVIRON *environment )
1314{
1315 TP_WAIT *wait;
1316
1317 if (!set_ntstatus( TpAllocWait( &wait, callback, userdata, environment ))) return NULL;
1318 return wait;
1319}
1320
1321
1322/***********************************************************************
1323 * CreateThreadpoolWork (kernelbase.@)
1324 */
1325PTP_WORK WINAPI DECLSPEC_HOTPATCH CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata,
1326 TP_CALLBACK_ENVIRON *environment )
1327{
1328 TP_WORK *work;
1329
1330 if (!set_ntstatus( TpAllocWork( &work, callback, userdata, environment ))) return NULL;
1331 return work;
1332}
1333
1334
1335/***********************************************************************
1336 * TrySubmitThreadpoolCallback (kernelbase.@)
1337 */
1338BOOL WINAPI DECLSPEC_HOTPATCH TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
1339 TP_CALLBACK_ENVIRON *environment )
1340{
1341 return set_ntstatus( TpSimpleTryPost( callback, userdata, environment ));
1342}
1343
1344
1345/***********************************************************************
1346 * QueueUserWorkItem (kernelbase.@)
1347 */
1348BOOL WINAPI DECLSPEC_HOTPATCH QueueUserWorkItem( LPTHREAD_START_ROUTINE func, PVOID context, ULONG flags )
1349{
1350 return set_ntstatus( RtlQueueWorkItem( func, context, flags ));
1351}
1352
1353/***********************************************************************
1354 * SetThreadpoolStackInformation (kernelbase.@)
1355 */
1356BOOL WINAPI DECLSPEC_HOTPATCH SetThreadpoolStackInformation( PTP_POOL pool, PTP_POOL_STACK_INFORMATION stack_info )
1357{
1358 return set_ntstatus( TpSetPoolStackInformation( pool, stack_info ));
1359}
1360
1361/***********************************************************************
1362 * QueryThreadpoolStackInformation (kernelbase.@)
1363 */
1364BOOL WINAPI DECLSPEC_HOTPATCH QueryThreadpoolStackInformation( PTP_POOL pool, PTP_POOL_STACK_INFORMATION stack_info )
1365{
1366 return set_ntstatus( TpQueryPoolStackInformation( pool, stack_info ));
1367}