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 "unsafe" 9 ) 10 11 //go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll" 12 //go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll" 13 //go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll" 14 //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" 15 //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" 16 //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" 17 //go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW%5 "advapi32.dll" 18 //go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom%3 "advapi32.dll" 19 //go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext%2 "advapi32.dll" 20 //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll" 21 //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll" 22 //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll" 23 //go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll" 24 //go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll" 25 //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll" 26 //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll" 27 //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll" 28 //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll" 29 //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" 30 //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" 31 //go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject%3 "ntdll.dll" 32 //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" 33 //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll" 34 //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll" 35 //go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll" 36 //go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll" 37 //go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll" 38 //go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll" 39 //go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll" 40 //go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll" 41 //go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll" 42 //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll" 43 //go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll" 44 //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll" 45 //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll" 46 //go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll" 47 48 var ( 49 // Following syscalls are available on every Windows PC. 50 // All these variables are set by the Windows executable 51 // loader before the Go program starts. 52 _AddVectoredExceptionHandler, 53 _CloseHandle, 54 _CreateEventA, 55 _CreateIoCompletionPort, 56 _CreateThread, 57 _CreateWaitableTimerA, 58 _CryptAcquireContextW, 59 _CryptGenRandom, 60 _CryptReleaseContext, 61 _DuplicateHandle, 62 _ExitProcess, 63 _FreeEnvironmentStringsW, 64 _GetEnvironmentStringsW, 65 _GetProcAddress, 66 _GetQueuedCompletionStatus, 67 _GetStdHandle, 68 _GetSystemInfo, 69 _GetThreadContext, 70 _LoadLibraryW, 71 _LoadLibraryA, 72 _NtWaitForSingleObject, 73 _ResumeThread, 74 _SetConsoleCtrlHandler, 75 _SetErrorMode, 76 _SetEvent, 77 _SetProcessPriorityBoost, 78 _SetThreadPriority, 79 _SetUnhandledExceptionFilter, 80 _SetWaitableTimer, 81 _SuspendThread, 82 _VirtualAlloc, 83 _VirtualFree, 84 _WSAGetOverlappedResult, 85 _WaitForSingleObject, 86 _WriteFile, 87 _timeBeginPeriod stdFunction 88 89 // Following syscalls are only available on some Windows PCs. 90 // We will load syscalls, if available, before using them. 91 _AddVectoredContinueHandler, 92 _GetQueuedCompletionStatusEx stdFunction 93 ) 94 95 // Call a Windows function with stdcall conventions, 96 // and switch to os stack during the call. 97 func asmstdcall(fn unsafe.Pointer) 98 99 var asmstdcallAddr unsafe.Pointer 100 101 func loadOptionalSyscalls() { 102 var buf [50]byte // large enough for longest string 103 strtoptr := func(s string) uintptr { 104 buf[copy(buf[:], s)] = 0 // nil-terminated for OS 105 return uintptr(noescape(unsafe.Pointer(&buf[0]))) 106 } 107 l := stdcall1(_LoadLibraryA, strtoptr("kernel32.dll")) 108 findfunc := func(name string) stdFunction { 109 f := stdcall2(_GetProcAddress, l, strtoptr(name)) 110 return stdFunction(unsafe.Pointer(f)) 111 } 112 if l != 0 { 113 _AddVectoredContinueHandler = findfunc("AddVectoredContinueHandler") 114 _GetQueuedCompletionStatusEx = findfunc("GetQueuedCompletionStatusEx") 115 } 116 } 117 118 //go:nosplit 119 func getLoadLibrary() uintptr { 120 return uintptr(unsafe.Pointer(_LoadLibraryW)) 121 } 122 123 //go:nosplit 124 func getGetProcAddress() uintptr { 125 return uintptr(unsafe.Pointer(_GetProcAddress)) 126 } 127 128 func getproccount() int32 { 129 var info systeminfo 130 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 131 return int32(info.dwnumberofprocessors) 132 } 133 134 const ( 135 currentProcess = ^uintptr(0) // -1 = current process 136 currentThread = ^uintptr(1) // -2 = current thread 137 ) 138 139 // in sys_windows_386.s and sys_windows_amd64.s 140 func externalthreadhandler() 141 142 func osinit() { 143 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) 144 145 setBadSignalMsg() 146 147 loadOptionalSyscalls() 148 149 disableWER() 150 151 externalthreadhandlerp = funcPC(externalthreadhandler) 152 153 initExceptionHandler() 154 155 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) 156 157 stdcall1(_timeBeginPeriod, 1) 158 159 ncpu = getproccount() 160 161 // Windows dynamic priority boosting assumes that a process has different types 162 // of dedicated threads -- GUI, IO, computational, etc. Go processes use 163 // equivalent threads that all do a mix of GUI, IO, computations, etc. 164 // In such context dynamic priority boosting does nothing but harm, so we turn it off. 165 stdcall2(_SetProcessPriorityBoost, currentProcess, 1) 166 } 167 168 //go:nosplit 169 func getRandomData(r []byte) { 170 const ( 171 prov_rsa_full = 1 172 crypt_verifycontext = 0xF0000000 173 ) 174 var handle uintptr 175 n := 0 176 if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 { 177 if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 { 178 n = len(r) 179 } 180 stdcall2(_CryptReleaseContext, handle, 0) 181 } 182 extendRandom(r, n) 183 } 184 185 func goenvs() { 186 // strings is a pointer to environment variable pairs in the form: 187 // "envA=valA\x00envB=valB\x00\x00" (in UTF-16) 188 // Two consecutive zero bytes end the list. 189 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)) 190 p := (*[1 << 24]uint16)(strings)[:] 191 192 n := 0 193 for from, i := 0, 0; true; i++ { 194 if p[i] == 0 { 195 // empty string marks the end 196 if i == from { 197 break 198 } 199 from = i + 1 200 n++ 201 } 202 } 203 envs = make([]string, n) 204 205 for i := range envs { 206 envs[i] = gostringw(&p[0]) 207 for p[0] != 0 { 208 p = p[1:] 209 } 210 p = p[1:] // skip nil byte 211 } 212 213 stdcall1(_FreeEnvironmentStringsW, uintptr(strings)) 214 } 215 216 //go:nosplit 217 func exit(code int32) { 218 stdcall1(_ExitProcess, uintptr(code)) 219 } 220 221 //go:nosplit 222 func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { 223 const ( 224 _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 225 _STD_ERROR_HANDLE = ^uintptr(11) // -12 226 ) 227 var handle uintptr 228 switch fd { 229 case 1: 230 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) 231 case 2: 232 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) 233 default: 234 // assume fd is real windows handle. 235 handle = fd 236 } 237 var written uint32 238 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) 239 return int32(written) 240 } 241 242 //go:nosplit 243 func semasleep(ns int64) int32 { 244 // store ms in ns to save stack space 245 if ns < 0 { 246 ns = _INFINITE 247 } else { 248 ns = int64(timediv(ns, 1000000, nil)) 249 if ns == 0 { 250 ns = 1 251 } 252 } 253 if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 { 254 return -1 // timeout 255 } 256 return 0 257 } 258 259 //go:nosplit 260 func semawakeup(mp *m) { 261 stdcall1(_SetEvent, mp.waitsema) 262 } 263 264 //go:nosplit 265 func semacreate() uintptr { 266 return stdcall4(_CreateEventA, 0, 0, 0, 0) 267 } 268 269 // May run with m.p==nil, so write barriers are not allowed. 270 //go:nowritebarrier 271 func newosproc(mp *m, stk unsafe.Pointer) { 272 const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 273 thandle := stdcall6(_CreateThread, 0, 0x20000, 274 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), 275 _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) 276 if thandle == 0 { 277 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n") 278 throw("runtime.newosproc") 279 } 280 } 281 282 // Called to initialize a new m (including the bootstrap m). 283 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 284 func mpreinit(mp *m) { 285 } 286 287 func msigsave(mp *m) { 288 } 289 290 // Called to initialize a new m (including the bootstrap m). 291 // Called on the new thread, can not allocate memory. 292 func minit() { 293 var thandle uintptr 294 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) 295 atomicstoreuintptr(&getg().m.thread, thandle) 296 } 297 298 // Called from dropm to undo the effect of an minit. 299 func unminit() { 300 tp := &getg().m.thread 301 stdcall1(_CloseHandle, *tp) 302 *tp = 0 303 } 304 305 // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ 306 type _KSYSTEM_TIME struct { 307 LowPart uint32 308 High1Time int32 309 High2Time int32 310 } 311 312 const ( 313 _INTERRUPT_TIME = 0x7ffe0008 314 _SYSTEM_TIME = 0x7ffe0014 315 ) 316 317 //go:nosplit 318 func systime(addr uintptr) int64 { 319 timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr)) 320 321 var t _KSYSTEM_TIME 322 for i := 1; i < 10000; i++ { 323 // these fields must be read in that order (see URL above) 324 t.High1Time = timeaddr.High1Time 325 t.LowPart = timeaddr.LowPart 326 t.High2Time = timeaddr.High2Time 327 if t.High1Time == t.High2Time { 328 return int64(t.High1Time)<<32 | int64(t.LowPart) 329 } 330 if (i % 100) == 0 { 331 osyield() 332 } 333 } 334 systemstack(func() { 335 throw("interrupt/system time is changing too fast") 336 }) 337 return 0 338 } 339 340 //go:nosplit 341 func unixnano() int64 { 342 return (systime(_SYSTEM_TIME) - 116444736000000000) * 100 343 } 344 345 //go:nosplit 346 func nanotime() int64 { 347 return systime(_INTERRUPT_TIME) * 100 348 } 349 350 // Calling stdcall on os stack. 351 // May run during STW, so write barriers are not allowed. 352 //go:nowritebarrier 353 //go:nosplit 354 func stdcall(fn stdFunction) uintptr { 355 gp := getg() 356 mp := gp.m 357 mp.libcall.fn = uintptr(unsafe.Pointer(fn)) 358 359 if mp.profilehz != 0 { 360 // leave pc/sp for cpu profiler 361 mp.libcallg.set(gp) 362 mp.libcallpc = getcallerpc(unsafe.Pointer(&fn)) 363 // sp must be the last, because once async cpu profiler finds 364 // all three values to be non-zero, it will use them 365 mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) 366 } 367 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall)) 368 mp.libcallsp = 0 369 return mp.libcall.r1 370 } 371 372 //go:nosplit 373 func stdcall0(fn stdFunction) uintptr { 374 mp := getg().m 375 mp.libcall.n = 0 376 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes 377 return stdcall(fn) 378 } 379 380 //go:nosplit 381 func stdcall1(fn stdFunction, a0 uintptr) uintptr { 382 mp := getg().m 383 mp.libcall.n = 1 384 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 385 return stdcall(fn) 386 } 387 388 //go:nosplit 389 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { 390 mp := getg().m 391 mp.libcall.n = 2 392 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 393 return stdcall(fn) 394 } 395 396 //go:nosplit 397 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { 398 mp := getg().m 399 mp.libcall.n = 3 400 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 401 return stdcall(fn) 402 } 403 404 //go:nosplit 405 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { 406 mp := getg().m 407 mp.libcall.n = 4 408 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 409 return stdcall(fn) 410 } 411 412 //go:nosplit 413 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { 414 mp := getg().m 415 mp.libcall.n = 5 416 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 417 return stdcall(fn) 418 } 419 420 //go:nosplit 421 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { 422 mp := getg().m 423 mp.libcall.n = 6 424 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 425 return stdcall(fn) 426 } 427 428 //go:nosplit 429 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { 430 mp := getg().m 431 mp.libcall.n = 7 432 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 433 return stdcall(fn) 434 } 435 436 // in sys_windows_386.s and sys_windows_amd64.s 437 func usleep1(usec uint32) 438 439 //go:nosplit 440 func osyield() { 441 usleep1(1) 442 } 443 444 //go:nosplit 445 func usleep(us uint32) { 446 // Have 1us units; want 100ns units. 447 usleep1(10 * us) 448 } 449 450 func ctrlhandler1(_type uint32) uint32 { 451 var s uint32 452 453 switch _type { 454 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: 455 s = _SIGINT 456 default: 457 return 0 458 } 459 460 if sigsend(s) { 461 return 1 462 } 463 exit(2) // SIGINT, SIGTERM, etc 464 return 0 465 } 466 467 // in sys_windows_386.s and sys_windows_amd64.s 468 func profileloop() 469 470 var profiletimer uintptr 471 472 func profilem(mp *m) { 473 var r *context 474 rbuf := make([]byte, unsafe.Sizeof(*r)+15) 475 476 tls := &mp.tls[0] 477 if mp == &m0 { 478 tls = &tls0[0] 479 } 480 gp := *((**g)(unsafe.Pointer(tls))) 481 482 // align Context to 16 bytes 483 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) 484 r.contextflags = _CONTEXT_CONTROL 485 stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) 486 sigprof(r.ip(), r.sp(), 0, gp, mp) 487 } 488 489 func profileloop1(param uintptr) uint32 { 490 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) 491 492 for { 493 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) 494 first := (*m)(atomicloadp(unsafe.Pointer(&allm))) 495 for mp := first; mp != nil; mp = mp.alllink { 496 thread := atomicloaduintptr(&mp.thread) 497 // Do not profile threads blocked on Notes, 498 // this includes idle worker threads, 499 // idle timer thread, idle heap scavenger, etc. 500 if thread == 0 || mp.profilehz == 0 || mp.blocked { 501 continue 502 } 503 stdcall1(_SuspendThread, thread) 504 if mp.profilehz != 0 && !mp.blocked { 505 profilem(mp) 506 } 507 stdcall1(_ResumeThread, thread) 508 } 509 } 510 } 511 512 var cpuprofilerlock mutex 513 514 func resetcpuprofiler(hz int32) { 515 lock(&cpuprofilerlock) 516 if profiletimer == 0 { 517 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) 518 atomicstoreuintptr(&profiletimer, timer) 519 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) 520 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) 521 stdcall1(_CloseHandle, thread) 522 } 523 unlock(&cpuprofilerlock) 524 525 ms := int32(0) 526 due := ^int64(^uint64(1 << 63)) 527 if hz > 0 { 528 ms = 1000 / hz 529 if ms == 0 { 530 ms = 1 531 } 532 due = int64(ms) * -10000 533 } 534 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) 535 atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) 536 } 537 538 func memlimit() uintptr { 539 return 0 540 } 541