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