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