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 "runtime/internal/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 _CreateFileA,
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 _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 _RtlGetCurrentPeb stdFunction
137 _RtlGetNtVersionNumbers stdFunction
138
139
140 _timeBeginPeriod,
141 _timeEndPeriod,
142 _WSAGetOverlappedResult,
143 _ stdFunction
144 )
145
146 var (
147 bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0}
148 ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
149 powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
150 winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
151 ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0}
152 )
153
154
155
156 func tstart_stdcall(newm *m)
157
158
159 func wintls()
160
161 type mOS struct {
162 threadLock mutex
163 thread uintptr
164
165 waitsema uintptr
166 resumesema uintptr
167
168 highResTimer uintptr
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191 preemptExtLock uint32
192 }
193
194
195 func open(name *byte, mode, perm int32) int32 {
196 throw("unimplemented")
197 return -1
198 }
199 func closefd(fd int32) int32 {
200 throw("unimplemented")
201 return -1
202 }
203 func read(fd int32, p unsafe.Pointer, n int32) int32 {
204 throw("unimplemented")
205 return -1
206 }
207
208 type sigset struct{}
209
210
211
212 func asmstdcall(fn unsafe.Pointer)
213
214 var asmstdcallAddr unsafe.Pointer
215
216 func windowsFindfunc(lib uintptr, name []byte) stdFunction {
217 if name[len(name)-1] != 0 {
218 throw("usage")
219 }
220 f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
221 return stdFunction(unsafe.Pointer(f))
222 }
223
224 const _MAX_PATH = 260
225 var sysDirectory [_MAX_PATH + 1]byte
226 var sysDirectoryLen uintptr
227
228 func initSysDirectory() {
229 l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
230 if l == 0 || l > uintptr(len(sysDirectory)-1) {
231 throw("Unable to determine system directory")
232 }
233 sysDirectory[l] = '\\'
234 sysDirectoryLen = l + 1
235 }
236
237
238 func windows_GetSystemDirectory() string {
239 return unsafe.String(&sysDirectory[0], sysDirectoryLen)
240 }
241
242 func windowsLoadSystemLib(name []uint16) uintptr {
243 return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
244 }
245
246 func loadOptionalSyscalls() {
247 bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:])
248 if bcryptPrimitives == 0 {
249 throw("bcryptprimitives.dll not found")
250 }
251 _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000"))
252
253 n32 := windowsLoadSystemLib(ntdlldll[:])
254 if n32 == 0 {
255 throw("ntdll.dll not found")
256 }
257 _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
258 _RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000"))
259
260 m32 := windowsLoadSystemLib(winmmdll[:])
261 if m32 == 0 {
262 throw("winmm.dll not found")
263 }
264 _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
265 _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
266 if _timeBeginPeriod == nil || _timeEndPeriod == nil {
267 throw("timeBegin/EndPeriod not found")
268 }
269
270 ws232 := windowsLoadSystemLib(ws2_32dll[:])
271 if ws232 == 0 {
272 throw("ws2_32.dll not found")
273 }
274 _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
275 if _WSAGetOverlappedResult == nil {
276 throw("WSAGetOverlappedResult not found")
277 }
278 }
279
280 func monitorSuspendResume() {
281 const (
282 _DEVICE_NOTIFY_CALLBACK = 2
283 )
284 type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
285 callback uintptr
286 context uintptr
287 }
288
289 powrprof := windowsLoadSystemLib(powrprofdll[:])
290 if powrprof == 0 {
291 return
292 }
293 powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
294 if powerRegisterSuspendResumeNotification == nil {
295 return
296 }
297 var fn any = func(context uintptr, changeType uint32, setting uintptr) uintptr {
298 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
299 if mp.resumesema != 0 {
300 stdcall1(_SetEvent, mp.resumesema)
301 }
302 }
303 return 0
304 }
305 params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
306 callback: compileCallback(*efaceOf(&fn), true),
307 }
308 handle := uintptr(0)
309 stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
310 uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle)))
311 }
312
313
314 func getLoadLibrary() uintptr {
315 return uintptr(unsafe.Pointer(_LoadLibraryW))
316 }
317
318
319 func getLoadLibraryEx() uintptr {
320 return uintptr(unsafe.Pointer(_LoadLibraryExW))
321 }
322
323
324 func getGetProcAddress() uintptr {
325 return uintptr(unsafe.Pointer(_GetProcAddress))
326 }
327
328 func getproccount() int32 {
329 var mask, sysmask uintptr
330 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
331 if ret != 0 {
332 n := 0
333 maskbits := int(unsafe.Sizeof(mask) * 8)
334 for i := 0; i < maskbits; i++ {
335 if mask&(1<<uint(i)) != 0 {
336 n++
337 }
338 }
339 if n != 0 {
340 return int32(n)
341 }
342 }
343
344 var info systeminfo
345 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
346 return int32(info.dwnumberofprocessors)
347 }
348
349 func getPageSize() uintptr {
350 var info systeminfo
351 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
352 return uintptr(info.dwpagesize)
353 }
354
355 const (
356 currentProcess = ^uintptr(0)
357 currentThread = ^uintptr(1)
358 )
359
360
361 func getlasterror() uint32
362
363 var timeBeginPeriodRetValue uint32
364
365
366
367
368
369 const osRelaxMinNS = 60 * 1e6
370
371
372
373
374
375
376
377
378
379
380
381 func osRelax(relax bool) uint32 {
382 if haveHighResTimer {
383
384
385
386 return 0
387 }
388
389 if relax {
390 return uint32(stdcall1(_timeEndPeriod, 1))
391 } else {
392 return uint32(stdcall1(_timeBeginPeriod, 1))
393 }
394 }
395
396
397
398 var haveHighResTimer = false
399
400
401
402
403
404 func createHighResTimer() uintptr {
405 const (
406
407
408 _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002
409
410 _SYNCHRONIZE = 0x00100000
411 _TIMER_QUERY_STATE = 0x0001
412 _TIMER_MODIFY_STATE = 0x0002
413 )
414 return stdcall4(_CreateWaitableTimerExW, 0, 0,
415 _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
416 _SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
417 }
418
419 func initHighResTimer() {
420 h := createHighResTimer()
421 if h != 0 {
422 haveHighResTimer = true
423 stdcall1(_CloseHandle, h)
424 }
425 }
426
427
428 var canUseLongPaths bool
429
430
431
432 var longFileName [(_MAX_PATH+1)*2 + 1]byte
433
434
435
436
437
438
439
440
441
442
443
444 func initLongPathSupport() {
445 const (
446 IsLongPathAwareProcess = 0x80
447 PebBitFieldOffset = 3
448 OPEN_EXISTING = 3
449 ERROR_PATH_NOT_FOUND = 3
450 )
451
452
453 var maj, min, build uint32
454 stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build)))
455 if maj < 10 || (maj == 10 && min == 0 && build&0xffff < 15063) {
456 return
457 }
458
459
460 bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset))
461 originalBitField := *bitField
462 *bitField |= IsLongPathAwareProcess
463
464
465
466
467
468
469
470
471 targ := longFileName[len(longFileName)-33 : len(longFileName)-1]
472 if readRandom(targ) != len(targ) {
473 readTimeRandom(targ)
474 }
475 start := copy(longFileName[:], sysDirectory[:sysDirectoryLen])
476 const dig = "0123456789abcdef"
477 for i := 0; i < 32; i++ {
478 longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4]
479 longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf]
480 }
481 start += 64
482 for i := start; i < len(longFileName)-1; i++ {
483 longFileName[i] = 'A'
484 }
485 stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0)
486
487
488
489 if getlasterror() == ERROR_PATH_NOT_FOUND {
490 *bitField = originalBitField
491 println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode")
492 return
493 }
494
495 canUseLongPaths = true
496 }
497
498 func osinit() {
499 asmstdcallAddr = unsafe.Pointer(abi.FuncPCABI0(asmstdcall))
500
501 loadOptionalSyscalls()
502
503 preventErrorDialogs()
504
505 initExceptionHandler()
506
507 initHighResTimer()
508 timeBeginPeriodRetValue = osRelax(false)
509
510 initSysDirectory()
511 initLongPathSupport()
512
513 ncpu = getproccount()
514
515 physPageSize = getPageSize()
516
517
518
519
520
521 stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
522 }
523
524
525 func readRandom(r []byte) int {
526 n := 0
527 if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
528 n = len(r)
529 }
530 return n
531 }
532
533 func goenvs() {
534
535
536
537 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
538 p := (*[1 << 24]uint16)(strings)[:]
539
540 n := 0
541 for from, i := 0, 0; true; i++ {
542 if p[i] == 0 {
543
544 if i == from {
545 break
546 }
547 from = i + 1
548 n++
549 }
550 }
551 envs = make([]string, n)
552
553 for i := range envs {
554 envs[i] = gostringw(&p[0])
555 for p[0] != 0 {
556 p = p[1:]
557 }
558 p = p[1:]
559 }
560
561 stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
562
563
564
565 var fn any = ctrlHandler
566 ctrlHandlerPC := compileCallback(*efaceOf(&fn), true)
567 stdcall2(_SetConsoleCtrlHandler, ctrlHandlerPC, 1)
568
569 monitorSuspendResume()
570 }
571
572
573 var exiting uint32
574
575
576 func exit(code int32) {
577
578
579
580
581 lock(&suspendLock)
582 atomic.Store(&exiting, 1)
583 stdcall1(_ExitProcess, uintptr(code))
584 }
585
586
587
588
589
590
591 func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
592 const (
593 _STD_OUTPUT_HANDLE = ^uintptr(10)
594 _STD_ERROR_HANDLE = ^uintptr(11)
595 )
596 var handle uintptr
597 switch fd {
598 case 1:
599 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
600 case 2:
601 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
602 default:
603
604 handle = fd
605 }
606 isASCII := true
607 b := (*[1 << 30]byte)(buf)[:n]
608 for _, x := range b {
609 if x >= 0x80 {
610 isASCII = false
611 break
612 }
613 }
614
615 if !isASCII {
616 var m uint32
617 isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
618
619
620 if isConsole {
621 return int32(writeConsole(handle, buf, n))
622 }
623 }
624 var written uint32
625 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
626 return int32(written)
627 }
628
629 var (
630 utf16ConsoleBack [1000]uint16
631 utf16ConsoleBackLock mutex
632 )
633
634
635
636 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
637 const surr2 = (surrogateMin + surrogateMax + 1) / 2
638
639
640 lock(&utf16ConsoleBackLock)
641
642 b := (*[1 << 30]byte)(buf)[:bufLen]
643 s := *(*string)(unsafe.Pointer(&b))
644
645 utf16tmp := utf16ConsoleBack[:]
646
647 total := len(s)
648 w := 0
649 for _, r := range s {
650 if w >= len(utf16tmp)-2 {
651 writeConsoleUTF16(handle, utf16tmp[:w])
652 w = 0
653 }
654 if r < 0x10000 {
655 utf16tmp[w] = uint16(r)
656 w++
657 } else {
658 r -= 0x10000
659 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
660 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
661 w += 2
662 }
663 }
664 writeConsoleUTF16(handle, utf16tmp[:w])
665 unlock(&utf16ConsoleBackLock)
666 return total
667 }
668
669
670
671
672 func writeConsoleUTF16(handle uintptr, b []uint16) {
673 l := uint32(len(b))
674 if l == 0 {
675 return
676 }
677 var written uint32
678 stdcall5(_WriteConsoleW,
679 handle,
680 uintptr(unsafe.Pointer(&b[0])),
681 uintptr(l),
682 uintptr(unsafe.Pointer(&written)),
683 0,
684 )
685 return
686 }
687
688
689 func semasleep(ns int64) int32 {
690 const (
691 _WAIT_ABANDONED = 0x00000080
692 _WAIT_OBJECT_0 = 0x00000000
693 _WAIT_TIMEOUT = 0x00000102
694 _WAIT_FAILED = 0xFFFFFFFF
695 )
696
697 var result uintptr
698 if ns < 0 {
699 result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
700 } else {
701 start := nanotime()
702 elapsed := int64(0)
703 for {
704 ms := int64(timediv(ns-elapsed, 1000000, nil))
705 if ms == 0 {
706 ms = 1
707 }
708 result = stdcall4(_WaitForMultipleObjects, 2,
709 uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
710 0, uintptr(ms))
711 if result != _WAIT_OBJECT_0+1 {
712
713 break
714 }
715 elapsed = nanotime() - start
716 if elapsed >= ns {
717 return -1
718 }
719 }
720 }
721 switch result {
722 case _WAIT_OBJECT_0:
723 return 0
724
725 case _WAIT_TIMEOUT:
726 return -1
727
728 case _WAIT_ABANDONED:
729 systemstack(func() {
730 throw("runtime.semasleep wait_abandoned")
731 })
732
733 case _WAIT_FAILED:
734 systemstack(func() {
735 print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
736 throw("runtime.semasleep wait_failed")
737 })
738
739 default:
740 systemstack(func() {
741 print("runtime: waitforsingleobject unexpected; result=", result, "\n")
742 throw("runtime.semasleep unexpected")
743 })
744 }
745
746 return -1
747 }
748
749
750 func semawakeup(mp *m) {
751 if stdcall1(_SetEvent, mp.waitsema) == 0 {
752 systemstack(func() {
753 print("runtime: setevent failed; errno=", getlasterror(), "\n")
754 throw("runtime.semawakeup")
755 })
756 }
757 }
758
759
760 func semacreate(mp *m) {
761 if mp.waitsema != 0 {
762 return
763 }
764 mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
765 if mp.waitsema == 0 {
766 systemstack(func() {
767 print("runtime: createevent failed; errno=", getlasterror(), "\n")
768 throw("runtime.semacreate")
769 })
770 }
771 mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
772 if mp.resumesema == 0 {
773 systemstack(func() {
774 print("runtime: createevent failed; errno=", getlasterror(), "\n")
775 throw("runtime.semacreate")
776 })
777 stdcall1(_CloseHandle, mp.waitsema)
778 mp.waitsema = 0
779 }
780 }
781
782
783
784
785
786
787
788 func newosproc(mp *m) {
789
790 thandle := stdcall6(_CreateThread, 0, 0,
791 abi.FuncPCABI0(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
792 0, 0)
793
794 if thandle == 0 {
795 if atomic.Load(&exiting) != 0 {
796
797
798
799
800 lock(&deadlock)
801 lock(&deadlock)
802 }
803 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
804 throw("runtime.newosproc")
805 }
806
807
808 stdcall1(_CloseHandle, thandle)
809 }
810
811
812
813
814
815
816
817 func newosproc0(mp *m, stk unsafe.Pointer) {
818
819
820
821 throw("bad newosproc0")
822 }
823
824 func exitThread(wait *atomic.Uint32) {
825
826
827 throw("exitThread")
828 }
829
830
831
832 func mpreinit(mp *m) {
833 }
834
835
836 func sigsave(p *sigset) {
837 }
838
839
840 func msigrestore(sigmask sigset) {
841 }
842
843
844
845 func clearSignalHandlers() {
846 }
847
848
849 func sigblock(exiting bool) {
850 }
851
852
853
854 func minit() {
855 var thandle uintptr
856 if stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
857 print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
858 throw("runtime.minit: duplicatehandle failed")
859 }
860
861 mp := getg().m
862 lock(&mp.threadLock)
863 mp.thread = thandle
864 mp.procid = uint64(stdcall0(_GetCurrentThreadId))
865
866
867 if mp.highResTimer == 0 && haveHighResTimer {
868 mp.highResTimer = createHighResTimer()
869 if mp.highResTimer == 0 {
870 print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
871 throw("CreateWaitableTimerEx when creating timer failed")
872 }
873 }
874 unlock(&mp.threadLock)
875
876
877
878 var mbi memoryBasicInformation
879 res := stdcall3(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
880 if res == 0 {
881 print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
882 throw("VirtualQuery for stack base failed")
883 }
884
885
886
887
888
889
890 base := mbi.allocationBase + 16<<10
891
892 g0 := getg()
893 if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
894 print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
895 throw("bad g0 stack")
896 }
897 g0.stack.lo = base
898 g0.stackguard0 = g0.stack.lo + stackGuard
899 g0.stackguard1 = g0.stackguard0
900
901 stackcheck()
902 }
903
904
905
906
907 func unminit() {
908 mp := getg().m
909 lock(&mp.threadLock)
910 if mp.thread != 0 {
911 stdcall1(_CloseHandle, mp.thread)
912 mp.thread = 0
913 }
914 unlock(&mp.threadLock)
915
916 mp.procid = 0
917 }
918
919
920
921
922
923 func mdestroy(mp *m) {
924 if mp.highResTimer != 0 {
925 stdcall1(_CloseHandle, mp.highResTimer)
926 mp.highResTimer = 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 = getcallerpc()
968
969
970 mp.libcallsp = 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