Home | History | Annotate | Download | only in runtime
      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 	"runtime/internal/atomic"
      9 	"unsafe"
     10 )
     11 
     12 // TODO(brainman): should not need those
     13 const (
     14 	_NSIG = 65
     15 )
     16 
     17 //go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll"
     18 //go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll"
     19 //go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll"
     20 //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
     21 //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
     22 //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
     23 //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
     24 //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
     25 //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
     26 //go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll"
     27 //go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll"
     28 //go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll"
     29 //go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll"
     30 //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
     31 //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
     32 //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
     33 //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
     34 //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
     35 //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
     36 //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
     37 //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
     38 //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll"
     39 //go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll"
     40 //go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll"
     41 //go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll"
     42 //go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll"
     43 //go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll"
     44 //go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll"
     45 //go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll"
     46 //go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
     47 //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
     48 //go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll"
     49 //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
     50 //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
     51 //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
     52 //go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
     53 
     54 type stdFunction unsafe.Pointer
     55 
     56 var (
     57 	// Following syscalls are available on every Windows PC.
     58 	// All these variables are set by the Windows executable
     59 	// loader before the Go program starts.
     60 	_AddVectoredExceptionHandler,
     61 	_CloseHandle,
     62 	_CreateEventA,
     63 	_CreateIoCompletionPort,
     64 	_CreateThread,
     65 	_CreateWaitableTimerA,
     66 	_DuplicateHandle,
     67 	_ExitProcess,
     68 	_FreeEnvironmentStringsW,
     69 	_GetConsoleMode,
     70 	_GetEnvironmentStringsW,
     71 	_GetProcAddress,
     72 	_GetProcessAffinityMask,
     73 	_GetQueuedCompletionStatus,
     74 	_GetStdHandle,
     75 	_GetSystemInfo,
     76 	_GetThreadContext,
     77 	_LoadLibraryW,
     78 	_LoadLibraryA,
     79 	_ResumeThread,
     80 	_SetConsoleCtrlHandler,
     81 	_SetErrorMode,
     82 	_SetEvent,
     83 	_SetProcessPriorityBoost,
     84 	_SetThreadPriority,
     85 	_SetUnhandledExceptionFilter,
     86 	_SetWaitableTimer,
     87 	_SuspendThread,
     88 	_SwitchToThread,
     89 	_VirtualAlloc,
     90 	_VirtualFree,
     91 	_WSAGetOverlappedResult,
     92 	_WaitForSingleObject,
     93 	_WriteConsoleW,
     94 	_WriteFile,
     95 	_timeBeginPeriod,
     96 	_ stdFunction
     97 
     98 	// Following syscalls are only available on some Windows PCs.
     99 	// We will load syscalls, if available, before using them.
    100 	_AddDllDirectory,
    101 	_AddVectoredContinueHandler,
    102 	_GetQueuedCompletionStatusEx,
    103 	_LoadLibraryExW,
    104 	_ stdFunction
    105 
    106 	// Use RtlGenRandom to generate cryptographically random data.
    107 	// This approach has been recommended by Microsoft (see issue
    108 	// 15589 for details).
    109 	// The RtlGenRandom is not listed in advapi32.dll, instead
    110 	// RtlGenRandom function can be found by searching for SystemFunction036.
    111 	// Also some versions of Mingw cannot link to SystemFunction036
    112 	// when building executable as Cgo. So load SystemFunction036
    113 	// manually during runtime startup.
    114 	_RtlGenRandom stdFunction
    115 
    116 	// Load ntdll.dll manually during startup, otherwise Mingw
    117 	// links wrong printf function to cgo executable (see issue
    118 	// 12030 for details).
    119 	_NtWaitForSingleObject stdFunction
    120 )
    121 
    122 // Function to be called by windows CreateThread
    123 // to start new os thread.
    124 func tstart_stdcall(newm *m) uint32
    125 
    126 func ctrlhandler(_type uint32) uint32
    127 
    128 type mOS struct {
    129 	waitsema uintptr // semaphore for parking on locks
    130 }
    131 
    132 //go:linkname os_sigpipe os.sigpipe
    133 func os_sigpipe() {
    134 	throw("too many writes on closed pipe")
    135 }
    136 
    137 // Stubs so tests can link correctly. These should never be called.
    138 func open(name *byte, mode, perm int32) int32 {
    139 	throw("unimplemented")
    140 	return -1
    141 }
    142 func closefd(fd int32) int32 {
    143 	throw("unimplemented")
    144 	return -1
    145 }
    146 func read(fd int32, p unsafe.Pointer, n int32) int32 {
    147 	throw("unimplemented")
    148 	return -1
    149 }
    150 
    151 type sigset struct{}
    152 
    153 // Call a Windows function with stdcall conventions,
    154 // and switch to os stack during the call.
    155 func asmstdcall(fn unsafe.Pointer)
    156 
    157 var asmstdcallAddr unsafe.Pointer
    158 
    159 func windowsFindfunc(lib uintptr, name []byte) stdFunction {
    160 	if name[len(name)-1] != 0 {
    161 		throw("usage")
    162 	}
    163 	f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
    164 	return stdFunction(unsafe.Pointer(f))
    165 }
    166 
    167 func loadOptionalSyscalls() {
    168 	var kernel32dll = []byte("kernel32.dll\000")
    169 	k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
    170 	if k32 == 0 {
    171 		throw("kernel32.dll not found")
    172 	}
    173 	_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
    174 	_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
    175 	_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
    176 	_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
    177 
    178 	var advapi32dll = []byte("advapi32.dll\000")
    179 	a32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&advapi32dll[0])))
    180 	if a32 == 0 {
    181 		throw("advapi32.dll not found")
    182 	}
    183 	_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
    184 
    185 	var ntdll = []byte("ntdll.dll\000")
    186 	n32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&ntdll[0])))
    187 	if n32 == 0 {
    188 		throw("ntdll.dll not found")
    189 	}
    190 	_NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
    191 }
    192 
    193 //go:nosplit
    194 func getLoadLibrary() uintptr {
    195 	return uintptr(unsafe.Pointer(_LoadLibraryW))
    196 }
    197 
    198 //go:nosplit
    199 func getLoadLibraryEx() uintptr {
    200 	return uintptr(unsafe.Pointer(_LoadLibraryExW))
    201 }
    202 
    203 //go:nosplit
    204 func getGetProcAddress() uintptr {
    205 	return uintptr(unsafe.Pointer(_GetProcAddress))
    206 }
    207 
    208 func getproccount() int32 {
    209 	var mask, sysmask uintptr
    210 	ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
    211 	if ret != 0 {
    212 		n := 0
    213 		maskbits := int(unsafe.Sizeof(mask) * 8)
    214 		for i := 0; i < maskbits; i++ {
    215 			if mask&(1<<uint(i)) != 0 {
    216 				n++
    217 			}
    218 		}
    219 		if n != 0 {
    220 			return int32(n)
    221 		}
    222 	}
    223 	// use GetSystemInfo if GetProcessAffinityMask fails
    224 	var info systeminfo
    225 	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
    226 	return int32(info.dwnumberofprocessors)
    227 }
    228 
    229 func getPageSize() uintptr {
    230 	var info systeminfo
    231 	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
    232 	return uintptr(info.dwpagesize)
    233 }
    234 
    235 const (
    236 	currentProcess = ^uintptr(0) // -1 = current process
    237 	currentThread  = ^uintptr(1) // -2 = current thread
    238 )
    239 
    240 // in sys_windows_386.s and sys_windows_amd64.s:
    241 func externalthreadhandler()
    242 func getlasterror() uint32
    243 func setlasterror(err uint32)
    244 
    245 // When loading DLLs, we prefer to use LoadLibraryEx with
    246 // LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
    247 // available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
    248 // flags are not available on some versions of Windows without a
    249 // security patch.
    250 //
    251 // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
    252 // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
    253 // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
    254 // systems that have KB2533623 installed. To determine whether the
    255 // flags are available, use GetProcAddress to get the address of the
    256 // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
    257 // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
    258 // flags can be used with LoadLibraryEx."
    259 var useLoadLibraryEx bool
    260 
    261 var timeBeginPeriodRetValue uint32
    262 
    263 func osinit() {
    264 	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
    265 	usleep2Addr = unsafe.Pointer(funcPC(usleep2))
    266 	switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread))
    267 
    268 	setBadSignalMsg()
    269 
    270 	loadOptionalSyscalls()
    271 
    272 	useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
    273 
    274 	disableWER()
    275 
    276 	externalthreadhandlerp = funcPC(externalthreadhandler)
    277 
    278 	initExceptionHandler()
    279 
    280 	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
    281 
    282 	timeBeginPeriodRetValue = uint32(stdcall1(_timeBeginPeriod, 1))
    283 
    284 	ncpu = getproccount()
    285 
    286 	physPageSize = getPageSize()
    287 
    288 	// Windows dynamic priority boosting assumes that a process has different types
    289 	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
    290 	// equivalent threads that all do a mix of GUI, IO, computations, etc.
    291 	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
    292 	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
    293 }
    294 
    295 //go:nosplit
    296 func getRandomData(r []byte) {
    297 	n := 0
    298 	if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
    299 		n = len(r)
    300 	}
    301 	extendRandom(r, n)
    302 }
    303 
    304 func goenvs() {
    305 	// strings is a pointer to environment variable pairs in the form:
    306 	//     "envA=valA\x00envB=valB\x00\x00" (in UTF-16)
    307 	// Two consecutive zero bytes end the list.
    308 	strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
    309 	p := (*[1 << 24]uint16)(strings)[:]
    310 
    311 	n := 0
    312 	for from, i := 0, 0; true; i++ {
    313 		if p[i] == 0 {
    314 			// empty string marks the end
    315 			if i == from {
    316 				break
    317 			}
    318 			from = i + 1
    319 			n++
    320 		}
    321 	}
    322 	envs = make([]string, n)
    323 
    324 	for i := range envs {
    325 		envs[i] = gostringw(&p[0])
    326 		for p[0] != 0 {
    327 			p = p[1:]
    328 		}
    329 		p = p[1:] // skip nil byte
    330 	}
    331 
    332 	stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
    333 }
    334 
    335 // exiting is set to non-zero when the process is exiting.
    336 var exiting uint32
    337 
    338 //go:nosplit
    339 func exit(code int32) {
    340 	atomic.Store(&exiting, 1)
    341 	stdcall1(_ExitProcess, uintptr(code))
    342 }
    343 
    344 //go:nosplit
    345 func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
    346 	const (
    347 		_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
    348 		_STD_ERROR_HANDLE  = ^uintptr(11) // -12
    349 	)
    350 	var handle uintptr
    351 	switch fd {
    352 	case 1:
    353 		handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
    354 	case 2:
    355 		handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
    356 	default:
    357 		// assume fd is real windows handle.
    358 		handle = fd
    359 	}
    360 	isASCII := true
    361 	b := (*[1 << 30]byte)(buf)[:n]
    362 	for _, x := range b {
    363 		if x >= 0x80 {
    364 			isASCII = false
    365 			break
    366 		}
    367 	}
    368 
    369 	if !isASCII {
    370 		var m uint32
    371 		isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
    372 		// If this is a console output, various non-unicode code pages can be in use.
    373 		// Use the dedicated WriteConsole call to ensure unicode is printed correctly.
    374 		if isConsole {
    375 			return int32(writeConsole(handle, buf, n))
    376 		}
    377 	}
    378 	var written uint32
    379 	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
    380 	return int32(written)
    381 }
    382 
    383 var (
    384 	utf16ConsoleBack     [1000]uint16
    385 	utf16ConsoleBackLock mutex
    386 )
    387 
    388 // writeConsole writes bufLen bytes from buf to the console File.
    389 // It returns the number of bytes written.
    390 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
    391 	const surr2 = (surrogateMin + surrogateMax + 1) / 2
    392 
    393 	// Do not use defer for unlock. May cause issues when printing a panic.
    394 	lock(&utf16ConsoleBackLock)
    395 
    396 	b := (*[1 << 30]byte)(buf)[:bufLen]
    397 	s := *(*string)(unsafe.Pointer(&b))
    398 
    399 	utf16tmp := utf16ConsoleBack[:]
    400 
    401 	total := len(s)
    402 	w := 0
    403 	for _, r := range s {
    404 		if w >= len(utf16tmp)-2 {
    405 			writeConsoleUTF16(handle, utf16tmp[:w])
    406 			w = 0
    407 		}
    408 		if r < 0x10000 {
    409 			utf16tmp[w] = uint16(r)
    410 			w++
    411 		} else {
    412 			r -= 0x10000
    413 			utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
    414 			utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
    415 			w += 2
    416 		}
    417 	}
    418 	writeConsoleUTF16(handle, utf16tmp[:w])
    419 	unlock(&utf16ConsoleBackLock)
    420 	return total
    421 }
    422 
    423 // writeConsoleUTF16 is the dedicated windows calls that correctly prints
    424 // to the console regardless of the current code page. Input is utf-16 code points.
    425 // The handle must be a console handle.
    426 func writeConsoleUTF16(handle uintptr, b []uint16) {
    427 	l := uint32(len(b))
    428 	if l == 0 {
    429 		return
    430 	}
    431 	var written uint32
    432 	stdcall5(_WriteConsoleW,
    433 		handle,
    434 		uintptr(unsafe.Pointer(&b[0])),
    435 		uintptr(l),
    436 		uintptr(unsafe.Pointer(&written)),
    437 		0,
    438 	)
    439 	return
    440 }
    441 
    442 //go:nosplit
    443 func semasleep(ns int64) int32 {
    444 	const (
    445 		_WAIT_ABANDONED = 0x00000080
    446 		_WAIT_OBJECT_0  = 0x00000000
    447 		_WAIT_TIMEOUT   = 0x00000102
    448 		_WAIT_FAILED    = 0xFFFFFFFF
    449 	)
    450 
    451 	// store ms in ns to save stack space
    452 	if ns < 0 {
    453 		ns = _INFINITE
    454 	} else {
    455 		ns = int64(timediv(ns, 1000000, nil))
    456 		if ns == 0 {
    457 			ns = 1
    458 		}
    459 	}
    460 
    461 	result := stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns))
    462 	switch result {
    463 	case _WAIT_OBJECT_0: //signaled
    464 		return 0
    465 
    466 	case _WAIT_TIMEOUT:
    467 		return -1
    468 
    469 	case _WAIT_ABANDONED:
    470 		systemstack(func() {
    471 			throw("runtime.semasleep wait_abandoned")
    472 		})
    473 
    474 	case _WAIT_FAILED:
    475 		systemstack(func() {
    476 			print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
    477 			throw("runtime.semasleep wait_failed")
    478 		})
    479 
    480 	default:
    481 		systemstack(func() {
    482 			print("runtime: waitforsingleobject unexpected; result=", result, "\n")
    483 			throw("runtime.semasleep unexpected")
    484 		})
    485 	}
    486 
    487 	return -1 // unreachable
    488 }
    489 
    490 //go:nosplit
    491 func semawakeup(mp *m) {
    492 	if stdcall1(_SetEvent, mp.waitsema) == 0 {
    493 		systemstack(func() {
    494 			print("runtime: setevent failed; errno=", getlasterror(), "\n")
    495 			throw("runtime.semawakeup")
    496 		})
    497 	}
    498 }
    499 
    500 //go:nosplit
    501 func semacreate(mp *m) {
    502 	if mp.waitsema != 0 {
    503 		return
    504 	}
    505 	mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
    506 	if mp.waitsema == 0 {
    507 		systemstack(func() {
    508 			print("runtime: createevent failed; errno=", getlasterror(), "\n")
    509 			throw("runtime.semacreate")
    510 		})
    511 	}
    512 }
    513 
    514 // May run with m.p==nil, so write barriers are not allowed. This
    515 // function is called by newosproc0, so it is also required to
    516 // operate without stack guards.
    517 //go:nowritebarrierrec
    518 //go:nosplit
    519 func newosproc(mp *m, stk unsafe.Pointer) {
    520 	const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
    521 	thandle := stdcall6(_CreateThread, 0, 0x20000,
    522 		funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
    523 		_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
    524 
    525 	if thandle == 0 {
    526 		if atomic.Load(&exiting) != 0 {
    527 			// CreateThread may fail if called
    528 			// concurrently with ExitProcess. If this
    529 			// happens, just freeze this thread and let
    530 			// the process exit. See issue #18253.
    531 			lock(&deadlock)
    532 			lock(&deadlock)
    533 		}
    534 		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
    535 		throw("runtime.newosproc")
    536 	}
    537 }
    538 
    539 // Used by the C library build mode. On Linux this function would allocate a
    540 // stack, but that's not necessary for Windows. No stack guards are present
    541 // and the GC has not been initialized, so write barriers will fail.
    542 //go:nowritebarrierrec
    543 //go:nosplit
    544 func newosproc0(mp *m, stk unsafe.Pointer) {
    545 	newosproc(mp, stk)
    546 }
    547 
    548 // Called to initialize a new m (including the bootstrap m).
    549 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    550 func mpreinit(mp *m) {
    551 }
    552 
    553 //go:nosplit
    554 func msigsave(mp *m) {
    555 }
    556 
    557 //go:nosplit
    558 func msigrestore(sigmask sigset) {
    559 }
    560 
    561 //go:nosplit
    562 func sigblock() {
    563 }
    564 
    565 // Called to initialize a new m (including the bootstrap m).
    566 // Called on the new thread, cannot allocate memory.
    567 func minit() {
    568 	var thandle uintptr
    569 	stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
    570 	atomic.Storeuintptr(&getg().m.thread, thandle)
    571 }
    572 
    573 // Called from dropm to undo the effect of an minit.
    574 //go:nosplit
    575 func unminit() {
    576 	tp := &getg().m.thread
    577 	stdcall1(_CloseHandle, *tp)
    578 	*tp = 0
    579 }
    580 
    581 // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
    582 type _KSYSTEM_TIME struct {
    583 	LowPart   uint32
    584 	High1Time int32
    585 	High2Time int32
    586 }
    587 
    588 const (
    589 	_INTERRUPT_TIME = 0x7ffe0008
    590 	_SYSTEM_TIME    = 0x7ffe0014
    591 )
    592 
    593 //go:nosplit
    594 func systime(addr uintptr) int64 {
    595 	timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
    596 
    597 	var t _KSYSTEM_TIME
    598 	for i := 1; i < 10000; i++ {
    599 		// these fields must be read in that order (see URL above)
    600 		t.High1Time = timeaddr.High1Time
    601 		t.LowPart = timeaddr.LowPart
    602 		t.High2Time = timeaddr.High2Time
    603 		if t.High1Time == t.High2Time {
    604 			return int64(t.High1Time)<<32 | int64(t.LowPart)
    605 		}
    606 		if (i % 100) == 0 {
    607 			osyield()
    608 		}
    609 	}
    610 	systemstack(func() {
    611 		throw("interrupt/system time is changing too fast")
    612 	})
    613 	return 0
    614 }
    615 
    616 //go:nosplit
    617 func unixnano() int64 {
    618 	return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
    619 }
    620 
    621 //go:nosplit
    622 func nanotime() int64 {
    623 	return systime(_INTERRUPT_TIME) * 100
    624 }
    625 
    626 // Calling stdcall on os stack.
    627 // May run during STW, so write barriers are not allowed.
    628 //go:nowritebarrier
    629 //go:nosplit
    630 func stdcall(fn stdFunction) uintptr {
    631 	gp := getg()
    632 	mp := gp.m
    633 	mp.libcall.fn = uintptr(unsafe.Pointer(fn))
    634 
    635 	if mp.profilehz != 0 {
    636 		// leave pc/sp for cpu profiler
    637 		mp.libcallg.set(gp)
    638 		mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
    639 		// sp must be the last, because once async cpu profiler finds
    640 		// all three values to be non-zero, it will use them
    641 		mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
    642 	}
    643 	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
    644 	mp.libcallsp = 0
    645 	return mp.libcall.r1
    646 }
    647 
    648 //go:nosplit
    649 func stdcall0(fn stdFunction) uintptr {
    650 	mp := getg().m
    651 	mp.libcall.n = 0
    652 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
    653 	return stdcall(fn)
    654 }
    655 
    656 //go:nosplit
    657 func stdcall1(fn stdFunction, a0 uintptr) uintptr {
    658 	mp := getg().m
    659 	mp.libcall.n = 1
    660 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    661 	return stdcall(fn)
    662 }
    663 
    664 //go:nosplit
    665 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
    666 	mp := getg().m
    667 	mp.libcall.n = 2
    668 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    669 	return stdcall(fn)
    670 }
    671 
    672 //go:nosplit
    673 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
    674 	mp := getg().m
    675 	mp.libcall.n = 3
    676 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    677 	return stdcall(fn)
    678 }
    679 
    680 //go:nosplit
    681 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
    682 	mp := getg().m
    683 	mp.libcall.n = 4
    684 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    685 	return stdcall(fn)
    686 }
    687 
    688 //go:nosplit
    689 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
    690 	mp := getg().m
    691 	mp.libcall.n = 5
    692 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    693 	return stdcall(fn)
    694 }
    695 
    696 //go:nosplit
    697 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
    698 	mp := getg().m
    699 	mp.libcall.n = 6
    700 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    701 	return stdcall(fn)
    702 }
    703 
    704 //go:nosplit
    705 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
    706 	mp := getg().m
    707 	mp.libcall.n = 7
    708 	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
    709 	return stdcall(fn)
    710 }
    711 
    712 // in sys_windows_386.s and sys_windows_amd64.s
    713 func onosstack(fn unsafe.Pointer, arg uint32)
    714 func usleep2(usec uint32)
    715 func switchtothread()
    716 
    717 var usleep2Addr unsafe.Pointer
    718 var switchtothreadAddr unsafe.Pointer
    719 
    720 //go:nosplit
    721 func osyield() {
    722 	onosstack(switchtothreadAddr, 0)
    723 }
    724 
    725 //go:nosplit
    726 func usleep(us uint32) {
    727 	// Have 1us units; want 100ns units.
    728 	onosstack(usleep2Addr, 10*us)
    729 }
    730 
    731 func ctrlhandler1(_type uint32) uint32 {
    732 	var s uint32
    733 
    734 	switch _type {
    735 	case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
    736 		s = _SIGINT
    737 	default:
    738 		return 0
    739 	}
    740 
    741 	if sigsend(s) {
    742 		return 1
    743 	}
    744 	exit(2) // SIGINT, SIGTERM, etc
    745 	return 0
    746 }
    747 
    748 // in sys_windows_386.s and sys_windows_amd64.s
    749 func profileloop()
    750 
    751 var profiletimer uintptr
    752 
    753 func profilem(mp *m) {
    754 	var r *context
    755 	rbuf := make([]byte, unsafe.Sizeof(*r)+15)
    756 
    757 	tls := &mp.tls[0]
    758 	gp := *((**g)(unsafe.Pointer(tls)))
    759 
    760 	// align Context to 16 bytes
    761 	r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
    762 	r.contextflags = _CONTEXT_CONTROL
    763 	stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
    764 	sigprof(r.ip(), r.sp(), 0, gp, mp)
    765 }
    766 
    767 func profileloop1(param uintptr) uint32 {
    768 	stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
    769 
    770 	for {
    771 		stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
    772 		first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
    773 		for mp := first; mp != nil; mp = mp.alllink {
    774 			thread := atomic.Loaduintptr(&mp.thread)
    775 			// Do not profile threads blocked on Notes,
    776 			// this includes idle worker threads,
    777 			// idle timer thread, idle heap scavenger, etc.
    778 			if thread == 0 || mp.profilehz == 0 || mp.blocked {
    779 				continue
    780 			}
    781 			stdcall1(_SuspendThread, thread)
    782 			if mp.profilehz != 0 && !mp.blocked {
    783 				profilem(mp)
    784 			}
    785 			stdcall1(_ResumeThread, thread)
    786 		}
    787 	}
    788 }
    789 
    790 var cpuprofilerlock mutex
    791 
    792 func resetcpuprofiler(hz int32) {
    793 	lock(&cpuprofilerlock)
    794 	if profiletimer == 0 {
    795 		timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
    796 		atomic.Storeuintptr(&profiletimer, timer)
    797 		thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
    798 		stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
    799 		stdcall1(_CloseHandle, thread)
    800 	}
    801 	unlock(&cpuprofilerlock)
    802 
    803 	ms := int32(0)
    804 	due := ^int64(^uint64(1 << 63))
    805 	if hz > 0 {
    806 		ms = 1000 / hz
    807 		if ms == 0 {
    808 			ms = 1
    809 		}
    810 		due = int64(ms) * -10000
    811 	}
    812 	stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
    813 	atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
    814 }
    815 
    816 func memlimit() uintptr {
    817 	return 0
    818 }
    819