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 func mdestroy(mp *m) {
914 if mp.highResTimer != 0 {
915 stdcall1(_CloseHandle, mp.highResTimer)
916 mp.highResTimer = 0
917 }
918 if mp.waitIocpTimer != 0 {
919 stdcall1(_CloseHandle, mp.waitIocpTimer)
920 mp.waitIocpTimer = 0
921 }
922 if mp.waitIocpHandle != 0 {
923 stdcall1(_CloseHandle, mp.waitIocpHandle)
924 mp.waitIocpHandle = 0
925 }
926 if mp.waitsema != 0 {
927 stdcall1(_CloseHandle, mp.waitsema)
928 mp.waitsema = 0
929 }
930 if mp.resumesema != 0 {
931 stdcall1(_CloseHandle, mp.resumesema)
932 mp.resumesema = 0
933 }
934 }
935
936
937 func asmstdcall_trampoline(args unsafe.Pointer)
938
939
940
941
942 func stdcall_no_g(fn stdFunction, n int, args uintptr) uintptr {
943 libcall := libcall{
944 fn: uintptr(unsafe.Pointer(fn)),
945 n: uintptr(n),
946 args: args,
947 }
948 asmstdcall_trampoline(noescape(unsafe.Pointer(&libcall)))
949 return libcall.r1
950 }
951
952
953
954
955
956
957 func stdcall(fn stdFunction) uintptr {
958 gp := getg()
959 mp := gp.m
960 mp.libcall.fn = uintptr(unsafe.Pointer(fn))
961 resetLibcall := false
962 if mp.profilehz != 0 && mp.libcallsp == 0 {
963
964 mp.libcallg.set(gp)
965 mp.libcallpc = sys.GetCallerPC()
966
967
968 mp.libcallsp = sys.GetCallerSP()
969 resetLibcall = true
970 }
971 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
972 if resetLibcall {
973 mp.libcallsp = 0
974 }
975 return mp.libcall.r1
976 }
977
978
979 func stdcall0(fn stdFunction) uintptr {
980 mp := getg().m
981 mp.libcall.n = 0
982 mp.libcall.args = 0
983 return stdcall(fn)
984 }
985
986
987
988 func stdcall1(fn stdFunction, a0 uintptr) uintptr {
989 mp := getg().m
990 mp.libcall.n = 1
991 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
992 return stdcall(fn)
993 }
994
995
996
997 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
998 mp := getg().m
999 mp.libcall.n = 2
1000 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1001 return stdcall(fn)
1002 }
1003
1004
1005
1006 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
1007 mp := getg().m
1008 mp.libcall.n = 3
1009 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1010 return stdcall(fn)
1011 }
1012
1013
1014
1015 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
1016 mp := getg().m
1017 mp.libcall.n = 4
1018 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1019 return stdcall(fn)
1020 }
1021
1022
1023
1024 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
1025 mp := getg().m
1026 mp.libcall.n = 5
1027 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1028 return stdcall(fn)
1029 }
1030
1031
1032
1033 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
1034 mp := getg().m
1035 mp.libcall.n = 6
1036 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1037 return stdcall(fn)
1038 }
1039
1040
1041
1042 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
1043 mp := getg().m
1044 mp.libcall.n = 7
1045 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1046 return stdcall(fn)
1047 }
1048
1049
1050
1051 func stdcall8(fn stdFunction, a0, a1, a2, a3, a4, a5, a6, a7 uintptr) uintptr {
1052 mp := getg().m
1053 mp.libcall.n = 8
1054 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1055 return stdcall(fn)
1056 }
1057
1058
1059
1060
1061 func osyield_no_g() {
1062 stdcall_no_g(_SwitchToThread, 0, 0)
1063 }
1064
1065
1066 func osyield() {
1067 systemstack(func() {
1068 stdcall0(_SwitchToThread)
1069 })
1070 }
1071
1072
1073 func usleep_no_g(us uint32) {
1074 timeout := uintptr(us) / 1000
1075 args := [...]uintptr{_INVALID_HANDLE_VALUE, timeout}
1076 stdcall_no_g(_WaitForSingleObject, len(args), uintptr(noescape(unsafe.Pointer(&args[0]))))
1077 }
1078
1079
1080 func usleep(us uint32) {
1081 systemstack(func() {
1082 var h, timeout uintptr
1083
1084
1085 if haveHighResTimer && getg().m.highResTimer != 0 {
1086 h = getg().m.highResTimer
1087 dt := -10 * int64(us)
1088 stdcall6(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
1089 timeout = _INFINITE
1090 } else {
1091 h = _INVALID_HANDLE_VALUE
1092 timeout = uintptr(us) / 1000
1093 }
1094 stdcall2(_WaitForSingleObject, h, timeout)
1095 })
1096 }
1097
1098 func ctrlHandler(_type uint32) uintptr {
1099 var s uint32
1100
1101 switch _type {
1102 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
1103 s = _SIGINT
1104 case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT:
1105 s = _SIGTERM
1106 default:
1107 return 0
1108 }
1109
1110 if sigsend(s) {
1111 if s == _SIGTERM {
1112
1113
1114
1115
1116 block()
1117 }
1118 return 1
1119 }
1120 return 0
1121 }
1122
1123
1124 func callbackasm1()
1125
1126 var profiletimer uintptr
1127
1128 func profilem(mp *m, thread uintptr) {
1129
1130 var c *context
1131 var cbuf [unsafe.Sizeof(*c) + 15]byte
1132 c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1133
1134 c.contextflags = _CONTEXT_CONTROL
1135 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1136
1137 gp := gFromSP(mp, c.sp())
1138
1139 sigprof(c.ip(), c.sp(), c.lr(), gp, mp)
1140 }
1141
1142 func gFromSP(mp *m, sp uintptr) *g {
1143 if gp := mp.g0; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1144 return gp
1145 }
1146 if gp := mp.gsignal; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1147 return gp
1148 }
1149 if gp := mp.curg; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1150 return gp
1151 }
1152 return nil
1153 }
1154
1155 func profileLoop() {
1156 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
1157
1158 for {
1159 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
1160 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
1161 for mp := first; mp != nil; mp = mp.alllink {
1162 if mp == getg().m {
1163
1164 continue
1165 }
1166
1167 lock(&mp.threadLock)
1168
1169
1170
1171 if mp.thread == 0 || mp.profilehz == 0 || mp.blocked {
1172 unlock(&mp.threadLock)
1173 continue
1174 }
1175
1176 var thread uintptr
1177 if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
1178 print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
1179 throw("duplicatehandle failed")
1180 }
1181 unlock(&mp.threadLock)
1182
1183
1184
1185
1186
1187 if int32(stdcall1(_SuspendThread, thread)) == -1 {
1188
1189 stdcall1(_CloseHandle, thread)
1190 continue
1191 }
1192 if mp.profilehz != 0 && !mp.blocked {
1193
1194
1195 profilem(mp, thread)
1196 }
1197 stdcall1(_ResumeThread, thread)
1198 stdcall1(_CloseHandle, thread)
1199 }
1200 }
1201 }
1202
1203 func setProcessCPUProfiler(hz int32) {
1204 if profiletimer == 0 {
1205 var timer uintptr
1206 if haveHighResTimer {
1207 timer = createHighResTimer()
1208 } else {
1209 timer = stdcall3(_CreateWaitableTimerA, 0, 0, 0)
1210 }
1211 atomic.Storeuintptr(&profiletimer, timer)
1212 newm(profileLoop, nil, -1)
1213 }
1214 }
1215
1216 func setThreadCPUProfiler(hz int32) {
1217 ms := int32(0)
1218 due := ^int64(^uint64(1 << 63))
1219 if hz > 0 {
1220 ms = 1000 / hz
1221 if ms == 0 {
1222 ms = 1
1223 }
1224 due = int64(ms) * -10000
1225 }
1226 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
1227 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
1228 }
1229
1230 const preemptMSupported = true
1231
1232
1233
1234 var suspendLock mutex
1235
1236 func preemptM(mp *m) {
1237 if mp == getg().m {
1238 throw("self-preempt")
1239 }
1240
1241
1242 if !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1243
1244
1245 mp.preemptGen.Add(1)
1246 return
1247 }
1248
1249
1250 lock(&mp.threadLock)
1251 if mp.thread == 0 {
1252
1253 unlock(&mp.threadLock)
1254 atomic.Store(&mp.preemptExtLock, 0)
1255 mp.preemptGen.Add(1)
1256 return
1257 }
1258 var thread uintptr
1259 if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
1260 print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
1261 throw("runtime.preemptM: duplicatehandle failed")
1262 }
1263 unlock(&mp.threadLock)
1264
1265
1266 var c *context
1267 var cbuf [unsafe.Sizeof(*c) + 15]byte
1268 c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1269 c.contextflags = _CONTEXT_CONTROL
1270
1271
1272
1273
1274
1275
1276 lock(&suspendLock)
1277
1278
1279 if int32(stdcall1(_SuspendThread, thread)) == -1 {
1280 unlock(&suspendLock)
1281 stdcall1(_CloseHandle, thread)
1282 atomic.Store(&mp.preemptExtLock, 0)
1283
1284
1285 mp.preemptGen.Add(1)
1286 return
1287 }
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1299
1300 unlock(&suspendLock)
1301
1302
1303 gp := gFromSP(mp, c.sp())
1304 if gp != nil && wantAsyncPreempt(gp) {
1305 if ok, newpc := isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()); ok {
1306
1307 targetPC := abi.FuncPCABI0(asyncPreempt)
1308 switch GOARCH {
1309 default:
1310 throw("unsupported architecture")
1311 case "386", "amd64":
1312
1313 sp := c.sp()
1314 sp -= goarch.PtrSize
1315 *(*uintptr)(unsafe.Pointer(sp)) = newpc
1316 c.set_sp(sp)
1317 c.set_ip(targetPC)
1318
1319 case "arm":
1320
1321
1322
1323
1324
1325 sp := c.sp()
1326 sp -= goarch.PtrSize
1327 c.set_sp(sp)
1328 *(*uint32)(unsafe.Pointer(sp)) = uint32(c.lr())
1329 c.set_lr(newpc - 1)
1330 c.set_ip(targetPC)
1331
1332 case "arm64":
1333
1334
1335
1336
1337 sp := c.sp() - 16
1338 c.set_sp(sp)
1339 *(*uint64)(unsafe.Pointer(sp)) = uint64(c.lr())
1340 c.set_lr(newpc)
1341 c.set_ip(targetPC)
1342 }
1343 stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1344 }
1345 }
1346
1347 atomic.Store(&mp.preemptExtLock, 0)
1348
1349
1350 mp.preemptGen.Add(1)
1351
1352 stdcall1(_ResumeThread, thread)
1353 stdcall1(_CloseHandle, thread)
1354 }
1355
1356
1357
1358
1359
1360
1361
1362
1363 func osPreemptExtEnter(mp *m) {
1364 for !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1365
1366
1367
1368
1369
1370
1371
1372
1373 osyield()
1374 }
1375
1376 }
1377
1378
1379
1380
1381
1382
1383
1384 func osPreemptExtExit(mp *m) {
1385 atomic.Store(&mp.preemptExtLock, 0)
1386 }
1387
View as plain text