Reactos
at master 1367 lines 48 kB view raw
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, &times, 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( &current_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}