github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/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._CryptAcquireContextW CryptAcquireContextW%5 "advapi32.dll" 24 //go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom%3 "advapi32.dll" 25 //go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext%2 "advapi32.dll" 26 //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll" 27 //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll" 28 //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll" 29 //go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll" 30 //go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll" 31 //go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll" 32 //go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll" 33 //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll" 34 //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "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._LoadLibraryW LoadLibraryW%1 "kernel32.dll" 38 //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" 39 //go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject%3 "ntdll.dll" 40 //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" 41 //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll" 42 //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll" 43 //go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll" 44 //go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll" 45 //go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll" 46 //go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll" 47 //go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll" 48 //go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll" 49 //go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll" 50 //go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll" 51 //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll" 52 //go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll" 53 //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll" 54 //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll" 55 //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll" 56 //go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll" 57 58 type stdFunction unsafe.Pointer 59 60 var ( 61 // Following syscalls are available on every Windows PC. 62 // All these variables are set by the Windows executable 63 // loader before the Go program starts. 64 _AddVectoredExceptionHandler, 65 _CloseHandle, 66 _CreateEventA, 67 _CreateIoCompletionPort, 68 _CreateThread, 69 _CreateWaitableTimerA, 70 _CryptAcquireContextW, 71 _CryptGenRandom, 72 _CryptReleaseContext, 73 _DuplicateHandle, 74 _ExitProcess, 75 _FreeEnvironmentStringsW, 76 _GetConsoleMode, 77 _GetEnvironmentStringsW, 78 _GetProcAddress, 79 _GetProcessAffinityMask, 80 _GetQueuedCompletionStatus, 81 _GetStdHandle, 82 _GetSystemInfo, 83 _GetThreadContext, 84 _LoadLibraryW, 85 _LoadLibraryA, 86 _NtWaitForSingleObject, 87 _ResumeThread, 88 _SetConsoleCtrlHandler, 89 _SetErrorMode, 90 _SetEvent, 91 _SetProcessPriorityBoost, 92 _SetThreadPriority, 93 _SetUnhandledExceptionFilter, 94 _SetWaitableTimer, 95 _SuspendThread, 96 _SwitchToThread, 97 _VirtualAlloc, 98 _VirtualFree, 99 _WSAGetOverlappedResult, 100 _WaitForSingleObject, 101 _WriteConsoleW, 102 _WriteFile, 103 _timeBeginPeriod, 104 _ stdFunction 105 106 // Following syscalls are only available on some Windows PCs. 107 // We will load syscalls, if available, before using them. 108 _AddDllDirectory, 109 _AddVectoredContinueHandler, 110 _GetQueuedCompletionStatusEx, 111 _LoadLibraryExW, 112 _ stdFunction 113 ) 114 115 // Function to be called by windows CreateThread 116 // to start new os thread. 117 func tstart_stdcall(newm *m) uint32 118 119 func ctrlhandler(_type uint32) uint32 120 121 type mOS struct { 122 waitsema uintptr // semaphore for parking on locks 123 } 124 125 //go:linkname os_sigpipe os.sigpipe 126 func os_sigpipe() { 127 throw("too many writes on closed pipe") 128 } 129 130 // Stubs so tests can link correctly. These should never be called. 131 func open(name *byte, mode, perm int32) int32 { 132 throw("unimplemented") 133 return -1 134 } 135 func closefd(fd int32) int32 { 136 throw("unimplemented") 137 return -1 138 } 139 func read(fd int32, p unsafe.Pointer, n int32) int32 { 140 throw("unimplemented") 141 return -1 142 } 143 144 type sigset struct{} 145 146 // Call a Windows function with stdcall conventions, 147 // and switch to os stack during the call. 148 func asmstdcall(fn unsafe.Pointer) 149 150 var asmstdcallAddr unsafe.Pointer 151 152 func windowsFindfunc(lib uintptr, name []byte) stdFunction { 153 if name[len(name)-1] != 0 { 154 throw("usage") 155 } 156 f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0]))) 157 return stdFunction(unsafe.Pointer(f)) 158 } 159 160 func loadOptionalSyscalls() { 161 var kernel32dll = []byte("kernel32.dll\000") 162 k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) 163 if k32 == 0 { 164 throw("kernel32.dll not found") 165 } 166 _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000")) 167 _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000")) 168 _GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000")) 169 _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000")) 170 } 171 172 //go:nosplit 173 func getLoadLibrary() uintptr { 174 return uintptr(unsafe.Pointer(_LoadLibraryW)) 175 } 176 177 //go:nosplit 178 func getLoadLibraryEx() uintptr { 179 return uintptr(unsafe.Pointer(_LoadLibraryExW)) 180 } 181 182 //go:nosplit 183 func getGetProcAddress() uintptr { 184 return uintptr(unsafe.Pointer(_GetProcAddress)) 185 } 186 187 func getproccount() int32 { 188 var mask, sysmask uintptr 189 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) 190 if ret != 0 { 191 n := 0 192 maskbits := int(unsafe.Sizeof(mask) * 8) 193 for i := 0; i < maskbits; i++ { 194 if mask&(1<<uint(i)) != 0 { 195 n++ 196 } 197 } 198 if n != 0 { 199 return int32(n) 200 } 201 } 202 // use GetSystemInfo if GetProcessAffinityMask fails 203 var info systeminfo 204 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 205 return int32(info.dwnumberofprocessors) 206 } 207 208 func getPageSize() uintptr { 209 var info systeminfo 210 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 211 return uintptr(info.dwpagesize) 212 } 213 214 const ( 215 currentProcess = ^uintptr(0) // -1 = current process 216 currentThread = ^uintptr(1) // -2 = current thread 217 ) 218 219 // in sys_windows_386.s and sys_windows_amd64.s: 220 func externalthreadhandler() 221 func getlasterror() uint32 222 func setlasterror(err uint32) 223 224 // When loading DLLs, we prefer to use LoadLibraryEx with 225 // LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not 226 // available on old Windows, though, and the LOAD_LIBRARY_SEARCH_* 227 // flags are not available on some versions of Windows without a 228 // security patch. 229 // 230 // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says: 231 // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows 232 // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on 233 // systems that have KB2533623 installed. To determine whether the 234 // flags are available, use GetProcAddress to get the address of the 235 // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories 236 // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_* 237 // flags can be used with LoadLibraryEx." 238 var useLoadLibraryEx bool 239 240 var timeBeginPeriodRetValue uint32 241 242 func osinit() { 243 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) 244 usleep2Addr = unsafe.Pointer(funcPC(usleep2)) 245 switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread)) 246 247 setBadSignalMsg() 248 249 loadOptionalSyscalls() 250 251 useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil) 252 253 disableWER() 254 255 externalthreadhandlerp = funcPC(externalthreadhandler) 256 257 initExceptionHandler() 258 259 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) 260 261 timeBeginPeriodRetValue = uint32(stdcall1(_timeBeginPeriod, 1)) 262 263 ncpu = getproccount() 264 265 physPageSize = getPageSize() 266 267 // Windows dynamic priority boosting assumes that a process has different types 268 // of dedicated threads -- GUI, IO, computational, etc. Go processes use 269 // equivalent threads that all do a mix of GUI, IO, computations, etc. 270 // In such context dynamic priority boosting does nothing but harm, so we turn it off. 271 stdcall2(_SetProcessPriorityBoost, currentProcess, 1) 272 } 273 274 //go:nosplit 275 func getRandomData(r []byte) { 276 const ( 277 prov_rsa_full = 1 278 crypt_verifycontext = 0xF0000000 279 ) 280 var handle uintptr 281 n := 0 282 if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 { 283 if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 { 284 n = len(r) 285 } 286 stdcall2(_CryptReleaseContext, handle, 0) 287 } 288 extendRandom(r, n) 289 } 290 291 func goenvs() { 292 // strings is a pointer to environment variable pairs in the form: 293 // "envA=valA\x00envB=valB\x00\x00" (in UTF-16) 294 // Two consecutive zero bytes end the list. 295 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)) 296 p := (*[1 << 24]uint16)(strings)[:] 297 298 n := 0 299 for from, i := 0, 0; true; i++ { 300 if p[i] == 0 { 301 // empty string marks the end 302 if i == from { 303 break 304 } 305 from = i + 1 306 n++ 307 } 308 } 309 envs = make([]string, n) 310 311 for i := range envs { 312 envs[i] = gostringw(&p[0]) 313 for p[0] != 0 { 314 p = p[1:] 315 } 316 p = p[1:] // skip nil byte 317 } 318 319 stdcall1(_FreeEnvironmentStringsW, uintptr(strings)) 320 } 321 322 //go:nosplit 323 func exit(code int32) { 324 stdcall1(_ExitProcess, uintptr(code)) 325 } 326 327 //go:nosplit 328 func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { 329 const ( 330 _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 331 _STD_ERROR_HANDLE = ^uintptr(11) // -12 332 ) 333 var handle uintptr 334 switch fd { 335 case 1: 336 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) 337 case 2: 338 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) 339 default: 340 // assume fd is real windows handle. 341 handle = fd 342 } 343 isASCII := true 344 b := (*[1 << 30]byte)(buf)[:n] 345 for _, x := range b { 346 if x >= 0x80 { 347 isASCII = false 348 break 349 } 350 } 351 352 if !isASCII { 353 var m uint32 354 isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0 355 // If this is a console output, various non-unicode code pages can be in use. 356 // Use the dedicated WriteConsole call to ensure unicode is printed correctly. 357 if isConsole { 358 return int32(writeConsole(handle, buf, n)) 359 } 360 } 361 var written uint32 362 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) 363 return int32(written) 364 } 365 366 var ( 367 utf16ConsoleBack [1000]uint16 368 utf16ConsoleBackLock mutex 369 ) 370 371 // writeConsole writes bufLen bytes from buf to the console File. 372 // It returns the number of bytes written. 373 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int { 374 const surr2 = (surrogateMin + surrogateMax + 1) / 2 375 376 // Do not use defer for unlock. May cause issues when printing a panic. 377 lock(&utf16ConsoleBackLock) 378 379 b := (*[1 << 30]byte)(buf)[:bufLen] 380 s := *(*string)(unsafe.Pointer(&b)) 381 382 utf16tmp := utf16ConsoleBack[:] 383 384 total := len(s) 385 w := 0 386 for len(s) > 0 { 387 if w >= len(utf16tmp)-2 { 388 writeConsoleUTF16(handle, utf16tmp[:w]) 389 w = 0 390 } 391 r, n := charntorune(s) 392 s = s[n:] 393 if r < 0x10000 { 394 utf16tmp[w] = uint16(r) 395 w++ 396 } else { 397 r -= 0x10000 398 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff 399 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff 400 w += 2 401 } 402 } 403 writeConsoleUTF16(handle, utf16tmp[:w]) 404 unlock(&utf16ConsoleBackLock) 405 return total 406 } 407 408 // writeConsoleUTF16 is the dedicated windows calls that correctly prints 409 // to the console regardless of the current code page. Input is utf-16 code points. 410 // The handle must be a console handle. 411 func writeConsoleUTF16(handle uintptr, b []uint16) { 412 l := uint32(len(b)) 413 if l == 0 { 414 return 415 } 416 var written uint32 417 stdcall5(_WriteConsoleW, 418 handle, 419 uintptr(unsafe.Pointer(&b[0])), 420 uintptr(l), 421 uintptr(unsafe.Pointer(&written)), 422 0, 423 ) 424 return 425 } 426 427 //go:nosplit 428 func semasleep(ns int64) int32 { 429 // store ms in ns to save stack space 430 if ns < 0 { 431 ns = _INFINITE 432 } else { 433 ns = int64(timediv(ns, 1000000, nil)) 434 if ns == 0 { 435 ns = 1 436 } 437 } 438 if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 { 439 return -1 // timeout 440 } 441 return 0 442 } 443 444 //go:nosplit 445 func semawakeup(mp *m) { 446 stdcall1(_SetEvent, mp.waitsema) 447 } 448 449 //go:nosplit 450 func semacreate(mp *m) { 451 if mp.waitsema != 0 { 452 return 453 } 454 mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0) 455 } 456 457 // May run with m.p==nil, so write barriers are not allowed. This 458 // function is called by newosproc0, so it is also required to 459 // operate without stack guards. 460 //go:nowritebarrierc 461 //go:nosplit 462 func newosproc(mp *m, stk unsafe.Pointer) { 463 const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 464 thandle := stdcall6(_CreateThread, 0, 0x20000, 465 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), 466 _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) 467 if thandle == 0 { 468 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n") 469 throw("runtime.newosproc") 470 } 471 } 472 473 // Used by the C library build mode. On Linux this function would allocate a 474 // stack, but that's not necessary for Windows. No stack guards are present 475 // and the GC has not been initialized, so write barriers will fail. 476 //go:nowritebarrierc 477 //go:nosplit 478 func newosproc0(mp *m, stk unsafe.Pointer) { 479 newosproc(mp, stk) 480 } 481 482 // Called to initialize a new m (including the bootstrap m). 483 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 484 func mpreinit(mp *m) { 485 } 486 487 //go:nosplit 488 func msigsave(mp *m) { 489 } 490 491 //go:nosplit 492 func msigrestore(sigmask sigset) { 493 } 494 495 //go:nosplit 496 func sigblock() { 497 } 498 499 // Called to initialize a new m (including the bootstrap m). 500 // Called on the new thread, cannot allocate memory. 501 func minit() { 502 var thandle uintptr 503 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) 504 atomic.Storeuintptr(&getg().m.thread, thandle) 505 } 506 507 // Called from dropm to undo the effect of an minit. 508 //go:nosplit 509 func unminit() { 510 tp := &getg().m.thread 511 stdcall1(_CloseHandle, *tp) 512 *tp = 0 513 } 514 515 // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ 516 type _KSYSTEM_TIME struct { 517 LowPart uint32 518 High1Time int32 519 High2Time int32 520 } 521 522 const ( 523 _INTERRUPT_TIME = 0x7ffe0008 524 _SYSTEM_TIME = 0x7ffe0014 525 ) 526 527 //go:nosplit 528 func systime(addr uintptr) int64 { 529 timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr)) 530 531 var t _KSYSTEM_TIME 532 for i := 1; i < 10000; i++ { 533 // these fields must be read in that order (see URL above) 534 t.High1Time = timeaddr.High1Time 535 t.LowPart = timeaddr.LowPart 536 t.High2Time = timeaddr.High2Time 537 if t.High1Time == t.High2Time { 538 return int64(t.High1Time)<<32 | int64(t.LowPart) 539 } 540 if (i % 100) == 0 { 541 osyield() 542 } 543 } 544 systemstack(func() { 545 throw("interrupt/system time is changing too fast") 546 }) 547 return 0 548 } 549 550 //go:nosplit 551 func unixnano() int64 { 552 return (systime(_SYSTEM_TIME) - 116444736000000000) * 100 553 } 554 555 //go:nosplit 556 func nanotime() int64 { 557 return systime(_INTERRUPT_TIME) * 100 558 } 559 560 // Calling stdcall on os stack. 561 // May run during STW, so write barriers are not allowed. 562 //go:nowritebarrier 563 //go:nosplit 564 func stdcall(fn stdFunction) uintptr { 565 gp := getg() 566 mp := gp.m 567 mp.libcall.fn = uintptr(unsafe.Pointer(fn)) 568 569 if mp.profilehz != 0 { 570 // leave pc/sp for cpu profiler 571 mp.libcallg.set(gp) 572 mp.libcallpc = getcallerpc(unsafe.Pointer(&fn)) 573 // sp must be the last, because once async cpu profiler finds 574 // all three values to be non-zero, it will use them 575 mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) 576 } 577 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall)) 578 mp.libcallsp = 0 579 return mp.libcall.r1 580 } 581 582 //go:nosplit 583 func stdcall0(fn stdFunction) uintptr { 584 mp := getg().m 585 mp.libcall.n = 0 586 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes 587 return stdcall(fn) 588 } 589 590 //go:nosplit 591 func stdcall1(fn stdFunction, a0 uintptr) uintptr { 592 mp := getg().m 593 mp.libcall.n = 1 594 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 595 return stdcall(fn) 596 } 597 598 //go:nosplit 599 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { 600 mp := getg().m 601 mp.libcall.n = 2 602 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 603 return stdcall(fn) 604 } 605 606 //go:nosplit 607 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { 608 mp := getg().m 609 mp.libcall.n = 3 610 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 611 return stdcall(fn) 612 } 613 614 //go:nosplit 615 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { 616 mp := getg().m 617 mp.libcall.n = 4 618 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 619 return stdcall(fn) 620 } 621 622 //go:nosplit 623 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { 624 mp := getg().m 625 mp.libcall.n = 5 626 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 627 return stdcall(fn) 628 } 629 630 //go:nosplit 631 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { 632 mp := getg().m 633 mp.libcall.n = 6 634 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 635 return stdcall(fn) 636 } 637 638 //go:nosplit 639 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { 640 mp := getg().m 641 mp.libcall.n = 7 642 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 643 return stdcall(fn) 644 } 645 646 // in sys_windows_386.s and sys_windows_amd64.s 647 func onosstack(fn unsafe.Pointer, arg uint32) 648 func usleep2(usec uint32) 649 func switchtothread() 650 651 var usleep2Addr unsafe.Pointer 652 var switchtothreadAddr unsafe.Pointer 653 654 //go:nosplit 655 func osyield() { 656 onosstack(switchtothreadAddr, 0) 657 } 658 659 //go:nosplit 660 func usleep(us uint32) { 661 // Have 1us units; want 100ns units. 662 onosstack(usleep2Addr, 10*us) 663 } 664 665 func ctrlhandler1(_type uint32) uint32 { 666 var s uint32 667 668 switch _type { 669 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: 670 s = _SIGINT 671 default: 672 return 0 673 } 674 675 if sigsend(s) { 676 return 1 677 } 678 exit(2) // SIGINT, SIGTERM, etc 679 return 0 680 } 681 682 // in sys_windows_386.s and sys_windows_amd64.s 683 func profileloop() 684 685 var profiletimer uintptr 686 687 func profilem(mp *m) { 688 var r *context 689 rbuf := make([]byte, unsafe.Sizeof(*r)+15) 690 691 tls := &mp.tls[0] 692 gp := *((**g)(unsafe.Pointer(tls))) 693 694 // align Context to 16 bytes 695 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) 696 r.contextflags = _CONTEXT_CONTROL 697 stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) 698 sigprof(r.ip(), r.sp(), 0, gp, mp) 699 } 700 701 func profileloop1(param uintptr) uint32 { 702 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) 703 704 for { 705 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) 706 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm))) 707 for mp := first; mp != nil; mp = mp.alllink { 708 thread := atomic.Loaduintptr(&mp.thread) 709 // Do not profile threads blocked on Notes, 710 // this includes idle worker threads, 711 // idle timer thread, idle heap scavenger, etc. 712 if thread == 0 || mp.profilehz == 0 || mp.blocked { 713 continue 714 } 715 stdcall1(_SuspendThread, thread) 716 if mp.profilehz != 0 && !mp.blocked { 717 profilem(mp) 718 } 719 stdcall1(_ResumeThread, thread) 720 } 721 } 722 } 723 724 var cpuprofilerlock mutex 725 726 func resetcpuprofiler(hz int32) { 727 lock(&cpuprofilerlock) 728 if profiletimer == 0 { 729 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) 730 atomic.Storeuintptr(&profiletimer, timer) 731 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) 732 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) 733 stdcall1(_CloseHandle, thread) 734 } 735 unlock(&cpuprofilerlock) 736 737 ms := int32(0) 738 due := ^int64(^uint64(1 << 63)) 739 if hz > 0 { 740 ms = 1000 / hz 741 if ms == 0 { 742 ms = 1 743 } 744 due = int64(ms) * -10000 745 } 746 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) 747 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) 748 } 749 750 func memlimit() uintptr { 751 return 0 752 }