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