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 "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 getCPUCount() 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 numCPUStartup = getCPUCount()
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
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, resumePC := isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()); ok {
1308
1309 targetPC := abi.FuncPCABI0(asyncPreempt)
1310 c.pushCall(targetPC, resumePC)
1311 stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1312 }
1313 }
1314
1315 atomic.Store(&mp.preemptExtLock, 0)
1316
1317
1318 mp.preemptGen.Add(1)
1319
1320 stdcall1(_ResumeThread, thread)
1321 stdcall1(_CloseHandle, thread)
1322 }
1323
1324
1325
1326
1327
1328
1329
1330
1331 func osPreemptExtEnter(mp *m) {
1332 for !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1333
1334
1335
1336
1337
1338
1339
1340
1341 osyield()
1342 }
1343
1344 }
1345
1346
1347
1348
1349
1350
1351
1352 func osPreemptExtExit(mp *m) {
1353 atomic.Store(&mp.preemptExtLock, 0)
1354 }
1355
View as plain text