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