github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll" 26 //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll" 27 //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll" 28 //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll" 29 //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "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 _GetProcessAffinityMask, 68 _GetQueuedCompletionStatus, 69 _GetStdHandle, 70 _GetSystemInfo, 71 _GetThreadContext, 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 mask, sysmask uintptr 132 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) 133 if ret != 0 { 134 n := 0 135 maskbits := int(unsafe.Sizeof(mask) * 8) 136 for i := 0; i < maskbits; i++ { 137 if mask&(1<<uint(i)) != 0 { 138 n++ 139 } 140 } 141 if n != 0 { 142 return int32(n) 143 } 144 } 145 // use GetSystemInfo if GetProcessAffinityMask fails 146 var info systeminfo 147 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) 148 return int32(info.dwnumberofprocessors) 149 } 150 151 const ( 152 currentProcess = ^uintptr(0) // -1 = current process 153 currentThread = ^uintptr(1) // -2 = current thread 154 ) 155 156 // in sys_windows_386.s and sys_windows_amd64.s 157 func externalthreadhandler() 158 159 var timeBeginPeriodRetValue uint32 160 161 func osinit() { 162 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) 163 164 setBadSignalMsg() 165 166 loadOptionalSyscalls() 167 168 disableWER() 169 170 externalthreadhandlerp = funcPC(externalthreadhandler) 171 172 initExceptionHandler() 173 174 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) 175 176 timeBeginPeriodRetValue = uint32(stdcall1(_timeBeginPeriod, 1)) 177 178 ncpu = getproccount() 179 180 // Windows dynamic priority boosting assumes that a process has different types 181 // of dedicated threads -- GUI, IO, computational, etc. Go processes use 182 // equivalent threads that all do a mix of GUI, IO, computations, etc. 183 // In such context dynamic priority boosting does nothing but harm, so we turn it off. 184 stdcall2(_SetProcessPriorityBoost, currentProcess, 1) 185 } 186 187 //go:nosplit 188 func getRandomData(r []byte) { 189 const ( 190 prov_rsa_full = 1 191 crypt_verifycontext = 0xF0000000 192 ) 193 var handle uintptr 194 n := 0 195 if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 { 196 if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 { 197 n = len(r) 198 } 199 stdcall2(_CryptReleaseContext, handle, 0) 200 } 201 extendRandom(r, n) 202 } 203 204 func goenvs() { 205 // strings is a pointer to environment variable pairs in the form: 206 // "envA=valA\x00envB=valB\x00\x00" (in UTF-16) 207 // Two consecutive zero bytes end the list. 208 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)) 209 p := (*[1 << 24]uint16)(strings)[:] 210 211 n := 0 212 for from, i := 0, 0; true; i++ { 213 if p[i] == 0 { 214 // empty string marks the end 215 if i == from { 216 break 217 } 218 from = i + 1 219 n++ 220 } 221 } 222 envs = make([]string, n) 223 224 for i := range envs { 225 envs[i] = gostringw(&p[0]) 226 for p[0] != 0 { 227 p = p[1:] 228 } 229 p = p[1:] // skip nil byte 230 } 231 232 stdcall1(_FreeEnvironmentStringsW, uintptr(strings)) 233 } 234 235 //go:nosplit 236 func exit(code int32) { 237 stdcall1(_ExitProcess, uintptr(code)) 238 } 239 240 //go:nosplit 241 func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { 242 const ( 243 _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 244 _STD_ERROR_HANDLE = ^uintptr(11) // -12 245 ) 246 var handle uintptr 247 switch fd { 248 case 1: 249 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) 250 case 2: 251 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) 252 default: 253 // assume fd is real windows handle. 254 handle = fd 255 } 256 var written uint32 257 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) 258 return int32(written) 259 } 260 261 //go:nosplit 262 func semasleep(ns int64) int32 { 263 // store ms in ns to save stack space 264 if ns < 0 { 265 ns = _INFINITE 266 } else { 267 ns = int64(timediv(ns, 1000000, nil)) 268 if ns == 0 { 269 ns = 1 270 } 271 } 272 if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 { 273 return -1 // timeout 274 } 275 return 0 276 } 277 278 //go:nosplit 279 func semawakeup(mp *m) { 280 stdcall1(_SetEvent, mp.waitsema) 281 } 282 283 //go:nosplit 284 func semacreate() uintptr { 285 return stdcall4(_CreateEventA, 0, 0, 0, 0) 286 } 287 288 // May run with m.p==nil, so write barriers are not allowed. 289 //go:nowritebarrier 290 func newosproc(mp *m, stk unsafe.Pointer) { 291 const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 292 thandle := stdcall6(_CreateThread, 0, 0x20000, 293 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), 294 _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) 295 if thandle == 0 { 296 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n") 297 throw("runtime.newosproc") 298 } 299 } 300 301 // Called to initialize a new m (including the bootstrap m). 302 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 303 func mpreinit(mp *m) { 304 } 305 306 func msigsave(mp *m) { 307 } 308 309 // Called to initialize a new m (including the bootstrap m). 310 // Called on the new thread, can not allocate memory. 311 func minit() { 312 var thandle uintptr 313 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) 314 atomicstoreuintptr(&getg().m.thread, thandle) 315 } 316 317 // Called from dropm to undo the effect of an minit. 318 func unminit() { 319 tp := &getg().m.thread 320 stdcall1(_CloseHandle, *tp) 321 *tp = 0 322 } 323 324 // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ 325 type _KSYSTEM_TIME struct { 326 LowPart uint32 327 High1Time int32 328 High2Time int32 329 } 330 331 const ( 332 _INTERRUPT_TIME = 0x7ffe0008 333 _SYSTEM_TIME = 0x7ffe0014 334 ) 335 336 //go:nosplit 337 func systime(addr uintptr) int64 { 338 timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr)) 339 340 var t _KSYSTEM_TIME 341 for i := 1; i < 10000; i++ { 342 // these fields must be read in that order (see URL above) 343 t.High1Time = timeaddr.High1Time 344 t.LowPart = timeaddr.LowPart 345 t.High2Time = timeaddr.High2Time 346 if t.High1Time == t.High2Time { 347 return int64(t.High1Time)<<32 | int64(t.LowPart) 348 } 349 if (i % 100) == 0 { 350 osyield() 351 } 352 } 353 systemstack(func() { 354 throw("interrupt/system time is changing too fast") 355 }) 356 return 0 357 } 358 359 //go:nosplit 360 func unixnano() int64 { 361 return (systime(_SYSTEM_TIME) - 116444736000000000) * 100 362 } 363 364 //go:nosplit 365 func nanotime() int64 { 366 return systime(_INTERRUPT_TIME) * 100 367 } 368 369 // Calling stdcall on os stack. 370 // May run during STW, so write barriers are not allowed. 371 //go:nowritebarrier 372 //go:nosplit 373 func stdcall(fn stdFunction) uintptr { 374 gp := getg() 375 mp := gp.m 376 mp.libcall.fn = uintptr(unsafe.Pointer(fn)) 377 378 if mp.profilehz != 0 { 379 // leave pc/sp for cpu profiler 380 mp.libcallg.set(gp) 381 mp.libcallpc = getcallerpc(unsafe.Pointer(&fn)) 382 // sp must be the last, because once async cpu profiler finds 383 // all three values to be non-zero, it will use them 384 mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) 385 } 386 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall)) 387 mp.libcallsp = 0 388 return mp.libcall.r1 389 } 390 391 //go:nosplit 392 func stdcall0(fn stdFunction) uintptr { 393 mp := getg().m 394 mp.libcall.n = 0 395 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes 396 return stdcall(fn) 397 } 398 399 //go:nosplit 400 func stdcall1(fn stdFunction, a0 uintptr) uintptr { 401 mp := getg().m 402 mp.libcall.n = 1 403 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 404 return stdcall(fn) 405 } 406 407 //go:nosplit 408 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { 409 mp := getg().m 410 mp.libcall.n = 2 411 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 412 return stdcall(fn) 413 } 414 415 //go:nosplit 416 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { 417 mp := getg().m 418 mp.libcall.n = 3 419 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 420 return stdcall(fn) 421 } 422 423 //go:nosplit 424 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { 425 mp := getg().m 426 mp.libcall.n = 4 427 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 428 return stdcall(fn) 429 } 430 431 //go:nosplit 432 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { 433 mp := getg().m 434 mp.libcall.n = 5 435 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 436 return stdcall(fn) 437 } 438 439 //go:nosplit 440 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { 441 mp := getg().m 442 mp.libcall.n = 6 443 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 444 return stdcall(fn) 445 } 446 447 //go:nosplit 448 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { 449 mp := getg().m 450 mp.libcall.n = 7 451 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) 452 return stdcall(fn) 453 } 454 455 // in sys_windows_386.s and sys_windows_amd64.s 456 func usleep1(usec uint32) 457 458 //go:nosplit 459 func osyield() { 460 usleep1(1) 461 } 462 463 //go:nosplit 464 func usleep(us uint32) { 465 // Have 1us units; want 100ns units. 466 usleep1(10 * us) 467 } 468 469 func ctrlhandler1(_type uint32) uint32 { 470 var s uint32 471 472 switch _type { 473 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: 474 s = _SIGINT 475 default: 476 return 0 477 } 478 479 if sigsend(s) { 480 return 1 481 } 482 exit(2) // SIGINT, SIGTERM, etc 483 return 0 484 } 485 486 // in sys_windows_386.s and sys_windows_amd64.s 487 func profileloop() 488 489 var profiletimer uintptr 490 491 func profilem(mp *m) { 492 var r *context 493 rbuf := make([]byte, unsafe.Sizeof(*r)+15) 494 495 tls := &mp.tls[0] 496 if mp == &m0 { 497 tls = &tls0[0] 498 } 499 gp := *((**g)(unsafe.Pointer(tls))) 500 501 // align Context to 16 bytes 502 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) 503 r.contextflags = _CONTEXT_CONTROL 504 stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) 505 sigprof(r.ip(), r.sp(), 0, gp, mp) 506 } 507 508 func profileloop1(param uintptr) uint32 { 509 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) 510 511 for { 512 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) 513 first := (*m)(atomicloadp(unsafe.Pointer(&allm))) 514 for mp := first; mp != nil; mp = mp.alllink { 515 thread := atomicloaduintptr(&mp.thread) 516 // Do not profile threads blocked on Notes, 517 // this includes idle worker threads, 518 // idle timer thread, idle heap scavenger, etc. 519 if thread == 0 || mp.profilehz == 0 || mp.blocked { 520 continue 521 } 522 stdcall1(_SuspendThread, thread) 523 if mp.profilehz != 0 && !mp.blocked { 524 profilem(mp) 525 } 526 stdcall1(_ResumeThread, thread) 527 } 528 } 529 } 530 531 var cpuprofilerlock mutex 532 533 func resetcpuprofiler(hz int32) { 534 lock(&cpuprofilerlock) 535 if profiletimer == 0 { 536 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) 537 atomicstoreuintptr(&profiletimer, timer) 538 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) 539 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) 540 stdcall1(_CloseHandle, thread) 541 } 542 unlock(&cpuprofilerlock) 543 544 ms := int32(0) 545 due := ^int64(^uint64(1 << 63)) 546 if hz > 0 { 547 ms = 1000 / hz 548 if ms == 0 { 549 ms = 1 550 } 551 due = int64(ms) * -10000 552 } 553 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) 554 atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) 555 } 556 557 func memlimit() uintptr { 558 return 0 559 }