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