1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package runtime 6 7import ( 8 "runtime/internal/atomic" 9 "runtime/internal/sys" 10 "unsafe" 11) 12 13// TODO(brainman): should not need those 14const ( 15 _NSIG = 65 16) 17 18//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll" 19//go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll" 20//go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll" 21//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" 22//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" 23//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" 24//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll" 25//go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll" 26//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll" 27//go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll" 28//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll" 29//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll" 30//go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll" 31//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll" 32//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll" 33//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll" 34//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll" 35//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll" 36//go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll" 37//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" 38//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" 39//go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" 40//go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" 41//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll" 42//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll" 43//go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll" 44//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll" 45//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll" 46//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll" 47//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll" 48//go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll" 49//go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll" 50//go:cgo_import_dynamic runtime._TlsAlloc TlsAlloc%0 "kernel32.dll" 51//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll" 52//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll" 53//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll" 54//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll" 55//go:cgo_import_dynamic runtime._WaitForMultipleObjects WaitForMultipleObjects%4 "kernel32.dll" 56//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll" 57//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll" 58 59type stdFunction unsafe.Pointer 60 61var ( 62 // Following syscalls are available on every Windows PC. 63 // All these variables are set by the Windows executable 64 // loader before the Go program starts. 65 _AddVectoredExceptionHandler, 66 _CloseHandle, 67 _CreateEventA, 68 _CreateIoCompletionPort, 69 _CreateThread, 70 _CreateWaitableTimerA, 71 _DuplicateHandle, 72 _ExitProcess, 73 _FreeEnvironmentStringsW, 74 _GetConsoleMode, 75 _GetEnvironmentStringsW, 76 _GetProcAddress, 77 _GetProcessAffinityMask, 78 _GetQueuedCompletionStatus, 79 _GetStdHandle, 80 _GetSystemDirectoryA, 81 _GetSystemInfo, 82 _GetSystemTimeAsFileTime, 83 _GetThreadContext, 84 _SetThreadContext, 85 _LoadLibraryW, 86 _LoadLibraryA, 87 _PostQueuedCompletionStatus, 88 _QueryPerformanceCounter, 89 _QueryPerformanceFrequency, 90 _ResumeThread, 91 _SetConsoleCtrlHandler, 92 _SetErrorMode, 93 _SetEvent, 94 _SetProcessPriorityBoost, 95 _SetThreadPriority, 96 _SetUnhandledExceptionFilter, 97 _SetWaitableTimer, 98 _SuspendThread, 99 _SwitchToThread, 100 _TlsAlloc, 101 _VirtualAlloc, 102 _VirtualFree, 103 _VirtualQuery, 104 _WaitForSingleObject, 105 _WaitForMultipleObjects, 106 _WriteConsoleW, 107 _WriteFile, 108 _ stdFunction 109 110 // Following syscalls are only available on some Windows PCs. 111 // We will load syscalls, if available, before using them. 112 _AddDllDirectory, 113 _AddVectoredContinueHandler, 114 _GetQueuedCompletionStatusEx, 115 _LoadLibraryExA, 116 _LoadLibraryExW, 117 _ stdFunction 118 119 // Use RtlGenRandom to generate cryptographically random data. 120 // This approach has been recommended by Microsoft (see issue 121 // 15589 for details). 122 // The RtlGenRandom is not listed in advapi32.dll, instead 123 // RtlGenRandom function can be found by searching for SystemFunction036. 124 // Also some versions of Mingw cannot link to SystemFunction036 125 // when building executable as Cgo. So load SystemFunction036 126 // manually during runtime startup. 127 _RtlGenRandom stdFunction 128 129 // Load ntdll.dll manually during startup, otherwise Mingw 130 // links wrong printf function to cgo executable (see issue 131 // 12030 for details). 132 _NtWaitForSingleObject stdFunction 133 134 // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them. 135 _timeBeginPeriod, 136 _timeEndPeriod, 137 _WSAGetOverlappedResult, 138 _ stdFunction 139) 140 141// Function to be called by windows CreateThread 142// to start new os thread. 143func tstart_stdcall(newm *m) 144 145// Called by OS using stdcall ABI. 146func ctrlhandler() 147 148type mOS struct { 149 threadLock mutex // protects "thread" and prevents closing 150 thread uintptr // thread handle 151 152 waitsema uintptr // semaphore for parking on locks 153 resumesema uintptr // semaphore to indicate suspend/resume 154 155 // preemptExtLock synchronizes preemptM with entry/exit from 156 // external C code. 157 // 158 // This protects against races between preemptM calling 159 // SuspendThread and external code on this thread calling 160 // ExitProcess. If these happen concurrently, it's possible to 161 // exit the suspending thread and suspend the exiting thread, 162 // leading to deadlock. 163 // 164 // 0 indicates this M is not being preempted or in external 165 // code. Entering external code CASes this from 0 to 1. If 166 // this fails, a preemption is in progress, so the thread must 167 // wait for the preemption. preemptM also CASes this from 0 to 168 // 1. If this fails, the preemption fails (as it would if the 169 // PC weren't in Go code). The value is reset to 0 when 170 // returning from external code or after a preemption is 171 // complete. 172 // 173 // TODO(austin): We may not need this if preemption were more 174 // tightly synchronized on the G/P status and preemption 175 // blocked transition into _Gsyscall/_Psyscall. 176 preemptExtLock uint32 177} 178 179//go:linkname os_sigpipe os.sigpipe 180func os_sigpipe() { 181 throw("too many writes on closed pipe") 182} 183 184// Stubs so tests can link correctly. These should never be called. 185func open(name *byte, mode, perm int32) int32 { 186 throw("unimplemented") 187 return -1 188} 189func closefd(fd int32) int32 { 190 throw("unimplemented") 191 return -1 192} 193func read(fd int32, p unsafe.Pointer, n int32) int32 { 194 throw("unimplemented") 195 return -1 196} 197 198type sigset struct{} 199 200// Call a Windows function with stdcall conventions, 201// and switch to os stack during the call. 202func asmstdcall(fn unsafe.Pointer) 203 204var asmstdcallAddr unsafe.Pointer 205 206func windowsFindfunc(lib uintptr, name []byte) stdFunction { 207 if name[len(name)-1] != 0 { 208 throw("usage") 209 } 210 f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0]))) 211 return stdFunction(unsafe.Pointer(f)) 212} 213 214var sysDirectory [521]byte 215var sysDirectoryLen uintptr 216 217func windowsLoadSystemLib(name []byte) uintptr { 218 if useLoadLibraryEx { 219 return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) 220 } else { 221 if sysDirectoryLen == 0 { 222 l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1)) 223 if l == 0 || l > uintptr(len(sysDirectory)-1) { 224 throw("Unable to determine system directory") 225 } 226 sysDirectory[l] = '\\' 227 sysDirectoryLen = l + 1 228 } 229 absName := append(sysDirectory[:sysDirectoryLen], name...) 230 return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0]))) 231 } 232} 233 234func loadOptionalSyscalls() { 235 var kernel32dll = []byte("kernel32.dll\000") 236 k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) 237 if k32 == 0 { 238 throw("kernel32.dll not found") 239 } 240 _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000")) 241 _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000")) 242 _GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000")) 243 _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000")) 244 _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000")) 245 useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil) 246 247 var advapi32dll = []byte("advapi32.dll\000") 248 a32 := windowsLoadSystemLib(advapi32dll) 249 if a32 == 0 { 250 throw("advapi32.dll not found") 251 } 252 _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) 253 254 var ntdll = []byte("ntdll.dll\000") 255 n32 := windowsLoadSystemLib(ntdll) 256 if n32 == 0 { 257 throw("ntdll.dll not found") 258 } 259 _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000")) 260 261 if GOARCH == "arm" { 262 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000")) 263 if _QueryPerformanceCounter == nil { 264 throw("could not find QPC syscalls") 265 } 266 } 267 268 var winmmdll = []byte("winmm.dll\000") 269 m32 := windowsLoadSystemLib(winmmdll) 270 if m32 == 0 { 271 throw("winmm.dll not found") 272 } 273 _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000")) 274 _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000")) 275 if _timeBeginPeriod == nil || _timeEndPeriod == nil { 276 throw("timeBegin/EndPeriod not found") 277 } 278 279 var ws232dll = []byte("ws2_32.dll\000") 280 ws232 := windowsLoadSystemLib(ws232dll) 281 if ws232 == 0 { 282 throw("ws2_32.dll not found") 283 } 284 _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000")) 285 if _WSAGetOverlappedResult == nil { 286 throw("WSAGetOverlappedResult not found") 287 } 288 289 if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil { 290 // running on Wine 291 initWine(k32) 292 } 293} 294 295func monitorSuspendResume() { 296 const ( 297 _DEVICE_NOTIFY_CALLBACK = 2 298 _ERROR_FILE_NOT_FOUND = 2 299 _ERROR_INVALID_PARAMETERS = 87 300 ) 301 type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct { 302 callback uintptr 303 context uintptr 304 } 305 306 powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000")) 307 if powrprof == 0 { 308 return // Running on Windows 7, where we don't need it anyway. 309 } 310 powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000")) 311 if powerRegisterSuspendResumeNotification == nil { 312 return // Running on Windows 7, where we don't need it anyway. 313 } 314 var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr { 315 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { 316 if mp.resumesema != 0 { 317 stdcall1(_SetEvent, mp.resumesema) 318 } 319 } 320 return 0 321 } 322 params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{ 323 callback: compileCallback(*efaceOf(&fn), true), 324 } 325 handle := uintptr(0) 326 ret := stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK, 327 uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle))) 328 // This function doesn't use GetLastError(), so we use the return value directly. 329 switch ret { 330 case 0: 331 return // Successful, nothing more to do. 332 case _ERROR_FILE_NOT_FOUND: 333 // Systems without access to the suspend/resume notifier 334 // also have their clock on "program time", and therefore 335 // don't want or need this anyway. 336 return 337 case _ERROR_INVALID_PARAMETERS: 338 // This is seen when running in Windows Docker. 339 // See issue 36557. 340 return 341 default: 342 println("runtime: PowerRegisterSuspendResumeNotification failed with errno=", ret) 343 throw("runtime: PowerRegisterSuspendResumeNotification failure") 344 } 345} 346 347//go:nosplit 348func getLoadLibrary() uintptr { 349 return uintptr(unsafe.Pointer(_LoadLibraryW)) 350} 351 352//go:nosplit 353func getLoadLibraryEx() uintptr { 354 return uintptr(unsafe.Pointer(_LoadLibraryExW)) 355} 356 357//go:nosplit 358func getGetProcAddress() uintptr { 359 return uintptr(unsafe.Pointer(_GetProcAddress)) 360} 361 362func getproccount() int32 { 363 var mask, sysmask uintptr 364 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) 365 if ret != 0 { 366 n := 0 367 maskbits := int(unsafe.Sizeof(mask) * 8) 368 for i := 0; i < maskbits; i++ { 369 if mask&(1<<uint(i)) != 0 { 370 n++ 371 } 372 } 373 if n != 0 { 374 return int32(n) 375 } 376 } 377 // use GetSystemInfo if GetProcessAffinityMask fails 378 var info systeminfo 379 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 380 return int32(info.dwnumberofprocessors) 381} 382 383func getPageSize() uintptr { 384 var info systeminfo 385 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 386 return uintptr(info.dwpagesize) 387} 388 389const ( 390 currentProcess = ^uintptr(0) // -1 = current process 391 currentThread = ^uintptr(1) // -2 = current thread 392) 393 394// in sys_windows_386.s and sys_windows_amd64.s: 395func externalthreadhandler() 396func getlasterror() uint32 397func setlasterror(err uint32) 398 399// When loading DLLs, we prefer to use LoadLibraryEx with 400// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not 401// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_* 402// flags are not available on some versions of Windows without a 403// security patch. 404// 405// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says: 406// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows 407// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on 408// systems that have KB2533623 installed. To determine whether the 409// flags are available, use GetProcAddress to get the address of the 410// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories 411// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_* 412// flags can be used with LoadLibraryEx." 413var useLoadLibraryEx bool 414 415var timeBeginPeriodRetValue uint32 416 417// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next 418// timer is less than 60 ms from now. Since osRelaxing may reduce 419// timer resolution to 15.6 ms, this keeps timer error under roughly 1 420// part in 4. 421const osRelaxMinNS = 60 * 1e6 422 423// osRelax is called by the scheduler when transitioning to and from 424// all Ps being idle. 425// 426// On Windows, it adjusts the system-wide timer resolution. Go needs a 427// high resolution timer while running and there's little extra cost 428// if we're already using the CPU, but if all Ps are idle there's no 429// need to consume extra power to drive the high-res timer. 430func osRelax(relax bool) uint32 { 431 if relax { 432 return uint32(stdcall1(_timeEndPeriod, 1)) 433 } else { 434 return uint32(stdcall1(_timeBeginPeriod, 1)) 435 } 436} 437 438func osinit() { 439 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) 440 usleep2Addr = unsafe.Pointer(funcPC(usleep2)) 441 switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread)) 442 443 setBadSignalMsg() 444 445 loadOptionalSyscalls() 446 447 disableWER() 448 449 initExceptionHandler() 450 451 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) 452 453 timeBeginPeriodRetValue = osRelax(false) 454 455 ncpu = getproccount() 456 457 physPageSize = getPageSize() 458 459 // Windows dynamic priority boosting assumes that a process has different types 460 // of dedicated threads -- GUI, IO, computational, etc. Go processes use 461 // equivalent threads that all do a mix of GUI, IO, computations, etc. 462 // In such context dynamic priority boosting does nothing but harm, so we turn it off. 463 stdcall2(_SetProcessPriorityBoost, currentProcess, 1) 464} 465 466// useQPCTime controls whether time.now and nanotime use QueryPerformanceCounter. 467// This is only set to 1 when running under Wine. 468var useQPCTime uint8 469 470var qpcStartCounter int64 471var qpcMultiplier int64 472 473//go:nosplit 474func nanotimeQPC() int64 { 475 var counter int64 = 0 476 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter))) 477 478 // returns number of nanoseconds 479 return (counter - qpcStartCounter) * qpcMultiplier 480} 481 482//go:nosplit 483func nowQPC() (sec int64, nsec int32, mono int64) { 484 var ft int64 485 stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft))) 486 487 t := (ft - 116444736000000000) * 100 488 489 sec = t / 1000000000 490 nsec = int32(t - sec*1000000000) 491 492 mono = nanotimeQPC() 493 return 494} 495 496func initWine(k32 uintptr) { 497 _GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000")) 498 if _GetSystemTimeAsFileTime == nil { 499 throw("could not find GetSystemTimeAsFileTime() syscall") 500 } 501 502 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000")) 503 _QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000")) 504 if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil { 505 throw("could not find QPC syscalls") 506 } 507 508 // We can not simply fallback to GetSystemTimeAsFileTime() syscall, since its time is not monotonic, 509 // instead we use QueryPerformanceCounter family of syscalls to implement monotonic timer 510 // https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx 511 512 var tmp int64 513 stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp))) 514 if tmp == 0 { 515 throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware") 516 } 517 518 // This should not overflow, it is a number of ticks of the performance counter per second, 519 // its resolution is at most 10 per usecond (on Wine, even smaller on real hardware), so it will be at most 10 millions here, 520 // panic if overflows. 521 if tmp > (1<<31 - 1) { 522 throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed") 523 } 524 qpcFrequency := int32(tmp) 525 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter))) 526 527 // Since we are supposed to run this time calls only on Wine, it does not lose precision, 528 // since Wine's timer is kind of emulated at 10 Mhz, so it will be a nice round multiplier of 100 529 // but for general purpose system (like 3.3 Mhz timer on i7) it will not be very precise. 530 // We have to do it this way (or similar), since multiplying QPC counter by 100 millions overflows 531 // int64 and resulted time will always be invalid. 532 qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil)) 533 534 useQPCTime = 1 535} 536 537//go:nosplit 538func getRandomData(r []byte) { 539 n := 0 540 if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { 541 n = len(r) 542 } 543 extendRandom(r, n) 544} 545 546func goenvs() { 547 // strings is a pointer to environment variable pairs in the form: 548 // "envA=valA\x00envB=valB\x00\x00" (in UTF-16) 549 // Two consecutive zero bytes end the list. 550 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)) 551 p := (*[1 << 24]uint16)(strings)[:] 552 553 n := 0 554 for from, i := 0, 0; true; i++ { 555 if p[i] == 0 { 556 // empty string marks the end 557 if i == from { 558 break 559 } 560 from = i + 1 561 n++ 562 } 563 } 564 envs = make([]string, n) 565 566 for i := range envs { 567 envs[i] = gostringw(&p[0]) 568 for p[0] != 0 { 569 p = p[1:] 570 } 571 p = p[1:] // skip nil byte 572 } 573 574 stdcall1(_FreeEnvironmentStringsW, uintptr(strings)) 575 576 // We call this all the way here, late in init, so that malloc works 577 // for the callback function this generates. 578 monitorSuspendResume() 579} 580 581// exiting is set to non-zero when the process is exiting. 582var exiting uint32 583 584//go:nosplit 585func exit(code int32) { 586 // Disallow thread suspension for preemption. Otherwise, 587 // ExitProcess and SuspendThread can race: SuspendThread 588 // queues a suspension request for this thread, ExitProcess 589 // kills the suspending thread, and then this thread suspends. 590 lock(&suspendLock) 591 atomic.Store(&exiting, 1) 592 stdcall1(_ExitProcess, uintptr(code)) 593} 594 595// write1 must be nosplit because it's used as a last resort in 596// functions like badmorestackg0. In such cases, we'll always take the 597// ASCII path. 598// 599//go:nosplit 600func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 { 601 const ( 602 _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 603 _STD_ERROR_HANDLE = ^uintptr(11) // -12 604 ) 605 var handle uintptr 606 switch fd { 607 case 1: 608 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) 609 case 2: 610 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) 611 default: 612 // assume fd is real windows handle. 613 handle = fd 614 } 615 isASCII := true 616 b := (*[1 << 30]byte)(buf)[:n] 617 for _, x := range b { 618 if x >= 0x80 { 619 isASCII = false 620 break 621 } 622 } 623 624 if !isASCII { 625 var m uint32 626 isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0 627 // If this is a console output, various non-unicode code pages can be in use. 628 // Use the dedicated WriteConsole call to ensure unicode is printed correctly. 629 if isConsole { 630 return int32(writeConsole(handle, buf, n)) 631 } 632 } 633 var written uint32 634 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) 635 return int32(written) 636} 637 638var ( 639 utf16ConsoleBack [1000]uint16 640 utf16ConsoleBackLock mutex 641) 642 643// writeConsole writes bufLen bytes from buf to the console File. 644// It returns the number of bytes written. 645func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int { 646 const surr2 = (surrogateMin + surrogateMax + 1) / 2 647 648 // Do not use defer for unlock. May cause issues when printing a panic. 649 lock(&utf16ConsoleBackLock) 650 651 b := (*[1 << 30]byte)(buf)[:bufLen] 652 s := *(*string)(unsafe.Pointer(&b)) 653 654 utf16tmp := utf16ConsoleBack[:] 655 656 total := len(s) 657 w := 0 658 for _, r := range s { 659 if w >= len(utf16tmp)-2 { 660 writeConsoleUTF16(handle, utf16tmp[:w]) 661 w = 0 662 } 663 if r < 0x10000 { 664 utf16tmp[w] = uint16(r) 665 w++ 666 } else { 667 r -= 0x10000 668 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff 669 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff 670 w += 2 671 } 672 } 673 writeConsoleUTF16(handle, utf16tmp[:w]) 674 unlock(&utf16ConsoleBackLock) 675 return total 676} 677 678// writeConsoleUTF16 is the dedicated windows calls that correctly prints 679// to the console regardless of the current code page. Input is utf-16 code points. 680// The handle must be a console handle. 681func writeConsoleUTF16(handle uintptr, b []uint16) { 682 l := uint32(len(b)) 683 if l == 0 { 684 return 685 } 686 var written uint32 687 stdcall5(_WriteConsoleW, 688 handle, 689 uintptr(unsafe.Pointer(&b[0])), 690 uintptr(l), 691 uintptr(unsafe.Pointer(&written)), 692 0, 693 ) 694 return 695} 696 697// walltime1 isn't implemented on Windows, but will never be called. 698func walltime1() (sec int64, nsec int32) 699 700//go:nosplit 701func semasleep(ns int64) int32 { 702 const ( 703 _WAIT_ABANDONED = 0x00000080 704 _WAIT_OBJECT_0 = 0x00000000 705 _WAIT_TIMEOUT = 0x00000102 706 _WAIT_FAILED = 0xFFFFFFFF 707 ) 708 709 var result uintptr 710 if ns < 0 { 711 result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE)) 712 } else { 713 start := nanotime() 714 elapsed := int64(0) 715 for { 716 ms := int64(timediv(ns-elapsed, 1000000, nil)) 717 if ms == 0 { 718 ms = 1 719 } 720 result = stdcall4(_WaitForMultipleObjects, 2, 721 uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})), 722 0, uintptr(ms)) 723 if result != _WAIT_OBJECT_0+1 { 724 // Not a suspend/resume event 725 break 726 } 727 elapsed = nanotime() - start 728 if elapsed >= ns { 729 return -1 730 } 731 } 732 } 733 switch result { 734 case _WAIT_OBJECT_0: // Signaled 735 return 0 736 737 case _WAIT_TIMEOUT: 738 return -1 739 740 case _WAIT_ABANDONED: 741 systemstack(func() { 742 throw("runtime.semasleep wait_abandoned") 743 }) 744 745 case _WAIT_FAILED: 746 systemstack(func() { 747 print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n") 748 throw("runtime.semasleep wait_failed") 749 }) 750 751 default: 752 systemstack(func() { 753 print("runtime: waitforsingleobject unexpected; result=", result, "\n") 754 throw("runtime.semasleep unexpected") 755 }) 756 } 757 758 return -1 // unreachable 759} 760 761//go:nosplit 762func semawakeup(mp *m) { 763 if stdcall1(_SetEvent, mp.waitsema) == 0 { 764 systemstack(func() { 765 print("runtime: setevent failed; errno=", getlasterror(), "\n") 766 throw("runtime.semawakeup") 767 }) 768 } 769} 770 771//go:nosplit 772func semacreate(mp *m) { 773 if mp.waitsema != 0 { 774 return 775 } 776 mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0) 777 if mp.waitsema == 0 { 778 systemstack(func() { 779 print("runtime: createevent failed; errno=", getlasterror(), "\n") 780 throw("runtime.semacreate") 781 }) 782 } 783 mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0) 784 if mp.resumesema == 0 { 785 systemstack(func() { 786 print("runtime: createevent failed; errno=", getlasterror(), "\n") 787 throw("runtime.semacreate") 788 }) 789 stdcall1(_CloseHandle, mp.waitsema) 790 mp.waitsema = 0 791 } 792} 793 794// May run with m.p==nil, so write barriers are not allowed. This 795// function is called by newosproc0, so it is also required to 796// operate without stack guards. 797//go:nowritebarrierrec 798//go:nosplit 799func newosproc(mp *m) { 800 // We pass 0 for the stack size to use the default for this binary. 801 thandle := stdcall6(_CreateThread, 0, 0, 802 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), 803 0, 0) 804 805 if thandle == 0 { 806 if atomic.Load(&exiting) != 0 { 807 // CreateThread may fail if called 808 // concurrently with ExitProcess. If this 809 // happens, just freeze this thread and let 810 // the process exit. See issue #18253. 811 lock(&deadlock) 812 lock(&deadlock) 813 } 814 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n") 815 throw("runtime.newosproc") 816 } 817 818 // Close thandle to avoid leaking the thread object if it exits. 819 stdcall1(_CloseHandle, thandle) 820} 821 822// Used by the C library build mode. On Linux this function would allocate a 823// stack, but that's not necessary for Windows. No stack guards are present 824// and the GC has not been initialized, so write barriers will fail. 825//go:nowritebarrierrec 826//go:nosplit 827func newosproc0(mp *m, stk unsafe.Pointer) { 828 // TODO: this is completely broken. The args passed to newosproc0 (in asm_amd64.s) 829 // are stacksize and function, not *m and stack. 830 // Check os_linux.go for an implementation that might actually work. 831 throw("bad newosproc0") 832} 833 834func exitThread(wait *uint32) { 835 // We should never reach exitThread on Windows because we let 836 // the OS clean up threads. 837 throw("exitThread") 838} 839 840// Called to initialize a new m (including the bootstrap m). 841// Called on the parent thread (main thread in case of bootstrap), can allocate memory. 842func mpreinit(mp *m) { 843} 844 845//go:nosplit 846func msigsave(mp *m) { 847} 848 849//go:nosplit 850func msigrestore(sigmask sigset) { 851} 852 853//go:nosplit 854//go:nowritebarrierrec 855func clearSignalHandlers() { 856} 857 858//go:nosplit 859func sigblock() { 860} 861 862// Called to initialize a new m (including the bootstrap m). 863// Called on the new thread, cannot allocate memory. 864func minit() { 865 var thandle uintptr 866 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) 867 868 mp := getg().m 869 lock(&mp.threadLock) 870 mp.thread = thandle 871 unlock(&mp.threadLock) 872 873 // Query the true stack base from the OS. Currently we're 874 // running on a small assumed stack. 875 var mbi memoryBasicInformation 876 res := stdcall3(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi)) 877 if res == 0 { 878 print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n") 879 throw("VirtualQuery for stack base failed") 880 } 881 // The system leaves an 8K PAGE_GUARD region at the bottom of 882 // the stack (in theory VirtualQuery isn't supposed to include 883 // that, but it does). Add an additional 8K of slop for 884 // calling C functions that don't have stack checks and for 885 // lastcontinuehandler. We shouldn't be anywhere near this 886 // bound anyway. 887 base := mbi.allocationBase + 16<<10 888 // Sanity check the stack bounds. 889 g0 := getg() 890 if base > g0.stack.hi || g0.stack.hi-base > 64<<20 { 891 print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n") 892 throw("bad g0 stack") 893 } 894 g0.stack.lo = base 895 g0.stackguard0 = g0.stack.lo + _StackGuard 896 g0.stackguard1 = g0.stackguard0 897 // Sanity check the SP. 898 stackcheck() 899} 900 901// Called from dropm to undo the effect of an minit. 902//go:nosplit 903func unminit() { 904 mp := getg().m 905 lock(&mp.threadLock) 906 stdcall1(_CloseHandle, mp.thread) 907 mp.thread = 0 908 unlock(&mp.threadLock) 909} 910 911// Calling stdcall on os stack. 912// May run during STW, so write barriers are not allowed. 913//go:nowritebarrier 914//go:nosplit 915func stdcall(fn stdFunction) uintptr { 916 gp := getg() 917 mp := gp.m 918 mp.libcall.fn = uintptr(unsafe.Pointer(fn)) 919 resetLibcall := false 920 if mp.profilehz != 0 && mp.libcallsp == 0 { 921 // leave pc/sp for cpu profiler 922 mp.libcallg.set(gp) 923 mp.libcallpc = getcallerpc() 924 // sp must be the last, because once async cpu profiler finds 925 // all three values to be non-zero, it will use them 926 mp.libcallsp = getcallersp() 927 resetLibcall = true // See comment in sys_darwin.go:libcCall 928 } 929 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall)) 930 if resetLibcall { 931 mp.libcallsp = 0 932 } 933 return mp.libcall.r1 934} 935 936//go:nosplit 937func stdcall0(fn stdFunction) uintptr { 938 mp := getg().m 939 mp.libcall.n = 0 940 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes 941 return stdcall(fn) 942} 943 944//go:nosplit 945func stdcall1(fn stdFunction, a0 uintptr) uintptr { 946 mp := getg().m 947 mp.libcall.n = 1 948 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 949 return stdcall(fn) 950} 951 952//go:nosplit 953func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { 954 mp := getg().m 955 mp.libcall.n = 2 956 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 957 return stdcall(fn) 958} 959 960//go:nosplit 961func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { 962 mp := getg().m 963 mp.libcall.n = 3 964 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 965 return stdcall(fn) 966} 967 968//go:nosplit 969func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { 970 mp := getg().m 971 mp.libcall.n = 4 972 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 973 return stdcall(fn) 974} 975 976//go:nosplit 977func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { 978 mp := getg().m 979 mp.libcall.n = 5 980 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 981 return stdcall(fn) 982} 983 984//go:nosplit 985func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { 986 mp := getg().m 987 mp.libcall.n = 6 988 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 989 return stdcall(fn) 990} 991 992//go:nosplit 993func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { 994 mp := getg().m 995 mp.libcall.n = 7 996 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 997 return stdcall(fn) 998} 999 1000// in sys_windows_386.s and sys_windows_amd64.s 1001func onosstack(fn unsafe.Pointer, arg uint32) 1002func usleep2(usec uint32) 1003func switchtothread() 1004 1005var usleep2Addr unsafe.Pointer 1006var switchtothreadAddr unsafe.Pointer 1007 1008//go:nosplit 1009func osyield() { 1010 onosstack(switchtothreadAddr, 0) 1011} 1012 1013//go:nosplit 1014func usleep(us uint32) { 1015 // Have 1us units; want 100ns units. 1016 onosstack(usleep2Addr, 10*us) 1017} 1018 1019func ctrlhandler1(_type uint32) uint32 { 1020 var s uint32 1021 1022 switch _type { 1023 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: 1024 s = _SIGINT 1025 case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT: 1026 s = _SIGTERM 1027 default: 1028 return 0 1029 } 1030 1031 if sigsend(s) { 1032 return 1 1033 } 1034 exit(2) // SIGINT, SIGTERM, etc 1035 return 0 1036} 1037 1038// in sys_windows_386.s and sys_windows_amd64.s 1039func profileloop() 1040 1041// called from zcallback_windows_*.s to sys_windows_*.s 1042func callbackasm1() 1043 1044var profiletimer uintptr 1045 1046func profilem(mp *m, thread uintptr) { 1047 var r *context 1048 rbuf := make([]byte, unsafe.Sizeof(*r)+15) 1049 1050 // align Context to 16 bytes 1051 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) 1052 r.contextflags = _CONTEXT_CONTROL 1053 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(r))) 1054 1055 gp := gFromTLS(mp) 1056 1057 sigprof(r.ip(), r.sp(), r.lr(), gp, mp) 1058} 1059 1060func gFromTLS(mp *m) *g { 1061 switch GOARCH { 1062 case "arm": 1063 tls := &mp.tls[0] 1064 return **((***g)(unsafe.Pointer(tls))) 1065 case "386", "amd64": 1066 tls := &mp.tls[0] 1067 return *((**g)(unsafe.Pointer(tls))) 1068 } 1069 throw("unsupported architecture") 1070 return nil 1071} 1072 1073func profileloop1(param uintptr) uint32 { 1074 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) 1075 1076 for { 1077 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) 1078 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm))) 1079 for mp := first; mp != nil; mp = mp.alllink { 1080 lock(&mp.threadLock) 1081 // Do not profile threads blocked on Notes, 1082 // this includes idle worker threads, 1083 // idle timer thread, idle heap scavenger, etc. 1084 if mp.thread == 0 || mp.profilehz == 0 || mp.blocked { 1085 unlock(&mp.threadLock) 1086 continue 1087 } 1088 // Acquire our own handle to the thread. 1089 var thread uintptr 1090 stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) 1091 unlock(&mp.threadLock) 1092 // mp may exit between the DuplicateHandle 1093 // above and the SuspendThread. The handle 1094 // will remain valid, but SuspendThread may 1095 // fail. 1096 if int32(stdcall1(_SuspendThread, thread)) == -1 { 1097 // The thread no longer exists. 1098 stdcall1(_CloseHandle, thread) 1099 continue 1100 } 1101 if mp.profilehz != 0 && !mp.blocked { 1102 // Pass the thread handle in case mp 1103 // was in the process of shutting down. 1104 profilem(mp, thread) 1105 } 1106 stdcall1(_ResumeThread, thread) 1107 stdcall1(_CloseHandle, thread) 1108 } 1109 } 1110} 1111 1112func setProcessCPUProfiler(hz int32) { 1113 if profiletimer == 0 { 1114 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) 1115 atomic.Storeuintptr(&profiletimer, timer) 1116 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) 1117 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) 1118 stdcall1(_CloseHandle, thread) 1119 } 1120} 1121 1122func setThreadCPUProfiler(hz int32) { 1123 ms := int32(0) 1124 due := ^int64(^uint64(1 << 63)) 1125 if hz > 0 { 1126 ms = 1000 / hz 1127 if ms == 0 { 1128 ms = 1 1129 } 1130 due = int64(ms) * -10000 1131 } 1132 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) 1133 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) 1134} 1135 1136const preemptMSupported = GOARCH != "arm" 1137 1138// suspendLock protects simultaneous SuspendThread operations from 1139// suspending each other. 1140var suspendLock mutex 1141 1142func preemptM(mp *m) { 1143 if GOARCH == "arm" { 1144 // TODO: Implement call injection 1145 return 1146 } 1147 1148 if mp == getg().m { 1149 throw("self-preempt") 1150 } 1151 1152 // Synchronize with external code that may try to ExitProcess. 1153 if !atomic.Cas(&mp.preemptExtLock, 0, 1) { 1154 // External code is running. Fail the preemption 1155 // attempt. 1156 atomic.Xadd(&mp.preemptGen, 1) 1157 return 1158 } 1159 1160 // Acquire our own handle to mp's thread. 1161 lock(&mp.threadLock) 1162 if mp.thread == 0 { 1163 // The M hasn't been minit'd yet (or was just unminit'd). 1164 unlock(&mp.threadLock) 1165 atomic.Store(&mp.preemptExtLock, 0) 1166 atomic.Xadd(&mp.preemptGen, 1) 1167 return 1168 } 1169 var thread uintptr 1170 stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) 1171 unlock(&mp.threadLock) 1172 1173 // Prepare thread context buffer. 1174 var c *context 1175 cbuf := make([]byte, unsafe.Sizeof(*c)+15) 1176 // Align Context to 16 bytes. 1177 c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15)) 1178 c.contextflags = _CONTEXT_CONTROL 1179 1180 // Serialize thread suspension. SuspendThread is asynchronous, 1181 // so it's otherwise possible for two threads to suspend each 1182 // other and deadlock. We must hold this lock until after 1183 // GetThreadContext, since that blocks until the thread is 1184 // actually suspended. 1185 lock(&suspendLock) 1186 1187 // Suspend the thread. 1188 if int32(stdcall1(_SuspendThread, thread)) == -1 { 1189 unlock(&suspendLock) 1190 stdcall1(_CloseHandle, thread) 1191 atomic.Store(&mp.preemptExtLock, 0) 1192 // The thread no longer exists. This shouldn't be 1193 // possible, but just acknowledge the request. 1194 atomic.Xadd(&mp.preemptGen, 1) 1195 return 1196 } 1197 1198 // We have to be very careful between this point and once 1199 // we've shown mp is at an async safe-point. This is like a 1200 // signal handler in the sense that mp could have been doing 1201 // anything when we stopped it, including holding arbitrary 1202 // locks. 1203 1204 // We have to get the thread context before inspecting the M 1205 // because SuspendThread only requests a suspend. 1206 // GetThreadContext actually blocks until it's suspended. 1207 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c))) 1208 1209 unlock(&suspendLock) 1210 1211 // Does it want a preemption and is it safe to preempt? 1212 gp := gFromTLS(mp) 1213 if wantAsyncPreempt(gp) && isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()) { 1214 // Inject call to asyncPreempt 1215 targetPC := funcPC(asyncPreempt) 1216 switch GOARCH { 1217 default: 1218 throw("unsupported architecture") 1219 case "386", "amd64": 1220 // Make it look like the thread called targetPC. 1221 pc := c.ip() 1222 sp := c.sp() 1223 sp -= sys.PtrSize 1224 *(*uintptr)(unsafe.Pointer(sp)) = pc 1225 c.set_sp(sp) 1226 c.set_ip(targetPC) 1227 } 1228 1229 stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c))) 1230 } 1231 1232 atomic.Store(&mp.preemptExtLock, 0) 1233 1234 // Acknowledge the preemption. 1235 atomic.Xadd(&mp.preemptGen, 1) 1236 1237 stdcall1(_ResumeThread, thread) 1238 stdcall1(_CloseHandle, thread) 1239} 1240 1241// osPreemptExtEnter is called before entering external code that may 1242// call ExitProcess. 1243// 1244// This must be nosplit because it may be called from a syscall with 1245// untyped stack slots, so the stack must not be grown or scanned. 1246// 1247//go:nosplit 1248func osPreemptExtEnter(mp *m) { 1249 for !atomic.Cas(&mp.preemptExtLock, 0, 1) { 1250 // An asynchronous preemption is in progress. It's not 1251 // safe to enter external code because it may call 1252 // ExitProcess and deadlock with SuspendThread. 1253 // Ideally we would do the preemption ourselves, but 1254 // can't since there may be untyped syscall arguments 1255 // on the stack. Instead, just wait and encourage the 1256 // SuspendThread APC to run. The preemption should be 1257 // done shortly. 1258 osyield() 1259 } 1260 // Asynchronous preemption is now blocked. 1261} 1262 1263// osPreemptExtExit is called after returning from external code that 1264// may call ExitProcess. 1265// 1266// See osPreemptExtEnter for why this is nosplit. 1267// 1268//go:nosplit 1269func osPreemptExtExit(mp *m) { 1270 atomic.Store(&mp.preemptExtLock, 0) 1271} 1272