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