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