Source file
src/runtime/os_windows.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/runtime/atomic"
10 "internal/runtime/sys"
11 "internal/runtime/syscall/windows"
12 "unsafe"
13 )
14
15
16 const (
17 _NSIG = 65
18 )
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 type stdFunction unsafe.Pointer
72
73 var (
74
75
76
77 _AddVectoredContinueHandler,
78 _AddVectoredExceptionHandler,
79 _CloseHandle,
80 _CreateEventA,
81 _CreateIoCompletionPort,
82 _CreateThread,
83 _CreateWaitableTimerA,
84 _CreateWaitableTimerExW,
85 _DuplicateHandle,
86 _ExitProcess,
87 _FreeEnvironmentStringsW,
88 _GetConsoleMode,
89 _GetCurrentThreadId,
90 _GetEnvironmentStringsW,
91 _GetErrorMode,
92 _GetProcAddress,
93 _GetProcessAffinityMask,
94 _GetQueuedCompletionStatusEx,
95 _GetStdHandle,
96 _GetSystemDirectoryA,
97 _GetSystemInfo,
98 _GetThreadContext,
99 _IsProcessorFeaturePresent,
100 _SetThreadContext,
101 _LoadLibraryExW,
102 _PostQueuedCompletionStatus,
103 _QueryPerformanceCounter,
104 _QueryPerformanceFrequency,
105 _RaiseFailFastException,
106 _ResumeThread,
107 _RtlLookupFunctionEntry,
108 _RtlVirtualUnwind,
109 _SetConsoleCtrlHandler,
110 _SetErrorMode,
111 _SetEvent,
112 _SetProcessPriorityBoost,
113 _SetThreadPriority,
114 _SetUnhandledExceptionFilter,
115 _SetWaitableTimer,
116 _SuspendThread,
117 _SwitchToThread,
118 _VirtualAlloc,
119 _VirtualFree,
120 _VirtualQuery,
121 _WaitForSingleObject,
122 _WaitForMultipleObjects,
123 _WerGetFlags,
124 _WerSetFlags,
125 _WriteConsoleW,
126 _WriteFile,
127 _ stdFunction
128
129
130 _ProcessPrng stdFunction
131
132
133
134 _QueryInterruptTimePrecise stdFunction
135
136
137
138
139 _NtCreateWaitCompletionPacket stdFunction
140 _NtAssociateWaitCompletionPacket stdFunction
141 _NtCancelWaitCompletionPacket stdFunction
142 _RtlGetCurrentPeb stdFunction
143 _RtlGetVersion stdFunction
144
145
146 _timeBeginPeriod,
147 _timeEndPeriod,
148 _ stdFunction
149 )
150
151 var (
152 bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0}
153 ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
154 powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
155 winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
156 realtimeapisetdll = [...]uint16{'a', 'p', 'i', '-', 'm', 's', '-', 'w', 'i', 'n', '-', 'c', 'o', 'r', 'e', '-', 'r', 'e', 'a', 'l', 't', 'i', 'm', 'e', '-', 'l', '1', '-', '1', '-', '1', '.', 'd', 'l', 'l', 0}
157 )
158
159
160
161 func tstart_stdcall(newm *m)
162
163 type mOS struct {
164
165 stdCallInfo windows.StdCallInfo
166
167 threadLock mutex
168 thread uintptr
169
170 waitsema uintptr
171 resumesema uintptr
172
173 highResTimer uintptr
174 waitIocpTimer uintptr
175 waitIocpHandle uintptr
176 }
177
178
179 func open(name *byte, mode, perm int32) int32 {
180 throw("unimplemented")
181 return -1
182 }
183 func closefd(fd int32) int32 {
184 throw("unimplemented")
185 return -1
186 }
187 func read(fd int32, p unsafe.Pointer, n int32) int32 {
188 throw("unimplemented")
189 return -1
190 }
191
192 type sigset struct{}
193
194 var asmstdcallAddr unsafe.Pointer
195
196 type winlibcall windows.StdCallInfo
197
198 func windowsFindfunc(lib uintptr, name []byte) stdFunction {
199 if name[len(name)-1] != 0 {
200 throw("usage")
201 }
202 f := stdcall(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
203 return stdFunction(unsafe.Pointer(f))
204 }
205
206 const _MAX_PATH = 260
207 var sysDirectory [_MAX_PATH + 1]byte
208 var sysDirectoryLen uintptr
209
210 func initSysDirectory() {
211 l := stdcall(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
212 if l == 0 || l > uintptr(len(sysDirectory)-1) {
213 throw("Unable to determine system directory")
214 }
215 sysDirectory[l] = '\\'
216 sysDirectoryLen = l + 1
217 }
218
219
220 func windows_GetSystemDirectory() string {
221 return unsafe.String(&sysDirectory[0], sysDirectoryLen)
222 }
223
224 func windowsLoadSystemLib(name []uint16) uintptr {
225 const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
226 return stdcall(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
227 }
228
229
230 func windows_QueryPerformanceCounter() int64 {
231 var counter int64
232 stdcall(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
233 return counter
234 }
235
236
237 func windows_QueryPerformanceFrequency() int64 {
238 var frequency int64
239 stdcall(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&frequency)))
240 return frequency
241 }
242
243
244
245
246
247
248 func nanotime1() int64 {
249 gp := getg()
250 if gp == nil || gp.m == nil || gp.m.profilehz == 0 || gp.m.libcallsp != 0 {
251 return nanotime2()
252 }
253 mp := gp.m
254 mp.libcallg.set(gp)
255 mp.libcallpc = sys.GetCallerPC()
256
257 mp.libcallsp = sys.GetCallerSP()
258 now := nanotime2()
259 mp.libcallsp = 0
260 return now
261 }
262
263 func nanotime2() int64
264
265
266 func cpu_isProcessorFeaturePresent(processorFeature uint32) bool {
267 ret := stdcall(_IsProcessorFeaturePresent, uintptr(processorFeature))
268 return ret != 0
269 }
270
271 func loadOptionalSyscalls() {
272
273
274
275 realtime := windowsLoadSystemLib(realtimeapisetdll[:])
276 if realtime == 0 {
277 throw("could not load realtime API set")
278 }
279 _QueryInterruptTimePrecise = windowsFindfunc(realtime, []byte("QueryInterruptTimePrecise\000"))
280 if _QueryInterruptTimePrecise == nil {
281 throw("QueryInterruptTimePrecise not found")
282 }
283
284 bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:])
285 if bcryptPrimitives == 0 {
286 throw("bcryptprimitives.dll not found")
287 }
288 _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000"))
289
290 n32 := windowsLoadSystemLib(ntdlldll[:])
291 if n32 == 0 {
292 throw("ntdll.dll not found")
293 }
294 _NtCreateWaitCompletionPacket = windowsFindfunc(n32, []byte("NtCreateWaitCompletionPacket\000"))
295 if _NtCreateWaitCompletionPacket != nil {
296
297 _NtAssociateWaitCompletionPacket = windowsFindfunc(n32, []byte("NtAssociateWaitCompletionPacket\000"))
298 if _NtAssociateWaitCompletionPacket == nil {
299 throw("NtCreateWaitCompletionPacket exists but NtAssociateWaitCompletionPacket does not")
300 }
301 _NtCancelWaitCompletionPacket = windowsFindfunc(n32, []byte("NtCancelWaitCompletionPacket\000"))
302 if _NtCancelWaitCompletionPacket == nil {
303 throw("NtCreateWaitCompletionPacket exists but NtCancelWaitCompletionPacket does not")
304 }
305 }
306 _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
307 _RtlGetVersion = windowsFindfunc(n32, []byte("RtlGetVersion\000"))
308 }
309
310 func monitorSuspendResume() {
311 const (
312 _DEVICE_NOTIFY_CALLBACK = 2
313 )
314 type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
315 callback uintptr
316 context uintptr
317 }
318
319 powrprof := windowsLoadSystemLib(powrprofdll[:])
320 if powrprof == 0 {
321 return
322 }
323 powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
324 if powerRegisterSuspendResumeNotification == nil {
325 return
326 }
327 var fn any = func(context uintptr, changeType uint32, setting uintptr) uintptr {
328 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
329 if mp.resumesema != 0 {
330 stdcall(_SetEvent, mp.resumesema)
331 }
332 }
333 return 0
334 }
335 params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
336 callback: compileCallback(*efaceOf(&fn), true),
337 }
338 handle := uintptr(0)
339 stdcall(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
340 uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle)))
341 }
342
343 func getCPUCount() int32 {
344 var mask, sysmask uintptr
345 ret := stdcall(_GetProcessAffinityMask, windows.CurrentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
346 if ret != 0 {
347 n := 0
348 maskbits := int(unsafe.Sizeof(mask) * 8)
349 for i := 0; i < maskbits; i++ {
350 if mask&(1<<uint(i)) != 0 {
351 n++
352 }
353 }
354 if n != 0 {
355 return int32(n)
356 }
357 }
358
359 var info windows.SystemInfo
360 stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
361 return int32(info.NumberOfProcessors)
362 }
363
364 func getPageSize() uintptr {
365 var info windows.SystemInfo
366 stdcall(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
367 return uintptr(info.PageSize)
368 }
369
370
371 func getlasterror() uint32
372
373 var timeBeginPeriodRetValue uint32
374
375
376
377
378
379 const osRelaxMinNS = 60 * 1e6
380
381
382
383
384
385
386
387
388
389
390
391 func osRelax(relax bool) uint32 {
392 if haveHighResTimer {
393
394
395
396 return 0
397 }
398
399 if relax {
400 return uint32(stdcall(_timeEndPeriod, 1))
401 } else {
402 return uint32(stdcall(_timeBeginPeriod, 1))
403 }
404 }
405
406
407
408 var haveHighResTimer = false
409
410
411
412
413
414
415 var haveHighResSleep = false
416
417
418
419
420
421 func createHighResTimer() uintptr {
422
423
424 return stdcall(_CreateWaitableTimerExW, 0, 0,
425 windows.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
426 windows.SYNCHRONIZE|windows.TIMER_QUERY_STATE|windows.TIMER_MODIFY_STATE)
427 }
428
429 func initHighResTimer() {
430 h := createHighResTimer()
431 if h != 0 {
432 haveHighResTimer = true
433 haveHighResSleep = _NtCreateWaitCompletionPacket != nil
434 stdcall(_CloseHandle, h)
435 } else {
436
437
438
439 m32 := windowsLoadSystemLib(winmmdll[:])
440 if m32 == 0 {
441 print("runtime: LoadLibraryExW failed; errno=", getlasterror(), "\n")
442 throw("winmm.dll not found")
443 }
444 _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
445 _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
446 if _timeBeginPeriod == nil || _timeEndPeriod == nil {
447 print("runtime: GetProcAddress failed; errno=", getlasterror(), "\n")
448 throw("timeBegin/EndPeriod not found")
449 }
450 }
451 }
452
453
454 var canUseLongPaths bool
455
456
457 func initLongPathSupport() {
458 const (
459 IsLongPathAwareProcess = 0x80
460 PebBitFieldOffset = 3
461 )
462
463
464 info := windows.OSVERSIONINFOW{}
465 info.OSVersionInfoSize = uint32(unsafe.Sizeof(info))
466 stdcall(_RtlGetVersion, uintptr(unsafe.Pointer(&info)))
467 if info.MajorVersion < 10 || (info.MajorVersion == 10 && info.MinorVersion == 0 && info.BuildNumber < 15063) {
468 return
469 }
470
471
472
473
474 bitField := (*byte)(unsafe.Pointer(stdcall(_RtlGetCurrentPeb) + PebBitFieldOffset))
475 *bitField |= IsLongPathAwareProcess
476
477 canUseLongPaths = true
478 }
479
480 func osinit() {
481 asmstdcallAddr = unsafe.Pointer(windows.AsmStdCallAddr())
482
483 loadOptionalSyscalls()
484
485 preventErrorDialogs()
486
487 initExceptionHandler()
488
489 initHighResTimer()
490 timeBeginPeriodRetValue = osRelax(false)
491
492 initSysDirectory()
493 initLongPathSupport()
494
495 numCPUStartup = getCPUCount()
496
497 physPageSize = getPageSize()
498
499
500
501
502
503 stdcall(_SetProcessPriorityBoost, windows.CurrentProcess, 1)
504 }
505
506
507 func readRandom(r []byte) int {
508 n := 0
509 if stdcall(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
510 n = len(r)
511 }
512 return n
513 }
514
515 func goenvs() {
516
517
518
519 strings := unsafe.Pointer(stdcall(_GetEnvironmentStringsW))
520 p := (*[1 << 24]uint16)(strings)[:]
521
522 n := 0
523 for from, i := 0, 0; true; i++ {
524 if p[i] == 0 {
525
526 if i == from {
527 break
528 }
529 from = i + 1
530 n++
531 }
532 }
533 envs = make([]string, n)
534
535 for i := range envs {
536 envs[i] = gostringw(&p[0])
537 for p[0] != 0 {
538 p = p[1:]
539 }
540 p = p[1:]
541 }
542
543 stdcall(_FreeEnvironmentStringsW, uintptr(strings))
544
545
546
547 var fn any = ctrlHandler
548 ctrlHandlerPC := compileCallback(*efaceOf(&fn), true)
549 stdcall(_SetConsoleCtrlHandler, ctrlHandlerPC, 1)
550
551 monitorSuspendResume()
552 }
553
554
555 var exiting uint32
556
557
558 func exit(code int32) {
559
560
561
562
563 lock(&suspendLock)
564 atomic.Store(&exiting, 1)
565 stdcall(_ExitProcess, uintptr(code))
566 }
567
568
569
570
571
572
573 func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
574 const (
575 _STD_OUTPUT_HANDLE = ^uintptr(10)
576 _STD_ERROR_HANDLE = ^uintptr(11)
577 )
578 var handle uintptr
579 switch fd {
580 case 1:
581 handle = stdcall(_GetStdHandle, _STD_OUTPUT_HANDLE)
582 case 2:
583 handle = stdcall(_GetStdHandle, _STD_ERROR_HANDLE)
584 default:
585
586 handle = fd
587 }
588 isASCII := true
589 b := (*[1 << 30]byte)(buf)[:n]
590 for _, x := range b {
591 if x >= 0x80 {
592 isASCII = false
593 break
594 }
595 }
596
597 if !isASCII {
598 var m uint32
599 isConsole := stdcall(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
600
601
602 if isConsole {
603 return int32(writeConsole(handle, buf, n))
604 }
605 }
606 var written uint32
607 stdcall(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
608 return int32(written)
609 }
610
611 var (
612 utf16ConsoleBack [1000]uint16
613 utf16ConsoleBackLock mutex
614 )
615
616
617
618 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
619 const surr2 = (surrogateMin + surrogateMax + 1) / 2
620
621
622 lock(&utf16ConsoleBackLock)
623
624 b := (*[1 << 30]byte)(buf)[:bufLen]
625 s := *(*string)(unsafe.Pointer(&b))
626
627 utf16tmp := utf16ConsoleBack[:]
628
629 total := len(s)
630 w := 0
631 for _, r := range s {
632 if w >= len(utf16tmp)-2 {
633 writeConsoleUTF16(handle, utf16tmp[:w])
634 w = 0
635 }
636 if r < 0x10000 {
637 utf16tmp[w] = uint16(r)
638 w++
639 } else {
640 r -= 0x10000
641 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
642 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
643 w += 2
644 }
645 }
646 writeConsoleUTF16(handle, utf16tmp[:w])
647 unlock(&utf16ConsoleBackLock)
648 return total
649 }
650
651
652
653
654 func writeConsoleUTF16(handle uintptr, b []uint16) {
655 l := uint32(len(b))
656 if l == 0 {
657 return
658 }
659 var written uint32
660 stdcall(_WriteConsoleW,
661 handle,
662 uintptr(unsafe.Pointer(&b[0])),
663 uintptr(l),
664 uintptr(unsafe.Pointer(&written)),
665 0,
666 )
667 return
668 }
669
670
671 func semasleep(ns int64) int32 {
672 const (
673 _WAIT_ABANDONED = 0x00000080
674 _WAIT_OBJECT_0 = 0x00000000
675 _WAIT_TIMEOUT = 0x00000102
676 _WAIT_FAILED = 0xFFFFFFFF
677 )
678
679 var result uintptr
680 if ns < 0 {
681 result = stdcall(_WaitForSingleObject, getg().m.waitsema, uintptr(windows.INFINITE))
682 } else {
683 start := nanotime()
684 elapsed := int64(0)
685 for {
686 ms := (ns - elapsed) / 1000000
687 if ms == 0 {
688 ms = 1
689 }
690 result = stdcall(_WaitForMultipleObjects, 2,
691 uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
692 0, uintptr(ms))
693 if result != _WAIT_OBJECT_0+1 {
694
695 break
696 }
697 elapsed = nanotime() - start
698 if elapsed >= ns {
699 return -1
700 }
701 }
702 }
703 switch result {
704 case _WAIT_OBJECT_0:
705 return 0
706
707 case _WAIT_TIMEOUT:
708 return -1
709
710 case _WAIT_ABANDONED:
711 systemstack(func() {
712 throw("runtime.semasleep wait_abandoned")
713 })
714
715 case _WAIT_FAILED:
716 systemstack(func() {
717 print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
718 throw("runtime.semasleep wait_failed")
719 })
720
721 default:
722 systemstack(func() {
723 print("runtime: waitforsingleobject unexpected; result=", result, "\n")
724 throw("runtime.semasleep unexpected")
725 })
726 }
727
728 return -1
729 }
730
731
732 func semawakeup(mp *m) {
733 if stdcall(_SetEvent, mp.waitsema) == 0 {
734 systemstack(func() {
735 print("runtime: setevent failed; errno=", getlasterror(), "\n")
736 throw("runtime.semawakeup")
737 })
738 }
739 }
740
741
742 func semacreate(mp *m) {
743 if mp.waitsema != 0 {
744 return
745 }
746 mp.waitsema = stdcall(_CreateEventA, 0, 0, 0, 0)
747 if mp.waitsema == 0 {
748 systemstack(func() {
749 print("runtime: createevent failed; errno=", getlasterror(), "\n")
750 throw("runtime.semacreate")
751 })
752 }
753 mp.resumesema = stdcall(_CreateEventA, 0, 0, 0, 0)
754 if mp.resumesema == 0 {
755 systemstack(func() {
756 print("runtime: createevent failed; errno=", getlasterror(), "\n")
757 throw("runtime.semacreate")
758 })
759 stdcall(_CloseHandle, mp.waitsema)
760 mp.waitsema = 0
761 }
762 }
763
764
765
766
767 func newosproc(mp *m) {
768
769
770 var thandle uintptr
771 var err uint32
772 systemstack(func() {
773 thandle, err = createThread(0, unsafe.Pointer(abi.FuncPCABI0(tstart_stdcall)), unsafe.Pointer(mp))
774 })
775 if thandle == 0 {
776 if atomic.Load(&exiting) != 0 {
777
778
779
780
781 lock(&deadlock)
782 lock(&deadlock)
783 }
784 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", err, ")\n")
785 throw("runtime.newosproc")
786 }
787
788
789 stdcall(_CloseHandle, thandle)
790 }
791
792
793
794
795
796
797
798
799
800
801 func poll_runtime_startThread(fn func()) {
802
803
804 if atomic.Load(&newmHandoff.haveTemplateThread) == 0 {
805 startTemplateThread()
806 }
807 gp := getg()
808 pc := sys.GetCallerPC()
809 systemstack(func() {
810 mp := acquirem()
811 worker := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, pc, false, waitReasonZero)
812
813 worker.labels = nil
814 thread := allocm(nil, pollStartThread, -1)
815 thread.syncIOWorker = true
816 thread.sigmask = initSigmask
817 thread.lockedExt = 1
818 thread.lockedg.set(worker)
819 worker.lockedm.set(thread)
820 newm1(thread)
821 releasem(mp)
822 })
823 }
824
825
826
827
828
829
830
831 func poll_runtime_threadHandle() uintptr {
832 gp := getg()
833 if !gp.m.syncIOWorker || gp.lockedm.ptr() != gp.m {
834 throw("runtime: not a synchronous I/O worker")
835 }
836 return gp.m.thread
837 }
838
839
840
841 func pollStartThread() {
842 mp := getg().m
843 lock(&sched.lock)
844
845
846 sched.nmidlelocked++
847 globrunqput(mp.lockedg.ptr())
848 startm(nil, false, true)
849 unlock(&sched.lock)
850 mPark()
851 acquirep(mp.nextp.ptr())
852 mp.nextp = 0
853 execute(mp.lockedg.ptr(), false)
854 }
855
856
857
858
859
860
861
862 func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
863 thandle, err := createThread(stacksize, fn, nil)
864 if thandle == 0 {
865 print("runtime: failed to create new OS thread (errno=", err, ")\n")
866 throw("runtime: failed to create new OS thread\n")
867 }
868 stdcall_no_g(_CloseHandle, thandle)
869 }
870
871
872
873
874
875 func createThread(stackSize uintptr, fn unsafe.Pointer, arg unsafe.Pointer) (handle uintptr, err uint32) {
876 for tries := range 20 {
877
878 handle = stdcall_no_g(_CreateThread, 0, stackSize, uintptr(fn), uintptr(arg), 0, 0)
879 if handle == 0 {
880 err = getlasterror()
881 }
882 if handle == 0 && err == windows.ERROR_ACCESS_DENIED {
883
884 usleep_no_g(uint32(tries) * 1000)
885 continue
886 }
887 break
888 }
889 return handle, err
890 }
891
892
893
894 func libpreinit() {}
895
896 func exitThread(wait *atomic.Uint32) {
897
898
899 throw("exitThread")
900 }
901
902
903
904 func mpreinit(mp *m) {
905 }
906
907
908 func sigsave(p *sigset) {
909 }
910
911
912 func msigrestore(sigmask sigset) {
913 }
914
915
916
917 func clearSignalHandlers() {
918 }
919
920
921 func sigblock(exiting bool) {
922 }
923
924
925
926 func minit() {
927 var thandle uintptr
928 if stdcall(_DuplicateHandle, windows.CurrentProcess, windows.CurrentThread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
929 print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
930 throw("runtime.minit: duplicatehandle failed")
931 }
932
933 mp := getg().m
934 lock(&mp.threadLock)
935 mp.thread = thandle
936 mp.procid = uint64(stdcall(_GetCurrentThreadId))
937
938
939 if mp.highResTimer == 0 && haveHighResTimer {
940 mp.highResTimer = createHighResTimer()
941 if mp.highResTimer == 0 {
942 print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
943 throw("CreateWaitableTimerEx when creating timer failed")
944 }
945 }
946 if mp.waitIocpHandle == 0 && haveHighResSleep {
947 mp.waitIocpTimer = createHighResTimer()
948 if mp.waitIocpTimer == 0 {
949 print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
950 throw("CreateWaitableTimerEx when creating timer failed")
951 }
952 const GENERIC_ALL = 0x10000000
953 errno := stdcall(_NtCreateWaitCompletionPacket, uintptr(unsafe.Pointer(&mp.waitIocpHandle)), GENERIC_ALL, 0)
954 if mp.waitIocpHandle == 0 {
955 print("runtime: NtCreateWaitCompletionPacket failed; errno=", errno, "\n")
956 throw("NtCreateWaitCompletionPacket failed")
957 }
958 }
959 unlock(&mp.threadLock)
960
961
962
963 var mbi windows.MemoryBasicInformation
964 res := stdcall(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
965 if res == 0 {
966 print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
967 throw("VirtualQuery for stack base failed")
968 }
969
970
971
972
973
974
975 base := mbi.AllocationBase + 16<<10
976
977 g0 := getg()
978 if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
979 print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
980 throw("bad g0 stack")
981 }
982 g0.stack.lo = base
983 g0.stackguard0 = g0.stack.lo + stackGuard
984 g0.stackguard1 = g0.stackguard0
985
986 stackcheck()
987 }
988
989
990
991
992 func unminit() {
993 mp := getg().m
994 lock(&mp.threadLock)
995 if mp.thread != 0 {
996 stdcall(_CloseHandle, mp.thread)
997 mp.thread = 0
998 }
999 unlock(&mp.threadLock)
1000
1001 mp.procid = 0
1002 }
1003
1004
1005
1006
1007
1008
1009
1010
1011 func mdestroy(mp *m) {
1012 if mp.highResTimer != 0 {
1013 stdcall(_CloseHandle, mp.highResTimer)
1014 mp.highResTimer = 0
1015 }
1016 if mp.waitIocpTimer != 0 {
1017 stdcall(_CloseHandle, mp.waitIocpTimer)
1018 mp.waitIocpTimer = 0
1019 }
1020 if mp.waitIocpHandle != 0 {
1021 stdcall(_CloseHandle, mp.waitIocpHandle)
1022 mp.waitIocpHandle = 0
1023 }
1024 if mp.waitsema != 0 {
1025 stdcall(_CloseHandle, mp.waitsema)
1026 mp.waitsema = 0
1027 }
1028 if mp.resumesema != 0 {
1029 stdcall(_CloseHandle, mp.resumesema)
1030 mp.resumesema = 0
1031 }
1032 }
1033
1034
1035
1036
1037
1038
1039 func stdcall_no_g(fn stdFunction, args ...uintptr) uintptr {
1040 call := windows.StdCallInfo{
1041 Fn: uintptr(unsafe.Pointer(fn)),
1042 N: uintptr(len(args)),
1043 }
1044 if len(args) > 0 {
1045 call.Args = uintptr(abi.NoEscape(unsafe.Pointer(&args[0])))
1046 }
1047 windows.StdCall(&call)
1048 return call.R1
1049 }
1050
1051
1052
1053
1054
1055
1056
1057
1058 func stdcall(fn stdFunction, args ...uintptr) uintptr {
1059 gp := getg()
1060 mp := gp.m
1061 mp.stdCallInfo.Fn = uintptr(unsafe.Pointer(fn))
1062 mp.stdCallInfo.N = uintptr(len(args))
1063 if len(args) > 0 {
1064 mp.stdCallInfo.Args = uintptr(abi.NoEscape(unsafe.Pointer(&args[0])))
1065 }
1066 resetLibcall := false
1067 if mp.profilehz != 0 && mp.libcallsp == 0 {
1068
1069 mp.libcallg.set(gp)
1070 mp.libcallpc = sys.GetCallerPC()
1071
1072
1073 mp.libcallsp = sys.GetCallerSP()
1074 resetLibcall = true
1075 }
1076 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.stdCallInfo))
1077 if resetLibcall {
1078 mp.libcallsp = 0
1079 }
1080 return mp.stdCallInfo.R1
1081 }
1082
1083
1084
1085
1086 func osyield_no_g() {
1087 stdcall_no_g(_SwitchToThread)
1088 }
1089
1090
1091 func osyield() {
1092 systemstack(func() {
1093 stdcall(_SwitchToThread)
1094 })
1095 }
1096
1097
1098 func usleep_no_g(us uint32) {
1099 timeout := uintptr(us) / 1000
1100 stdcall_no_g(_WaitForSingleObject, windows.INVALID_HANDLE_VALUE, timeout)
1101 }
1102
1103
1104 func usleep(us uint32) {
1105 systemstack(func() {
1106 var h, timeout uintptr
1107
1108
1109 if haveHighResTimer && getg().m.highResTimer != 0 {
1110 h = getg().m.highResTimer
1111 dt := -10 * int64(us)
1112 stdcall(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
1113 timeout = windows.INFINITE
1114 } else {
1115 h = windows.INVALID_HANDLE_VALUE
1116 timeout = uintptr(us) / 1000
1117 }
1118 stdcall(_WaitForSingleObject, h, timeout)
1119 })
1120 }
1121
1122 func ctrlHandler(_type uint32) uintptr {
1123 var s uint32
1124
1125 switch _type {
1126 case windows.CTRL_C_EVENT, windows.CTRL_BREAK_EVENT:
1127 s = windows.SIGINT
1128 case windows.CTRL_CLOSE_EVENT, windows.CTRL_LOGOFF_EVENT, windows.CTRL_SHUTDOWN_EVENT:
1129 s = windows.SIGTERM
1130 default:
1131 return 0
1132 }
1133
1134 if sigsend(s) {
1135 if s == windows.SIGTERM {
1136
1137
1138
1139
1140 block()
1141 }
1142 return 1
1143 }
1144 return 0
1145 }
1146
1147
1148 func callbackasm1()
1149
1150 var profiletimer uintptr
1151
1152 func profilem(mp *m, thread uintptr) {
1153
1154 var c *windows.Context
1155 var cbuf [unsafe.Sizeof(*c) + 15]byte
1156 c = (*windows.Context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1157
1158 c.ContextFlags = windows.CONTEXT_CONTROL
1159 stdcall(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1160
1161 gp := gFromSP(mp, c.SP())
1162
1163 sigprof(c.PC(), c.SP(), c.LR(), gp, mp)
1164 }
1165
1166 func gFromSP(mp *m, sp uintptr) *g {
1167 if gp := mp.g0; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1168 return gp
1169 }
1170 if gp := mp.gsignal; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1171 return gp
1172 }
1173 if gp := mp.curg; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1174 return gp
1175 }
1176 return nil
1177 }
1178
1179 func profileLoop() {
1180 stdcall(_SetThreadPriority, windows.CurrentThread, windows.THREAD_PRIORITY_HIGHEST)
1181
1182 for {
1183 stdcall(_WaitForSingleObject, profiletimer, windows.INFINITE)
1184 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
1185 for mp := first; mp != nil; mp = mp.alllink {
1186 if mp == getg().m {
1187
1188 continue
1189 }
1190
1191 lock(&mp.threadLock)
1192
1193
1194
1195 if mp.thread == 0 || mp.profilehz == 0 || mp.blocked {
1196 unlock(&mp.threadLock)
1197 continue
1198 }
1199
1200 var thread uintptr
1201 if stdcall(_DuplicateHandle, windows.CurrentProcess, mp.thread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
1202 print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
1203 throw("duplicatehandle failed")
1204 }
1205 unlock(&mp.threadLock)
1206
1207
1208
1209
1210
1211 if int32(stdcall(_SuspendThread, thread)) == -1 {
1212
1213 stdcall(_CloseHandle, thread)
1214 continue
1215 }
1216 if mp.profilehz != 0 && !mp.blocked {
1217
1218
1219 profilem(mp, thread)
1220 }
1221 stdcall(_ResumeThread, thread)
1222 stdcall(_CloseHandle, thread)
1223 }
1224 }
1225 }
1226
1227 func setProcessCPUProfiler(hz int32) {
1228 if profiletimer == 0 {
1229 var timer uintptr
1230 if haveHighResTimer {
1231 timer = createHighResTimer()
1232 if timer != 0 && !profileTimerSupportsPeriod(timer) {
1233
1234
1235
1236
1237
1238
1239 stdcall(_CloseHandle, timer)
1240 timer = 0
1241 }
1242 }
1243 if timer == 0 {
1244 timer = stdcall(_CreateWaitableTimerA, 0, 0, 0)
1245 }
1246 atomic.Storeuintptr(&profiletimer, timer)
1247 newm(profileLoop, nil, -1)
1248 }
1249 }
1250
1251
1252
1253
1254
1255 func profileTimerSupportsPeriod(timer uintptr) bool {
1256 due := int64(-10000)
1257 return stdcall(_SetWaitableTimer, timer, uintptr(unsafe.Pointer(&due)), 1, 0, 0, 0) != 0
1258 }
1259
1260 func setThreadCPUProfiler(hz int32) {
1261 ms := int32(0)
1262 due := ^int64(^uint64(1 << 63))
1263 if hz > 0 {
1264 ms = 1000 / hz
1265 if ms == 0 {
1266 ms = 1
1267 }
1268 due = int64(ms) * -10000
1269 }
1270 stdcall(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
1271 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
1272 }
1273
1274 const preemptMSupported = true
1275
1276
1277
1278 var suspendLock mutex
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295 const threadPausedLockRank = lockRankLeafRank
1296
1297
1298
1299
1300
1301 func preemptM(gp *g) {
1302 mp := gp.m
1303 if mp == getg().m {
1304 throw("self-preempt")
1305 }
1306
1307
1308
1309
1310
1311
1312
1313 lock(&mp.threadLock)
1314 if mp.thread == 0 {
1315
1316 unlock(&mp.threadLock)
1317 casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
1318 mp.preemptGen.Add(1)
1319 return
1320 }
1321 var thread uintptr
1322 if stdcall(_DuplicateHandle, windows.CurrentProcess, mp.thread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
1323 print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
1324 throw("runtime.preemptM: duplicatehandle failed")
1325 }
1326 unlock(&mp.threadLock)
1327
1328
1329 var c *windows.Context
1330 var cbuf [unsafe.Sizeof(*c) + 15]byte
1331 c = (*windows.Context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1332
1333 c.ContextFlags = windows.CONTEXT_CONTROL | windows.CONTEXT_EXCEPTION_REQUEST
1334
1335
1336
1337
1338
1339
1340 lock(&suspendLock)
1341
1342
1343 acquireLockRankAndM(threadPausedLockRank)
1344
1345
1346 if int32(stdcall(_SuspendThread, thread)) == -1 {
1347 unlock(&suspendLock)
1348 stdcall(_CloseHandle, thread)
1349
1350
1351 mp.preemptGen.Add(1)
1352 releaseLockRankAndM(threadPausedLockRank)
1353 casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
1354 return
1355 }
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366 stdcall(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1367
1368 unlock(&suspendLock)
1369
1370
1371
1372
1373 safe := c.ContextFlags&windows.CONTEXT_EXCEPTION_REPORTING != 0 &&
1374 c.ContextFlags&(windows.CONTEXT_EXCEPTION_ACTIVE|windows.CONTEXT_SERVICE_ACTIVE) == 0
1375 c.ContextFlags = windows.CONTEXT_CONTROL
1376
1377
1378 if safe && gFromSP(mp, c.SP()) == gp {
1379 if ok, resumePC := isAsyncSafePoint(gp, c.PC(), c.SP(), c.LR()); ok {
1380
1381 targetPC := abi.FuncPCABI0(asyncPreempt)
1382 c.PushCall(targetPC, resumePC)
1383 stdcall(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1384 }
1385 }
1386
1387
1388 mp.preemptGen.Add(1)
1389
1390 stdcall(_ResumeThread, thread)
1391 stdcall(_CloseHandle, thread)
1392
1393 releaseLockRankAndM(threadPausedLockRank)
1394 casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
1395 }
1396
View as plain text