github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/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 "unsafe" 10 ) 11 12 // TODO(brainman): should not need those 13 const ( 14 _NSIG = 65 15 ) 16 17 //go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll" 18 //go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll" 19 //go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll" 20 //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" 21 //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" 22 //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" 23 //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll" 24 //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll" 25 //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll" 26 //go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll" 27 //go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll" 28 //go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll" 29 //go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll" 30 //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll" 31 //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll" 32 //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll" 33 //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll" 34 //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" 35 //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" 36 //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" 37 //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll" 38 //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll" 39 //go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll" 40 //go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll" 41 //go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll" 42 //go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll" 43 //go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll" 44 //go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll" 45 //go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll" 46 //go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll" 47 //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll" 48 //go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll" 49 //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll" 50 //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll" 51 //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll" 52 //go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll" 53 //go:cgo_import_dynamic runtime._timeEndPeriod timeEndPeriod%1 "winmm.dll" 54 55 type stdFunction unsafe.Pointer 56 57 var ( 58 // Following syscalls are available on every Windows PC. 59 // All these variables are set by the Windows executable 60 // loader before the Go program starts. 61 _AddVectoredExceptionHandler, 62 _CloseHandle, 63 _CreateEventA, 64 _CreateIoCompletionPort, 65 _CreateThread, 66 _CreateWaitableTimerA, 67 _DuplicateHandle, 68 _ExitProcess, 69 _FreeEnvironmentStringsW, 70 _GetConsoleMode, 71 _GetEnvironmentStringsW, 72 _GetProcAddress, 73 _GetProcessAffinityMask, 74 _GetQueuedCompletionStatus, 75 _GetStdHandle, 76 _GetSystemInfo, 77 _GetSystemTimeAsFileTime, 78 _GetThreadContext, 79 _LoadLibraryW, 80 _LoadLibraryA, 81 _QueryPerformanceCounter, 82 _QueryPerformanceFrequency, 83 _ResumeThread, 84 _SetConsoleCtrlHandler, 85 _SetErrorMode, 86 _SetEvent, 87 _SetProcessPriorityBoost, 88 _SetThreadPriority, 89 _SetUnhandledExceptionFilter, 90 _SetWaitableTimer, 91 _SuspendThread, 92 _SwitchToThread, 93 _VirtualAlloc, 94 _VirtualFree, 95 _WSAGetOverlappedResult, 96 _WaitForSingleObject, 97 _WriteConsoleW, 98 _WriteFile, 99 _timeBeginPeriod, 100 _timeEndPeriod, 101 _ stdFunction 102 103 // Following syscalls are only available on some Windows PCs. 104 // We will load syscalls, if available, before using them. 105 _AddDllDirectory, 106 _AddVectoredContinueHandler, 107 _GetQueuedCompletionStatusEx, 108 _LoadLibraryExW, 109 _ stdFunction 110 111 // Use RtlGenRandom to generate cryptographically random data. 112 // This approach has been recommended by Microsoft (see issue 113 // 15589 for details). 114 // The RtlGenRandom is not listed in advapi32.dll, instead 115 // RtlGenRandom function can be found by searching for SystemFunction036. 116 // Also some versions of Mingw cannot link to SystemFunction036 117 // when building executable as Cgo. So load SystemFunction036 118 // manually during runtime startup. 119 _RtlGenRandom stdFunction 120 121 // Load ntdll.dll manually during startup, otherwise Mingw 122 // links wrong printf function to cgo executable (see issue 123 // 12030 for details). 124 _NtWaitForSingleObject stdFunction 125 ) 126 127 // Function to be called by windows CreateThread 128 // to start new os thread. 129 func tstart_stdcall(newm *m) uint32 130 131 func ctrlhandler(_type uint32) uint32 132 133 type mOS struct { 134 waitsema uintptr // semaphore for parking on locks 135 } 136 137 //go:linkname os_sigpipe os.sigpipe 138 func os_sigpipe() { 139 throw("too many writes on closed pipe") 140 } 141 142 // Stubs so tests can link correctly. These should never be called. 143 func open(name *byte, mode, perm int32) int32 { 144 throw("unimplemented") 145 return -1 146 } 147 func closefd(fd int32) int32 { 148 throw("unimplemented") 149 return -1 150 } 151 func read(fd int32, p unsafe.Pointer, n int32) int32 { 152 throw("unimplemented") 153 return -1 154 } 155 156 type sigset struct{} 157 158 // Call a Windows function with stdcall conventions, 159 // and switch to os stack during the call. 160 func asmstdcall(fn unsafe.Pointer) 161 162 var asmstdcallAddr unsafe.Pointer 163 164 func windowsFindfunc(lib uintptr, name []byte) stdFunction { 165 if name[len(name)-1] != 0 { 166 throw("usage") 167 } 168 f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0]))) 169 return stdFunction(unsafe.Pointer(f)) 170 } 171 172 func loadOptionalSyscalls() { 173 var kernel32dll = []byte("kernel32.dll\000") 174 k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) 175 if k32 == 0 { 176 throw("kernel32.dll not found") 177 } 178 _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000")) 179 _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000")) 180 _GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000")) 181 _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000")) 182 183 var advapi32dll = []byte("advapi32.dll\000") 184 a32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&advapi32dll[0]))) 185 if a32 == 0 { 186 throw("advapi32.dll not found") 187 } 188 _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) 189 190 var ntdll = []byte("ntdll.dll\000") 191 n32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&ntdll[0]))) 192 if n32 == 0 { 193 throw("ntdll.dll not found") 194 } 195 _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000")) 196 197 if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil { 198 // running on Wine 199 initWine(k32) 200 } 201 } 202 203 //go:nosplit 204 func getLoadLibrary() uintptr { 205 return uintptr(unsafe.Pointer(_LoadLibraryW)) 206 } 207 208 //go:nosplit 209 func getLoadLibraryEx() uintptr { 210 return uintptr(unsafe.Pointer(_LoadLibraryExW)) 211 } 212 213 //go:nosplit 214 func getGetProcAddress() uintptr { 215 return uintptr(unsafe.Pointer(_GetProcAddress)) 216 } 217 218 func getproccount() int32 { 219 var mask, sysmask uintptr 220 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) 221 if ret != 0 { 222 n := 0 223 maskbits := int(unsafe.Sizeof(mask) * 8) 224 for i := 0; i < maskbits; i++ { 225 if mask&(1<<uint(i)) != 0 { 226 n++ 227 } 228 } 229 if n != 0 { 230 return int32(n) 231 } 232 } 233 // use GetSystemInfo if GetProcessAffinityMask fails 234 var info systeminfo 235 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 236 return int32(info.dwnumberofprocessors) 237 } 238 239 func getPageSize() uintptr { 240 var info systeminfo 241 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 242 return uintptr(info.dwpagesize) 243 } 244 245 const ( 246 currentProcess = ^uintptr(0) // -1 = current process 247 currentThread = ^uintptr(1) // -2 = current thread 248 ) 249 250 // in sys_windows_386.s and sys_windows_amd64.s: 251 func externalthreadhandler() 252 func getlasterror() uint32 253 func setlasterror(err uint32) 254 255 // When loading DLLs, we prefer to use LoadLibraryEx with 256 // LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not 257 // available on old Windows, though, and the LOAD_LIBRARY_SEARCH_* 258 // flags are not available on some versions of Windows without a 259 // security patch. 260 // 261 // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says: 262 // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows 263 // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on 264 // systems that have KB2533623 installed. To determine whether the 265 // flags are available, use GetProcAddress to get the address of the 266 // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories 267 // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_* 268 // flags can be used with LoadLibraryEx." 269 var useLoadLibraryEx bool 270 271 var timeBeginPeriodRetValue uint32 272 273 // osRelaxMinNS indicates that sysmon shouldn't osRelax if the next 274 // timer is less than 60 ms from now. Since osRelaxing may reduce 275 // timer resolution to 15.6 ms, this keeps timer error under roughly 1 276 // part in 4. 277 const osRelaxMinNS = 60 * 1e6 278 279 // osRelax is called by the scheduler when transitioning to and from 280 // all Ps being idle. 281 // 282 // On Windows, it adjusts the system-wide timer resolution. Go needs a 283 // high resolution timer while running and there's little extra cost 284 // if we're already using the CPU, but if all Ps are idle there's no 285 // need to consume extra power to drive the high-res timer. 286 func osRelax(relax bool) uint32 { 287 if relax { 288 return uint32(stdcall1(_timeEndPeriod, 1)) 289 } else { 290 return uint32(stdcall1(_timeBeginPeriod, 1)) 291 } 292 } 293 294 func osinit() { 295 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) 296 usleep2Addr = unsafe.Pointer(funcPC(usleep2)) 297 switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread)) 298 299 setBadSignalMsg() 300 301 loadOptionalSyscalls() 302 303 useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil) 304 305 disableWER() 306 307 externalthreadhandlerp = funcPC(externalthreadhandler) 308 309 initExceptionHandler() 310 311 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) 312 313 timeBeginPeriodRetValue = osRelax(false) 314 315 ncpu = getproccount() 316 317 physPageSize = getPageSize() 318 319 // Windows dynamic priority boosting assumes that a process has different types 320 // of dedicated threads -- GUI, IO, computational, etc. Go processes use 321 // equivalent threads that all do a mix of GUI, IO, computations, etc. 322 // In such context dynamic priority boosting does nothing but harm, so we turn it off. 323 stdcall2(_SetProcessPriorityBoost, currentProcess, 1) 324 } 325 326 func nanotime() int64 327 328 // useQPCTime controls whether time.now and nanotime use QueryPerformanceCounter. 329 // This is only set to 1 when running under Wine. 330 var useQPCTime uint8 331 332 var qpcStartCounter int64 333 var qpcMultiplier int64 334 335 //go:nosplit 336 func nanotimeQPC() int64 { 337 var counter int64 = 0 338 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter))) 339 340 // returns number of nanoseconds 341 return (counter - qpcStartCounter) * qpcMultiplier 342 } 343 344 //go:nosplit 345 func nowQPC() (sec int64, nsec int32, mono int64) { 346 var ft int64 347 stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft))) 348 349 t := (ft - 116444736000000000) * 100 350 351 sec = t / 1000000000 352 nsec = int32(t - sec*1000000000) 353 354 mono = nanotimeQPC() 355 return 356 } 357 358 func initWine(k32 uintptr) { 359 _GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000")) 360 if _GetSystemTimeAsFileTime == nil { 361 throw("could not find GetSystemTimeAsFileTime() syscall") 362 } 363 364 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000")) 365 _QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000")) 366 if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil { 367 throw("could not find QPC syscalls") 368 } 369 370 // We can not simply fallback to GetSystemTimeAsFileTime() syscall, since its time is not monotonic, 371 // instead we use QueryPerformanceCounter family of syscalls to implement monotonic timer 372 // https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx 373 374 var tmp int64 375 stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp))) 376 if tmp == 0 { 377 throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware") 378 } 379 380 // This should not overflow, it is a number of ticks of the performance counter per second, 381 // its resolution is at most 10 per usecond (on Wine, even smaller on real hardware), so it will be at most 10 millions here, 382 // panic if overflows. 383 if tmp > (1<<31 - 1) { 384 throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed") 385 } 386 qpcFrequency := int32(tmp) 387 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter))) 388 389 // Since we are supposed to run this time calls only on Wine, it does not lose precision, 390 // since Wine's timer is kind of emulated at 10 Mhz, so it will be a nice round multiplier of 100 391 // but for general purpose system (like 3.3 Mhz timer on i7) it will not be very precise. 392 // We have to do it this way (or similar), since multiplying QPC counter by 100 millions overflows 393 // int64 and resulted time will always be invalid. 394 qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil)) 395 396 useQPCTime = 1 397 } 398 399 //go:nosplit 400 func getRandomData(r []byte) { 401 n := 0 402 if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { 403 n = len(r) 404 } 405 extendRandom(r, n) 406 } 407 408 func goenvs() { 409 // strings is a pointer to environment variable pairs in the form: 410 // "envA=valA\x00envB=valB\x00\x00" (in UTF-16) 411 // Two consecutive zero bytes end the list. 412 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)) 413 p := (*[1 << 24]uint16)(strings)[:] 414 415 n := 0 416 for from, i := 0, 0; true; i++ { 417 if p[i] == 0 { 418 // empty string marks the end 419 if i == from { 420 break 421 } 422 from = i + 1 423 n++ 424 } 425 } 426 envs = make([]string, n) 427 428 for i := range envs { 429 envs[i] = gostringw(&p[0]) 430 for p[0] != 0 { 431 p = p[1:] 432 } 433 p = p[1:] // skip nil byte 434 } 435 436 stdcall1(_FreeEnvironmentStringsW, uintptr(strings)) 437 } 438 439 // exiting is set to non-zero when the process is exiting. 440 var exiting uint32 441 442 //go:nosplit 443 func exit(code int32) { 444 atomic.Store(&exiting, 1) 445 stdcall1(_ExitProcess, uintptr(code)) 446 } 447 448 //go:nosplit 449 func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { 450 const ( 451 _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 452 _STD_ERROR_HANDLE = ^uintptr(11) // -12 453 ) 454 var handle uintptr 455 switch fd { 456 case 1: 457 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) 458 case 2: 459 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) 460 default: 461 // assume fd is real windows handle. 462 handle = fd 463 } 464 isASCII := true 465 b := (*[1 << 30]byte)(buf)[:n] 466 for _, x := range b { 467 if x >= 0x80 { 468 isASCII = false 469 break 470 } 471 } 472 473 if !isASCII { 474 var m uint32 475 isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0 476 // If this is a console output, various non-unicode code pages can be in use. 477 // Use the dedicated WriteConsole call to ensure unicode is printed correctly. 478 if isConsole { 479 return int32(writeConsole(handle, buf, n)) 480 } 481 } 482 var written uint32 483 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) 484 return int32(written) 485 } 486 487 var ( 488 utf16ConsoleBack [1000]uint16 489 utf16ConsoleBackLock mutex 490 ) 491 492 // writeConsole writes bufLen bytes from buf to the console File. 493 // It returns the number of bytes written. 494 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int { 495 const surr2 = (surrogateMin + surrogateMax + 1) / 2 496 497 // Do not use defer for unlock. May cause issues when printing a panic. 498 lock(&utf16ConsoleBackLock) 499 500 b := (*[1 << 30]byte)(buf)[:bufLen] 501 s := *(*string)(unsafe.Pointer(&b)) 502 503 utf16tmp := utf16ConsoleBack[:] 504 505 total := len(s) 506 w := 0 507 for _, r := range s { 508 if w >= len(utf16tmp)-2 { 509 writeConsoleUTF16(handle, utf16tmp[:w]) 510 w = 0 511 } 512 if r < 0x10000 { 513 utf16tmp[w] = uint16(r) 514 w++ 515 } else { 516 r -= 0x10000 517 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff 518 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff 519 w += 2 520 } 521 } 522 writeConsoleUTF16(handle, utf16tmp[:w]) 523 unlock(&utf16ConsoleBackLock) 524 return total 525 } 526 527 // writeConsoleUTF16 is the dedicated windows calls that correctly prints 528 // to the console regardless of the current code page. Input is utf-16 code points. 529 // The handle must be a console handle. 530 func writeConsoleUTF16(handle uintptr, b []uint16) { 531 l := uint32(len(b)) 532 if l == 0 { 533 return 534 } 535 var written uint32 536 stdcall5(_WriteConsoleW, 537 handle, 538 uintptr(unsafe.Pointer(&b[0])), 539 uintptr(l), 540 uintptr(unsafe.Pointer(&written)), 541 0, 542 ) 543 return 544 } 545 546 //go:nosplit 547 func semasleep(ns int64) int32 { 548 const ( 549 _WAIT_ABANDONED = 0x00000080 550 _WAIT_OBJECT_0 = 0x00000000 551 _WAIT_TIMEOUT = 0x00000102 552 _WAIT_FAILED = 0xFFFFFFFF 553 ) 554 555 // store ms in ns to save stack space 556 if ns < 0 { 557 ns = _INFINITE 558 } else { 559 ns = int64(timediv(ns, 1000000, nil)) 560 if ns == 0 { 561 ns = 1 562 } 563 } 564 565 result := stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) 566 switch result { 567 case _WAIT_OBJECT_0: //signaled 568 return 0 569 570 case _WAIT_TIMEOUT: 571 return -1 572 573 case _WAIT_ABANDONED: 574 systemstack(func() { 575 throw("runtime.semasleep wait_abandoned") 576 }) 577 578 case _WAIT_FAILED: 579 systemstack(func() { 580 print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n") 581 throw("runtime.semasleep wait_failed") 582 }) 583 584 default: 585 systemstack(func() { 586 print("runtime: waitforsingleobject unexpected; result=", result, "\n") 587 throw("runtime.semasleep unexpected") 588 }) 589 } 590 591 return -1 // unreachable 592 } 593 594 //go:nosplit 595 func semawakeup(mp *m) { 596 if stdcall1(_SetEvent, mp.waitsema) == 0 { 597 systemstack(func() { 598 print("runtime: setevent failed; errno=", getlasterror(), "\n") 599 throw("runtime.semawakeup") 600 }) 601 } 602 } 603 604 //go:nosplit 605 func semacreate(mp *m) { 606 if mp.waitsema != 0 { 607 return 608 } 609 mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0) 610 if mp.waitsema == 0 { 611 systemstack(func() { 612 print("runtime: createevent failed; errno=", getlasterror(), "\n") 613 throw("runtime.semacreate") 614 }) 615 } 616 } 617 618 // May run with m.p==nil, so write barriers are not allowed. This 619 // function is called by newosproc0, so it is also required to 620 // operate without stack guards. 621 //go:nowritebarrierrec 622 //go:nosplit 623 func newosproc(mp *m, stk unsafe.Pointer) { 624 const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 625 // stackSize must match SizeOfStackReserve in cmd/link/internal/ld/pe.go. 626 const stackSize = 0x00200000*_64bit + 0x00100000*(1-_64bit) 627 thandle := stdcall6(_CreateThread, 0, stackSize, 628 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), 629 _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) 630 631 if thandle == 0 { 632 if atomic.Load(&exiting) != 0 { 633 // CreateThread may fail if called 634 // concurrently with ExitProcess. If this 635 // happens, just freeze this thread and let 636 // the process exit. See issue #18253. 637 lock(&deadlock) 638 lock(&deadlock) 639 } 640 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n") 641 throw("runtime.newosproc") 642 } 643 644 // Close thandle to avoid leaking the thread object if it exits. 645 stdcall1(_CloseHandle, thandle) 646 } 647 648 // Used by the C library build mode. On Linux this function would allocate a 649 // stack, but that's not necessary for Windows. No stack guards are present 650 // and the GC has not been initialized, so write barriers will fail. 651 //go:nowritebarrierrec 652 //go:nosplit 653 func newosproc0(mp *m, stk unsafe.Pointer) { 654 newosproc(mp, stk) 655 } 656 657 func exitThread(wait *uint32) { 658 // We should never reach exitThread on Windows because we let 659 // the OS clean up threads. 660 throw("exitThread") 661 } 662 663 // Called to initialize a new m (including the bootstrap m). 664 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 665 func mpreinit(mp *m) { 666 } 667 668 //go:nosplit 669 func msigsave(mp *m) { 670 } 671 672 //go:nosplit 673 func msigrestore(sigmask sigset) { 674 } 675 676 //go:nosplit 677 //go:nowritebarrierrec 678 func clearSignalHandlers() { 679 } 680 681 //go:nosplit 682 func sigblock() { 683 } 684 685 // Called to initialize a new m (including the bootstrap m). 686 // Called on the new thread, cannot allocate memory. 687 func minit() { 688 var thandle uintptr 689 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) 690 atomic.Storeuintptr(&getg().m.thread, thandle) 691 } 692 693 // Called from dropm to undo the effect of an minit. 694 //go:nosplit 695 func unminit() { 696 tp := &getg().m.thread 697 stdcall1(_CloseHandle, *tp) 698 *tp = 0 699 } 700 701 // Calling stdcall on os stack. 702 // May run during STW, so write barriers are not allowed. 703 //go:nowritebarrier 704 //go:nosplit 705 func stdcall(fn stdFunction) uintptr { 706 gp := getg() 707 mp := gp.m 708 mp.libcall.fn = uintptr(unsafe.Pointer(fn)) 709 710 if mp.profilehz != 0 { 711 // leave pc/sp for cpu profiler 712 mp.libcallg.set(gp) 713 mp.libcallpc = getcallerpc() 714 // sp must be the last, because once async cpu profiler finds 715 // all three values to be non-zero, it will use them 716 mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) 717 } 718 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall)) 719 mp.libcallsp = 0 720 return mp.libcall.r1 721 } 722 723 //go:nosplit 724 func stdcall0(fn stdFunction) uintptr { 725 mp := getg().m 726 mp.libcall.n = 0 727 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes 728 return stdcall(fn) 729 } 730 731 //go:nosplit 732 func stdcall1(fn stdFunction, a0 uintptr) uintptr { 733 mp := getg().m 734 mp.libcall.n = 1 735 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 736 return stdcall(fn) 737 } 738 739 //go:nosplit 740 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { 741 mp := getg().m 742 mp.libcall.n = 2 743 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 744 return stdcall(fn) 745 } 746 747 //go:nosplit 748 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { 749 mp := getg().m 750 mp.libcall.n = 3 751 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 752 return stdcall(fn) 753 } 754 755 //go:nosplit 756 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { 757 mp := getg().m 758 mp.libcall.n = 4 759 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 760 return stdcall(fn) 761 } 762 763 //go:nosplit 764 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { 765 mp := getg().m 766 mp.libcall.n = 5 767 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 768 return stdcall(fn) 769 } 770 771 //go:nosplit 772 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { 773 mp := getg().m 774 mp.libcall.n = 6 775 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 776 return stdcall(fn) 777 } 778 779 //go:nosplit 780 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { 781 mp := getg().m 782 mp.libcall.n = 7 783 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 784 return stdcall(fn) 785 } 786 787 // in sys_windows_386.s and sys_windows_amd64.s 788 func onosstack(fn unsafe.Pointer, arg uint32) 789 func usleep2(usec uint32) 790 func switchtothread() 791 792 var usleep2Addr unsafe.Pointer 793 var switchtothreadAddr unsafe.Pointer 794 795 //go:nosplit 796 func osyield() { 797 onosstack(switchtothreadAddr, 0) 798 } 799 800 //go:nosplit 801 func usleep(us uint32) { 802 // Have 1us units; want 100ns units. 803 onosstack(usleep2Addr, 10*us) 804 } 805 806 func ctrlhandler1(_type uint32) uint32 { 807 var s uint32 808 809 switch _type { 810 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: 811 s = _SIGINT 812 default: 813 return 0 814 } 815 816 if sigsend(s) { 817 return 1 818 } 819 exit(2) // SIGINT, SIGTERM, etc 820 return 0 821 } 822 823 // in sys_windows_386.s and sys_windows_amd64.s 824 func profileloop() 825 826 var profiletimer uintptr 827 828 func profilem(mp *m) { 829 var r *context 830 rbuf := make([]byte, unsafe.Sizeof(*r)+15) 831 832 tls := &mp.tls[0] 833 gp := *((**g)(unsafe.Pointer(tls))) 834 835 // align Context to 16 bytes 836 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) 837 r.contextflags = _CONTEXT_CONTROL 838 stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) 839 sigprof(r.ip(), r.sp(), 0, gp, mp) 840 } 841 842 func profileloop1(param uintptr) uint32 { 843 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) 844 845 for { 846 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) 847 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm))) 848 for mp := first; mp != nil; mp = mp.alllink { 849 thread := atomic.Loaduintptr(&mp.thread) 850 // Do not profile threads blocked on Notes, 851 // this includes idle worker threads, 852 // idle timer thread, idle heap scavenger, etc. 853 if thread == 0 || mp.profilehz == 0 || mp.blocked { 854 continue 855 } 856 stdcall1(_SuspendThread, thread) 857 if mp.profilehz != 0 && !mp.blocked { 858 profilem(mp) 859 } 860 stdcall1(_ResumeThread, thread) 861 } 862 } 863 } 864 865 func setProcessCPUProfiler(hz int32) { 866 if profiletimer == 0 { 867 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) 868 atomic.Storeuintptr(&profiletimer, timer) 869 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) 870 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) 871 stdcall1(_CloseHandle, thread) 872 } 873 } 874 875 func setThreadCPUProfiler(hz int32) { 876 ms := int32(0) 877 due := ^int64(^uint64(1 << 63)) 878 if hz > 0 { 879 ms = 1000 / hz 880 if ms == 0 { 881 ms = 1 882 } 883 due = int64(ms) * -10000 884 } 885 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) 886 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) 887 } 888 889 func memlimit() uintptr { 890 return 0 891 }