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