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
5package runtime
6
7import (
8	"runtime/internal/atomic"
9	"runtime/internal/sys"
10	"unsafe"
11)
12
13// TODO(brainman): should not need those
14const (
15	_NSIG = 65
16)
17
18//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll"
19//go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll"
20//go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll"
21//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
22//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
23//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
24//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
25//go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
26//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
27//go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll"
28//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll"
29//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll"
30//go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll"
31//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
32//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
33//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll"
34//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
35//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
36//go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll"
37//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
38//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
39//go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
40//go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
41//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
42//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll"
43//go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll"
44//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll"
45//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll"
46//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll"
47//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll"
48//go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll"
49//go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll"
50//go:cgo_import_dynamic runtime._TlsAlloc TlsAlloc%0 "kernel32.dll"
51//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
52//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
53//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
54//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
55//go:cgo_import_dynamic runtime._WaitForMultipleObjects WaitForMultipleObjects%4 "kernel32.dll"
56//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
57//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
58
59type stdFunction unsafe.Pointer
60
61var (
62	// Following syscalls are available on every Windows PC.
63	// All these variables are set by the Windows executable
64	// loader before the Go program starts.
65	_AddVectoredExceptionHandler,
66	_CloseHandle,
67	_CreateEventA,
68	_CreateIoCompletionPort,
69	_CreateThread,
70	_CreateWaitableTimerA,
71	_DuplicateHandle,
72	_ExitProcess,
73	_FreeEnvironmentStringsW,
74	_GetConsoleMode,
75	_GetEnvironmentStringsW,
76	_GetProcAddress,
77	_GetProcessAffinityMask,
78	_GetQueuedCompletionStatus,
79	_GetStdHandle,
80	_GetSystemDirectoryA,
81	_GetSystemInfo,
82	_GetSystemTimeAsFileTime,
83	_GetThreadContext,
84	_SetThreadContext,
85	_LoadLibraryW,
86	_LoadLibraryA,
87	_PostQueuedCompletionStatus,
88	_QueryPerformanceCounter,
89	_QueryPerformanceFrequency,
90	_ResumeThread,
91	_SetConsoleCtrlHandler,
92	_SetErrorMode,
93	_SetEvent,
94	_SetProcessPriorityBoost,
95	_SetThreadPriority,
96	_SetUnhandledExceptionFilter,
97	_SetWaitableTimer,
98	_SuspendThread,
99	_SwitchToThread,
100	_TlsAlloc,
101	_VirtualAlloc,
102	_VirtualFree,
103	_VirtualQuery,
104	_WaitForSingleObject,
105	_WaitForMultipleObjects,
106	_WriteConsoleW,
107	_WriteFile,
108	_ stdFunction
109
110	// Following syscalls are only available on some Windows PCs.
111	// We will load syscalls, if available, before using them.
112	_AddDllDirectory,
113	_AddVectoredContinueHandler,
114	_GetQueuedCompletionStatusEx,
115	_LoadLibraryExA,
116	_LoadLibraryExW,
117	_ stdFunction
118
119	// Use RtlGenRandom to generate cryptographically random data.
120	// This approach has been recommended by Microsoft (see issue
121	// 15589 for details).
122	// The RtlGenRandom is not listed in advapi32.dll, instead
123	// RtlGenRandom function can be found by searching for SystemFunction036.
124	// Also some versions of Mingw cannot link to SystemFunction036
125	// when building executable as Cgo. So load SystemFunction036
126	// manually during runtime startup.
127	_RtlGenRandom stdFunction
128
129	// Load ntdll.dll manually during startup, otherwise Mingw
130	// links wrong printf function to cgo executable (see issue
131	// 12030 for details).
132	_NtWaitForSingleObject stdFunction
133
134	// These are from non-kernel32.dll, so we prefer to LoadLibraryEx them.
135	_timeBeginPeriod,
136	_timeEndPeriod,
137	_WSAGetOverlappedResult,
138	_ stdFunction
139)
140
141// Function to be called by windows CreateThread
142// to start new os thread.
143func tstart_stdcall(newm *m)
144
145// Called by OS using stdcall ABI.
146func ctrlhandler()
147
148type mOS struct {
149	threadLock mutex   // protects "thread" and prevents closing
150	thread     uintptr // thread handle
151
152	waitsema   uintptr // semaphore for parking on locks
153	resumesema uintptr // semaphore to indicate suspend/resume
154
155	// preemptExtLock synchronizes preemptM with entry/exit from
156	// external C code.
157	//
158	// This protects against races between preemptM calling
159	// SuspendThread and external code on this thread calling
160	// ExitProcess. If these happen concurrently, it's possible to
161	// exit the suspending thread and suspend the exiting thread,
162	// leading to deadlock.
163	//
164	// 0 indicates this M is not being preempted or in external
165	// code. Entering external code CASes this from 0 to 1. If
166	// this fails, a preemption is in progress, so the thread must
167	// wait for the preemption. preemptM also CASes this from 0 to
168	// 1. If this fails, the preemption fails (as it would if the
169	// PC weren't in Go code). The value is reset to 0 when
170	// returning from external code or after a preemption is
171	// complete.
172	//
173	// TODO(austin): We may not need this if preemption were more
174	// tightly synchronized on the G/P status and preemption
175	// blocked transition into _Gsyscall/_Psyscall.
176	preemptExtLock uint32
177}
178
179//go:linkname os_sigpipe os.sigpipe
180func os_sigpipe() {
181	throw("too many writes on closed pipe")
182}
183
184// Stubs so tests can link correctly. These should never be called.
185func open(name *byte, mode, perm int32) int32 {
186	throw("unimplemented")
187	return -1
188}
189func closefd(fd int32) int32 {
190	throw("unimplemented")
191	return -1
192}
193func read(fd int32, p unsafe.Pointer, n int32) int32 {
194	throw("unimplemented")
195	return -1
196}
197
198type sigset struct{}
199
200// Call a Windows function with stdcall conventions,
201// and switch to os stack during the call.
202func asmstdcall(fn unsafe.Pointer)
203
204var asmstdcallAddr unsafe.Pointer
205
206func windowsFindfunc(lib uintptr, name []byte) stdFunction {
207	if name[len(name)-1] != 0 {
208		throw("usage")
209	}
210	f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
211	return stdFunction(unsafe.Pointer(f))
212}
213
214var sysDirectory [521]byte
215var sysDirectoryLen uintptr
216
217func windowsLoadSystemLib(name []byte) uintptr {
218	if useLoadLibraryEx {
219		return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
220	} else {
221		if sysDirectoryLen == 0 {
222			l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
223			if l == 0 || l > uintptr(len(sysDirectory)-1) {
224				throw("Unable to determine system directory")
225			}
226			sysDirectory[l] = '\\'
227			sysDirectoryLen = l + 1
228		}
229		absName := append(sysDirectory[:sysDirectoryLen], name...)
230		return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
231	}
232}
233
234func loadOptionalSyscalls() {
235	var kernel32dll = []byte("kernel32.dll\000")
236	k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
237	if k32 == 0 {
238		throw("kernel32.dll not found")
239	}
240	_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
241	_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
242	_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
243	_LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
244	_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
245	useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
246
247	var advapi32dll = []byte("advapi32.dll\000")
248	a32 := windowsLoadSystemLib(advapi32dll)
249	if a32 == 0 {
250		throw("advapi32.dll not found")
251	}
252	_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
253
254	var ntdll = []byte("ntdll.dll\000")
255	n32 := windowsLoadSystemLib(ntdll)
256	if n32 == 0 {
257		throw("ntdll.dll not found")
258	}
259	_NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
260
261	if GOARCH == "arm" {
262		_QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
263		if _QueryPerformanceCounter == nil {
264			throw("could not find QPC syscalls")
265		}
266	}
267
268	var winmmdll = []byte("winmm.dll\000")
269	m32 := windowsLoadSystemLib(winmmdll)
270	if m32 == 0 {
271		throw("winmm.dll not found")
272	}
273	_timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
274	_timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
275	if _timeBeginPeriod == nil || _timeEndPeriod == nil {
276		throw("timeBegin/EndPeriod not found")
277	}
278
279	var ws232dll = []byte("ws2_32.dll\000")
280	ws232 := windowsLoadSystemLib(ws232dll)
281	if ws232 == 0 {
282		throw("ws2_32.dll not found")
283	}
284	_WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
285	if _WSAGetOverlappedResult == nil {
286		throw("WSAGetOverlappedResult not found")
287	}
288
289	if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
290		// running on Wine
291		initWine(k32)
292	}
293}
294
295func monitorSuspendResume() {
296	const (
297		_DEVICE_NOTIFY_CALLBACK   = 2
298		_ERROR_FILE_NOT_FOUND     = 2
299		_ERROR_INVALID_PARAMETERS = 87
300	)
301	type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
302		callback uintptr
303		context  uintptr
304	}
305
306	powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
307	if powrprof == 0 {
308		return // Running on Windows 7, where we don't need it anyway.
309	}
310	powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
311	if powerRegisterSuspendResumeNotification == nil {
312		return // Running on Windows 7, where we don't need it anyway.
313	}
314	var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
315		for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
316			if mp.resumesema != 0 {
317				stdcall1(_SetEvent, mp.resumesema)
318			}
319		}
320		return 0
321	}
322	params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
323		callback: compileCallback(*efaceOf(&fn), true),
324	}
325	handle := uintptr(0)
326	ret := stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
327		uintptr(unsafe.Pointer(&params)), uintptr(unsafe.Pointer(&handle)))
328	// This function doesn't use GetLastError(), so we use the return value directly.
329	switch ret {
330	case 0:
331		return // Successful, nothing more to do.
332	case _ERROR_FILE_NOT_FOUND:
333		// Systems without access to the suspend/resume notifier
334		// also have their clock on "program time", and therefore
335		// don't want or need this anyway.
336		return
337	case _ERROR_INVALID_PARAMETERS:
338		// This is seen when running in Windows Docker.
339		// See issue 36557.
340		return
341	default:
342		println("runtime: PowerRegisterSuspendResumeNotification failed with errno=", ret)
343		throw("runtime: PowerRegisterSuspendResumeNotification failure")
344	}
345}
346
347//go:nosplit
348func getLoadLibrary() uintptr {
349	return uintptr(unsafe.Pointer(_LoadLibraryW))
350}
351
352//go:nosplit
353func getLoadLibraryEx() uintptr {
354	return uintptr(unsafe.Pointer(_LoadLibraryExW))
355}
356
357//go:nosplit
358func getGetProcAddress() uintptr {
359	return uintptr(unsafe.Pointer(_GetProcAddress))
360}
361
362func getproccount() int32 {
363	var mask, sysmask uintptr
364	ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
365	if ret != 0 {
366		n := 0
367		maskbits := int(unsafe.Sizeof(mask) * 8)
368		for i := 0; i < maskbits; i++ {
369			if mask&(1<<uint(i)) != 0 {
370				n++
371			}
372		}
373		if n != 0 {
374			return int32(n)
375		}
376	}
377	// use GetSystemInfo if GetProcessAffinityMask fails
378	var info systeminfo
379	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
380	return int32(info.dwnumberofprocessors)
381}
382
383func getPageSize() uintptr {
384	var info systeminfo
385	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
386	return uintptr(info.dwpagesize)
387}
388
389const (
390	currentProcess = ^uintptr(0) // -1 = current process
391	currentThread  = ^uintptr(1) // -2 = current thread
392)
393
394// in sys_windows_386.s and sys_windows_amd64.s:
395func externalthreadhandler()
396func getlasterror() uint32
397func setlasterror(err uint32)
398
399// When loading DLLs, we prefer to use LoadLibraryEx with
400// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
401// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
402// flags are not available on some versions of Windows without a
403// security patch.
404//
405// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
406// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
407// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
408// systems that have KB2533623 installed. To determine whether the
409// flags are available, use GetProcAddress to get the address of the
410// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
411// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
412// flags can be used with LoadLibraryEx."
413var useLoadLibraryEx bool
414
415var timeBeginPeriodRetValue uint32
416
417// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
418// timer is less than 60 ms from now. Since osRelaxing may reduce
419// timer resolution to 15.6 ms, this keeps timer error under roughly 1
420// part in 4.
421const osRelaxMinNS = 60 * 1e6
422
423// osRelax is called by the scheduler when transitioning to and from
424// all Ps being idle.
425//
426// On Windows, it adjusts the system-wide timer resolution. Go needs a
427// high resolution timer while running and there's little extra cost
428// if we're already using the CPU, but if all Ps are idle there's no
429// need to consume extra power to drive the high-res timer.
430func osRelax(relax bool) uint32 {
431	if relax {
432		return uint32(stdcall1(_timeEndPeriod, 1))
433	} else {
434		return uint32(stdcall1(_timeBeginPeriod, 1))
435	}
436}
437
438func osinit() {
439	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
440	usleep2Addr = unsafe.Pointer(funcPC(usleep2))
441	switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread))
442
443	setBadSignalMsg()
444
445	loadOptionalSyscalls()
446
447	disableWER()
448
449	initExceptionHandler()
450
451	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
452
453	timeBeginPeriodRetValue = osRelax(false)
454
455	ncpu = getproccount()
456
457	physPageSize = getPageSize()
458
459	// Windows dynamic priority boosting assumes that a process has different types
460	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
461	// equivalent threads that all do a mix of GUI, IO, computations, etc.
462	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
463	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
464}
465
466// useQPCTime controls whether time.now and nanotime use QueryPerformanceCounter.
467// This is only set to 1 when running under Wine.
468var useQPCTime uint8
469
470var qpcStartCounter int64
471var qpcMultiplier int64
472
473//go:nosplit
474func nanotimeQPC() int64 {
475	var counter int64 = 0
476	stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
477
478	// returns number of nanoseconds
479	return (counter - qpcStartCounter) * qpcMultiplier
480}
481
482//go:nosplit
483func nowQPC() (sec int64, nsec int32, mono int64) {
484	var ft int64
485	stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft)))
486
487	t := (ft - 116444736000000000) * 100
488
489	sec = t / 1000000000
490	nsec = int32(t - sec*1000000000)
491
492	mono = nanotimeQPC()
493	return
494}
495
496func initWine(k32 uintptr) {
497	_GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
498	if _GetSystemTimeAsFileTime == nil {
499		throw("could not find GetSystemTimeAsFileTime() syscall")
500	}
501
502	_QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
503	_QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000"))
504	if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil {
505		throw("could not find QPC syscalls")
506	}
507
508	// We can not simply fallback to GetSystemTimeAsFileTime() syscall, since its time is not monotonic,
509	// instead we use QueryPerformanceCounter family of syscalls to implement monotonic timer
510	// https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
511
512	var tmp int64
513	stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp)))
514	if tmp == 0 {
515		throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware")
516	}
517
518	// This should not overflow, it is a number of ticks of the performance counter per second,
519	// its resolution is at most 10 per usecond (on Wine, even smaller on real hardware), so it will be at most 10 millions here,
520	// panic if overflows.
521	if tmp > (1<<31 - 1) {
522		throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed")
523	}
524	qpcFrequency := int32(tmp)
525	stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter)))
526
527	// Since we are supposed to run this time calls only on Wine, it does not lose precision,
528	// since Wine's timer is kind of emulated at 10 Mhz, so it will be a nice round multiplier of 100
529	// but for general purpose system (like 3.3 Mhz timer on i7) it will not be very precise.
530	// We have to do it this way (or similar), since multiplying QPC counter by 100 millions overflows
531	// int64 and resulted time will always be invalid.
532	qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))
533
534	useQPCTime = 1
535}
536
537//go:nosplit
538func getRandomData(r []byte) {
539	n := 0
540	if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
541		n = len(r)
542	}
543	extendRandom(r, n)
544}
545
546func goenvs() {
547	// strings is a pointer to environment variable pairs in the form:
548	//     "envA=valA\x00envB=valB\x00\x00" (in UTF-16)
549	// Two consecutive zero bytes end the list.
550	strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
551	p := (*[1 << 24]uint16)(strings)[:]
552
553	n := 0
554	for from, i := 0, 0; true; i++ {
555		if p[i] == 0 {
556			// empty string marks the end
557			if i == from {
558				break
559			}
560			from = i + 1
561			n++
562		}
563	}
564	envs = make([]string, n)
565
566	for i := range envs {
567		envs[i] = gostringw(&p[0])
568		for p[0] != 0 {
569			p = p[1:]
570		}
571		p = p[1:] // skip nil byte
572	}
573
574	stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
575
576	// We call this all the way here, late in init, so that malloc works
577	// for the callback function this generates.
578	monitorSuspendResume()
579}
580
581// exiting is set to non-zero when the process is exiting.
582var exiting uint32
583
584//go:nosplit
585func exit(code int32) {
586	// Disallow thread suspension for preemption. Otherwise,
587	// ExitProcess and SuspendThread can race: SuspendThread
588	// queues a suspension request for this thread, ExitProcess
589	// kills the suspending thread, and then this thread suspends.
590	lock(&suspendLock)
591	atomic.Store(&exiting, 1)
592	stdcall1(_ExitProcess, uintptr(code))
593}
594
595// write1 must be nosplit because it's used as a last resort in
596// functions like badmorestackg0. In such cases, we'll always take the
597// ASCII path.
598//
599//go:nosplit
600func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
601	const (
602		_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
603		_STD_ERROR_HANDLE  = ^uintptr(11) // -12
604	)
605	var handle uintptr
606	switch fd {
607	case 1:
608		handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
609	case 2:
610		handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
611	default:
612		// assume fd is real windows handle.
613		handle = fd
614	}
615	isASCII := true
616	b := (*[1 << 30]byte)(buf)[:n]
617	for _, x := range b {
618		if x >= 0x80 {
619			isASCII = false
620			break
621		}
622	}
623
624	if !isASCII {
625		var m uint32
626		isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
627		// If this is a console output, various non-unicode code pages can be in use.
628		// Use the dedicated WriteConsole call to ensure unicode is printed correctly.
629		if isConsole {
630			return int32(writeConsole(handle, buf, n))
631		}
632	}
633	var written uint32
634	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
635	return int32(written)
636}
637
638var (
639	utf16ConsoleBack     [1000]uint16
640	utf16ConsoleBackLock mutex
641)
642
643// writeConsole writes bufLen bytes from buf to the console File.
644// It returns the number of bytes written.
645func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
646	const surr2 = (surrogateMin + surrogateMax + 1) / 2
647
648	// Do not use defer for unlock. May cause issues when printing a panic.
649	lock(&utf16ConsoleBackLock)
650
651	b := (*[1 << 30]byte)(buf)[:bufLen]
652	s := *(*string)(unsafe.Pointer(&b))
653
654	utf16tmp := utf16ConsoleBack[:]
655
656	total := len(s)
657	w := 0
658	for _, r := range s {
659		if w >= len(utf16tmp)-2 {
660			writeConsoleUTF16(handle, utf16tmp[:w])
661			w = 0
662		}
663		if r < 0x10000 {
664			utf16tmp[w] = uint16(r)
665			w++
666		} else {
667			r -= 0x10000
668			utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
669			utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
670			w += 2
671		}
672	}
673	writeConsoleUTF16(handle, utf16tmp[:w])
674	unlock(&utf16ConsoleBackLock)
675	return total
676}
677
678// writeConsoleUTF16 is the dedicated windows calls that correctly prints
679// to the console regardless of the current code page. Input is utf-16 code points.
680// The handle must be a console handle.
681func writeConsoleUTF16(handle uintptr, b []uint16) {
682	l := uint32(len(b))
683	if l == 0 {
684		return
685	}
686	var written uint32
687	stdcall5(_WriteConsoleW,
688		handle,
689		uintptr(unsafe.Pointer(&b[0])),
690		uintptr(l),
691		uintptr(unsafe.Pointer(&written)),
692		0,
693	)
694	return
695}
696
697// walltime1 isn't implemented on Windows, but will never be called.
698func walltime1() (sec int64, nsec int32)
699
700//go:nosplit
701func semasleep(ns int64) int32 {
702	const (
703		_WAIT_ABANDONED = 0x00000080
704		_WAIT_OBJECT_0  = 0x00000000
705		_WAIT_TIMEOUT   = 0x00000102
706		_WAIT_FAILED    = 0xFFFFFFFF
707	)
708
709	var result uintptr
710	if ns < 0 {
711		result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
712	} else {
713		start := nanotime()
714		elapsed := int64(0)
715		for {
716			ms := int64(timediv(ns-elapsed, 1000000, nil))
717			if ms == 0 {
718				ms = 1
719			}
720			result = stdcall4(_WaitForMultipleObjects, 2,
721				uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
722				0, uintptr(ms))
723			if result != _WAIT_OBJECT_0+1 {
724				// Not a suspend/resume event
725				break
726			}
727			elapsed = nanotime() - start
728			if elapsed >= ns {
729				return -1
730			}
731		}
732	}
733	switch result {
734	case _WAIT_OBJECT_0: // Signaled
735		return 0
736
737	case _WAIT_TIMEOUT:
738		return -1
739
740	case _WAIT_ABANDONED:
741		systemstack(func() {
742			throw("runtime.semasleep wait_abandoned")
743		})
744
745	case _WAIT_FAILED:
746		systemstack(func() {
747			print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
748			throw("runtime.semasleep wait_failed")
749		})
750
751	default:
752		systemstack(func() {
753			print("runtime: waitforsingleobject unexpected; result=", result, "\n")
754			throw("runtime.semasleep unexpected")
755		})
756	}
757
758	return -1 // unreachable
759}
760
761//go:nosplit
762func semawakeup(mp *m) {
763	if stdcall1(_SetEvent, mp.waitsema) == 0 {
764		systemstack(func() {
765			print("runtime: setevent failed; errno=", getlasterror(), "\n")
766			throw("runtime.semawakeup")
767		})
768	}
769}
770
771//go:nosplit
772func semacreate(mp *m) {
773	if mp.waitsema != 0 {
774		return
775	}
776	mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
777	if mp.waitsema == 0 {
778		systemstack(func() {
779			print("runtime: createevent failed; errno=", getlasterror(), "\n")
780			throw("runtime.semacreate")
781		})
782	}
783	mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
784	if mp.resumesema == 0 {
785		systemstack(func() {
786			print("runtime: createevent failed; errno=", getlasterror(), "\n")
787			throw("runtime.semacreate")
788		})
789		stdcall1(_CloseHandle, mp.waitsema)
790		mp.waitsema = 0
791	}
792}
793
794// May run with m.p==nil, so write barriers are not allowed. This
795// function is called by newosproc0, so it is also required to
796// operate without stack guards.
797//go:nowritebarrierrec
798//go:nosplit
799func newosproc(mp *m) {
800	// We pass 0 for the stack size to use the default for this binary.
801	thandle := stdcall6(_CreateThread, 0, 0,
802		funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
803		0, 0)
804
805	if thandle == 0 {
806		if atomic.Load(&exiting) != 0 {
807			// CreateThread may fail if called
808			// concurrently with ExitProcess. If this
809			// happens, just freeze this thread and let
810			// the process exit. See issue #18253.
811			lock(&deadlock)
812			lock(&deadlock)
813		}
814		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
815		throw("runtime.newosproc")
816	}
817
818	// Close thandle to avoid leaking the thread object if it exits.
819	stdcall1(_CloseHandle, thandle)
820}
821
822// Used by the C library build mode. On Linux this function would allocate a
823// stack, but that's not necessary for Windows. No stack guards are present
824// and the GC has not been initialized, so write barriers will fail.
825//go:nowritebarrierrec
826//go:nosplit
827func newosproc0(mp *m, stk unsafe.Pointer) {
828	// TODO: this is completely broken. The args passed to newosproc0 (in asm_amd64.s)
829	// are stacksize and function, not *m and stack.
830	// Check os_linux.go for an implementation that might actually work.
831	throw("bad newosproc0")
832}
833
834func exitThread(wait *uint32) {
835	// We should never reach exitThread on Windows because we let
836	// the OS clean up threads.
837	throw("exitThread")
838}
839
840// Called to initialize a new m (including the bootstrap m).
841// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
842func mpreinit(mp *m) {
843}
844
845//go:nosplit
846func msigsave(mp *m) {
847}
848
849//go:nosplit
850func msigrestore(sigmask sigset) {
851}
852
853//go:nosplit
854//go:nowritebarrierrec
855func clearSignalHandlers() {
856}
857
858//go:nosplit
859func sigblock() {
860}
861
862// Called to initialize a new m (including the bootstrap m).
863// Called on the new thread, cannot allocate memory.
864func minit() {
865	var thandle uintptr
866	stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
867
868	mp := getg().m
869	lock(&mp.threadLock)
870	mp.thread = thandle
871	unlock(&mp.threadLock)
872
873	// Query the true stack base from the OS. Currently we're
874	// running on a small assumed stack.
875	var mbi memoryBasicInformation
876	res := stdcall3(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
877	if res == 0 {
878		print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
879		throw("VirtualQuery for stack base failed")
880	}
881	// The system leaves an 8K PAGE_GUARD region at the bottom of
882	// the stack (in theory VirtualQuery isn't supposed to include
883	// that, but it does). Add an additional 8K of slop for
884	// calling C functions that don't have stack checks and for
885	// lastcontinuehandler. We shouldn't be anywhere near this
886	// bound anyway.
887	base := mbi.allocationBase + 16<<10
888	// Sanity check the stack bounds.
889	g0 := getg()
890	if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
891		print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
892		throw("bad g0 stack")
893	}
894	g0.stack.lo = base
895	g0.stackguard0 = g0.stack.lo + _StackGuard
896	g0.stackguard1 = g0.stackguard0
897	// Sanity check the SP.
898	stackcheck()
899}
900
901// Called from dropm to undo the effect of an minit.
902//go:nosplit
903func unminit() {
904	mp := getg().m
905	lock(&mp.threadLock)
906	stdcall1(_CloseHandle, mp.thread)
907	mp.thread = 0
908	unlock(&mp.threadLock)
909}
910
911// Calling stdcall on os stack.
912// May run during STW, so write barriers are not allowed.
913//go:nowritebarrier
914//go:nosplit
915func stdcall(fn stdFunction) uintptr {
916	gp := getg()
917	mp := gp.m
918	mp.libcall.fn = uintptr(unsafe.Pointer(fn))
919	resetLibcall := false
920	if mp.profilehz != 0 && mp.libcallsp == 0 {
921		// leave pc/sp for cpu profiler
922		mp.libcallg.set(gp)
923		mp.libcallpc = getcallerpc()
924		// sp must be the last, because once async cpu profiler finds
925		// all three values to be non-zero, it will use them
926		mp.libcallsp = getcallersp()
927		resetLibcall = true // See comment in sys_darwin.go:libcCall
928	}
929	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
930	if resetLibcall {
931		mp.libcallsp = 0
932	}
933	return mp.libcall.r1
934}
935
936//go:nosplit
937func stdcall0(fn stdFunction) uintptr {
938	mp := getg().m
939	mp.libcall.n = 0
940	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
941	return stdcall(fn)
942}
943
944//go:nosplit
945func stdcall1(fn stdFunction, a0 uintptr) uintptr {
946	mp := getg().m
947	mp.libcall.n = 1
948	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
949	return stdcall(fn)
950}
951
952//go:nosplit
953func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
954	mp := getg().m
955	mp.libcall.n = 2
956	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
957	return stdcall(fn)
958}
959
960//go:nosplit
961func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
962	mp := getg().m
963	mp.libcall.n = 3
964	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
965	return stdcall(fn)
966}
967
968//go:nosplit
969func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
970	mp := getg().m
971	mp.libcall.n = 4
972	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
973	return stdcall(fn)
974}
975
976//go:nosplit
977func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
978	mp := getg().m
979	mp.libcall.n = 5
980	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
981	return stdcall(fn)
982}
983
984//go:nosplit
985func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
986	mp := getg().m
987	mp.libcall.n = 6
988	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
989	return stdcall(fn)
990}
991
992//go:nosplit
993func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
994	mp := getg().m
995	mp.libcall.n = 7
996	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
997	return stdcall(fn)
998}
999
1000// in sys_windows_386.s and sys_windows_amd64.s
1001func onosstack(fn unsafe.Pointer, arg uint32)
1002func usleep2(usec uint32)
1003func switchtothread()
1004
1005var usleep2Addr unsafe.Pointer
1006var switchtothreadAddr unsafe.Pointer
1007
1008//go:nosplit
1009func osyield() {
1010	onosstack(switchtothreadAddr, 0)
1011}
1012
1013//go:nosplit
1014func usleep(us uint32) {
1015	// Have 1us units; want 100ns units.
1016	onosstack(usleep2Addr, 10*us)
1017}
1018
1019func ctrlhandler1(_type uint32) uint32 {
1020	var s uint32
1021
1022	switch _type {
1023	case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
1024		s = _SIGINT
1025	case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT:
1026		s = _SIGTERM
1027	default:
1028		return 0
1029	}
1030
1031	if sigsend(s) {
1032		return 1
1033	}
1034	exit(2) // SIGINT, SIGTERM, etc
1035	return 0
1036}
1037
1038// in sys_windows_386.s and sys_windows_amd64.s
1039func profileloop()
1040
1041// called from zcallback_windows_*.s to sys_windows_*.s
1042func callbackasm1()
1043
1044var profiletimer uintptr
1045
1046func profilem(mp *m, thread uintptr) {
1047	var r *context
1048	rbuf := make([]byte, unsafe.Sizeof(*r)+15)
1049
1050	// align Context to 16 bytes
1051	r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
1052	r.contextflags = _CONTEXT_CONTROL
1053	stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(r)))
1054
1055	gp := gFromTLS(mp)
1056
1057	sigprof(r.ip(), r.sp(), r.lr(), gp, mp)
1058}
1059
1060func gFromTLS(mp *m) *g {
1061	switch GOARCH {
1062	case "arm":
1063		tls := &mp.tls[0]
1064		return **((***g)(unsafe.Pointer(tls)))
1065	case "386", "amd64":
1066		tls := &mp.tls[0]
1067		return *((**g)(unsafe.Pointer(tls)))
1068	}
1069	throw("unsupported architecture")
1070	return nil
1071}
1072
1073func profileloop1(param uintptr) uint32 {
1074	stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
1075
1076	for {
1077		stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
1078		first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
1079		for mp := first; mp != nil; mp = mp.alllink {
1080			lock(&mp.threadLock)
1081			// Do not profile threads blocked on Notes,
1082			// this includes idle worker threads,
1083			// idle timer thread, idle heap scavenger, etc.
1084			if mp.thread == 0 || mp.profilehz == 0 || mp.blocked {
1085				unlock(&mp.threadLock)
1086				continue
1087			}
1088			// Acquire our own handle to the thread.
1089			var thread uintptr
1090			stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS)
1091			unlock(&mp.threadLock)
1092			// mp may exit between the DuplicateHandle
1093			// above and the SuspendThread. The handle
1094			// will remain valid, but SuspendThread may
1095			// fail.
1096			if int32(stdcall1(_SuspendThread, thread)) == -1 {
1097				// The thread no longer exists.
1098				stdcall1(_CloseHandle, thread)
1099				continue
1100			}
1101			if mp.profilehz != 0 && !mp.blocked {
1102				// Pass the thread handle in case mp
1103				// was in the process of shutting down.
1104				profilem(mp, thread)
1105			}
1106			stdcall1(_ResumeThread, thread)
1107			stdcall1(_CloseHandle, thread)
1108		}
1109	}
1110}
1111
1112func setProcessCPUProfiler(hz int32) {
1113	if profiletimer == 0 {
1114		timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
1115		atomic.Storeuintptr(&profiletimer, timer)
1116		thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
1117		stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
1118		stdcall1(_CloseHandle, thread)
1119	}
1120}
1121
1122func setThreadCPUProfiler(hz int32) {
1123	ms := int32(0)
1124	due := ^int64(^uint64(1 << 63))
1125	if hz > 0 {
1126		ms = 1000 / hz
1127		if ms == 0 {
1128			ms = 1
1129		}
1130		due = int64(ms) * -10000
1131	}
1132	stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
1133	atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
1134}
1135
1136const preemptMSupported = GOARCH != "arm"
1137
1138// suspendLock protects simultaneous SuspendThread operations from
1139// suspending each other.
1140var suspendLock mutex
1141
1142func preemptM(mp *m) {
1143	if GOARCH == "arm" {
1144		// TODO: Implement call injection
1145		return
1146	}
1147
1148	if mp == getg().m {
1149		throw("self-preempt")
1150	}
1151
1152	// Synchronize with external code that may try to ExitProcess.
1153	if !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1154		// External code is running. Fail the preemption
1155		// attempt.
1156		atomic.Xadd(&mp.preemptGen, 1)
1157		return
1158	}
1159
1160	// Acquire our own handle to mp's thread.
1161	lock(&mp.threadLock)
1162	if mp.thread == 0 {
1163		// The M hasn't been minit'd yet (or was just unminit'd).
1164		unlock(&mp.threadLock)
1165		atomic.Store(&mp.preemptExtLock, 0)
1166		atomic.Xadd(&mp.preemptGen, 1)
1167		return
1168	}
1169	var thread uintptr
1170	stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS)
1171	unlock(&mp.threadLock)
1172
1173	// Prepare thread context buffer.
1174	var c *context
1175	cbuf := make([]byte, unsafe.Sizeof(*c)+15)
1176	// Align Context to 16 bytes.
1177	c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1178	c.contextflags = _CONTEXT_CONTROL
1179
1180	// Serialize thread suspension. SuspendThread is asynchronous,
1181	// so it's otherwise possible for two threads to suspend each
1182	// other and deadlock. We must hold this lock until after
1183	// GetThreadContext, since that blocks until the thread is
1184	// actually suspended.
1185	lock(&suspendLock)
1186
1187	// Suspend the thread.
1188	if int32(stdcall1(_SuspendThread, thread)) == -1 {
1189		unlock(&suspendLock)
1190		stdcall1(_CloseHandle, thread)
1191		atomic.Store(&mp.preemptExtLock, 0)
1192		// The thread no longer exists. This shouldn't be
1193		// possible, but just acknowledge the request.
1194		atomic.Xadd(&mp.preemptGen, 1)
1195		return
1196	}
1197
1198	// We have to be very careful between this point and once
1199	// we've shown mp is at an async safe-point. This is like a
1200	// signal handler in the sense that mp could have been doing
1201	// anything when we stopped it, including holding arbitrary
1202	// locks.
1203
1204	// We have to get the thread context before inspecting the M
1205	// because SuspendThread only requests a suspend.
1206	// GetThreadContext actually blocks until it's suspended.
1207	stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1208
1209	unlock(&suspendLock)
1210
1211	// Does it want a preemption and is it safe to preempt?
1212	gp := gFromTLS(mp)
1213	if wantAsyncPreempt(gp) && isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()) {
1214		// Inject call to asyncPreempt
1215		targetPC := funcPC(asyncPreempt)
1216		switch GOARCH {
1217		default:
1218			throw("unsupported architecture")
1219		case "386", "amd64":
1220			// Make it look like the thread called targetPC.
1221			pc := c.ip()
1222			sp := c.sp()
1223			sp -= sys.PtrSize
1224			*(*uintptr)(unsafe.Pointer(sp)) = pc
1225			c.set_sp(sp)
1226			c.set_ip(targetPC)
1227		}
1228
1229		stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1230	}
1231
1232	atomic.Store(&mp.preemptExtLock, 0)
1233
1234	// Acknowledge the preemption.
1235	atomic.Xadd(&mp.preemptGen, 1)
1236
1237	stdcall1(_ResumeThread, thread)
1238	stdcall1(_CloseHandle, thread)
1239}
1240
1241// osPreemptExtEnter is called before entering external code that may
1242// call ExitProcess.
1243//
1244// This must be nosplit because it may be called from a syscall with
1245// untyped stack slots, so the stack must not be grown or scanned.
1246//
1247//go:nosplit
1248func osPreemptExtEnter(mp *m) {
1249	for !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1250		// An asynchronous preemption is in progress. It's not
1251		// safe to enter external code because it may call
1252		// ExitProcess and deadlock with SuspendThread.
1253		// Ideally we would do the preemption ourselves, but
1254		// can't since there may be untyped syscall arguments
1255		// on the stack. Instead, just wait and encourage the
1256		// SuspendThread APC to run. The preemption should be
1257		// done shortly.
1258		osyield()
1259	}
1260	// Asynchronous preemption is now blocked.
1261}
1262
1263// osPreemptExtExit is called after returning from external code that
1264// may call ExitProcess.
1265//
1266// See osPreemptExtEnter for why this is nosplit.
1267//
1268//go:nosplit
1269func osPreemptExtExit(mp *m) {
1270	atomic.Store(&mp.preemptExtLock, 0)
1271}
1272