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