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(mp *m, stk unsafe.Pointer) {
781
782
783
784 throw("bad newosproc0")
785 }
786
787 func exitThread(wait *atomic.Uint32) {
788
789
790 throw("exitThread")
791 }
792
793
794
795 func mpreinit(mp *m) {
796 }
797
798
799 func sigsave(p *sigset) {
800 }
801
802
803 func msigrestore(sigmask sigset) {
804 }
805
806
807
808 func clearSignalHandlers() {
809 }
810
811
812 func sigblock(exiting bool) {
813 }
814
815
816
817 func minit() {
818 var thandle uintptr
819 if stdcall(_DuplicateHandle, windows.CurrentProcess, windows.CurrentThread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
820 print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
821 throw("runtime.minit: duplicatehandle failed")
822 }
823
824 mp := getg().m
825 lock(&mp.threadLock)
826 mp.thread = thandle
827 mp.procid = uint64(stdcall(_GetCurrentThreadId))
828
829
830 if mp.highResTimer == 0 && haveHighResTimer {
831 mp.highResTimer = createHighResTimer()
832 if mp.highResTimer == 0 {
833 print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
834 throw("CreateWaitableTimerEx when creating timer failed")
835 }
836 }
837 if mp.waitIocpHandle == 0 && haveHighResSleep {
838 mp.waitIocpTimer = createHighResTimer()
839 if mp.waitIocpTimer == 0 {
840 print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
841 throw("CreateWaitableTimerEx when creating timer failed")
842 }
843 const GENERIC_ALL = 0x10000000
844 errno := stdcall(_NtCreateWaitCompletionPacket, uintptr(unsafe.Pointer(&mp.waitIocpHandle)), GENERIC_ALL, 0)
845 if mp.waitIocpHandle == 0 {
846 print("runtime: NtCreateWaitCompletionPacket failed; errno=", errno, "\n")
847 throw("NtCreateWaitCompletionPacket failed")
848 }
849 }
850 unlock(&mp.threadLock)
851
852
853
854 var mbi windows.MemoryBasicInformation
855 res := stdcall(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
856 if res == 0 {
857 print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
858 throw("VirtualQuery for stack base failed")
859 }
860
861
862
863
864
865
866 base := mbi.AllocationBase + 16<<10
867
868 g0 := getg()
869 if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
870 print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
871 throw("bad g0 stack")
872 }
873 g0.stack.lo = base
874 g0.stackguard0 = g0.stack.lo + stackGuard
875 g0.stackguard1 = g0.stackguard0
876
877 stackcheck()
878 }
879
880
881
882
883 func unminit() {
884 mp := getg().m
885 lock(&mp.threadLock)
886 if mp.thread != 0 {
887 stdcall(_CloseHandle, mp.thread)
888 mp.thread = 0
889 }
890 unlock(&mp.threadLock)
891
892 mp.procid = 0
893 }
894
895
896
897
898
899
900
901
902 func mdestroy(mp *m) {
903 if mp.highResTimer != 0 {
904 stdcall(_CloseHandle, mp.highResTimer)
905 mp.highResTimer = 0
906 }
907 if mp.waitIocpTimer != 0 {
908 stdcall(_CloseHandle, mp.waitIocpTimer)
909 mp.waitIocpTimer = 0
910 }
911 if mp.waitIocpHandle != 0 {
912 stdcall(_CloseHandle, mp.waitIocpHandle)
913 mp.waitIocpHandle = 0
914 }
915 if mp.waitsema != 0 {
916 stdcall(_CloseHandle, mp.waitsema)
917 mp.waitsema = 0
918 }
919 if mp.resumesema != 0 {
920 stdcall(_CloseHandle, mp.resumesema)
921 mp.resumesema = 0
922 }
923 }
924
925
926
927
928
929
930 func stdcall_no_g(fn stdFunction, args ...uintptr) uintptr {
931 call := windows.StdCallInfo{
932 Fn: uintptr(unsafe.Pointer(fn)),
933 N: uintptr(len(args)),
934 }
935 if len(args) > 0 {
936 call.Args = uintptr(abi.NoEscape(unsafe.Pointer(&args[0])))
937 }
938 windows.StdCall(&call)
939 return call.R1
940 }
941
942
943
944
945
946
947
948
949 func stdcall(fn stdFunction, args ...uintptr) uintptr {
950 gp := getg()
951 mp := gp.m
952 mp.stdCallInfo.Fn = uintptr(unsafe.Pointer(fn))
953 mp.stdCallInfo.N = uintptr(len(args))
954 if len(args) > 0 {
955 mp.stdCallInfo.Args = uintptr(abi.NoEscape(unsafe.Pointer(&args[0])))
956 }
957 resetLibcall := false
958 if mp.profilehz != 0 && mp.libcallsp == 0 {
959
960 mp.libcallg.set(gp)
961 mp.libcallpc = sys.GetCallerPC()
962
963
964 mp.libcallsp = sys.GetCallerSP()
965 resetLibcall = true
966 }
967 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.stdCallInfo))
968 if resetLibcall {
969 mp.libcallsp = 0
970 }
971 return mp.stdCallInfo.R1
972 }
973
974
975
976
977 func osyield_no_g() {
978 stdcall_no_g(_SwitchToThread)
979 }
980
981
982 func osyield() {
983 systemstack(func() {
984 stdcall(_SwitchToThread)
985 })
986 }
987
988
989 func usleep_no_g(us uint32) {
990 timeout := uintptr(us) / 1000
991 stdcall_no_g(_WaitForSingleObject, windows.INVALID_HANDLE_VALUE, timeout)
992 }
993
994
995 func usleep(us uint32) {
996 systemstack(func() {
997 var h, timeout uintptr
998
999
1000 if haveHighResTimer && getg().m.highResTimer != 0 {
1001 h = getg().m.highResTimer
1002 dt := -10 * int64(us)
1003 stdcall(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
1004 timeout = windows.INFINITE
1005 } else {
1006 h = windows.INVALID_HANDLE_VALUE
1007 timeout = uintptr(us) / 1000
1008 }
1009 stdcall(_WaitForSingleObject, h, timeout)
1010 })
1011 }
1012
1013 func ctrlHandler(_type uint32) uintptr {
1014 var s uint32
1015
1016 switch _type {
1017 case windows.CTRL_C_EVENT, windows.CTRL_BREAK_EVENT:
1018 s = windows.SIGINT
1019 case windows.CTRL_CLOSE_EVENT, windows.CTRL_LOGOFF_EVENT, windows.CTRL_SHUTDOWN_EVENT:
1020 s = windows.SIGTERM
1021 default:
1022 return 0
1023 }
1024
1025 if sigsend(s) {
1026 if s == windows.SIGTERM {
1027
1028
1029
1030
1031 block()
1032 }
1033 return 1
1034 }
1035 return 0
1036 }
1037
1038
1039 func callbackasm1()
1040
1041 var profiletimer uintptr
1042
1043 func profilem(mp *m, thread uintptr) {
1044
1045 var c *windows.Context
1046 var cbuf [unsafe.Sizeof(*c) + 15]byte
1047 c = (*windows.Context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1048
1049 c.ContextFlags = windows.CONTEXT_CONTROL
1050 stdcall(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1051
1052 gp := gFromSP(mp, c.SP())
1053
1054 sigprof(c.PC(), c.SP(), c.LR(), gp, mp)
1055 }
1056
1057 func gFromSP(mp *m, sp uintptr) *g {
1058 if gp := mp.g0; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1059 return gp
1060 }
1061 if gp := mp.gsignal; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1062 return gp
1063 }
1064 if gp := mp.curg; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1065 return gp
1066 }
1067 return nil
1068 }
1069
1070 func profileLoop() {
1071 stdcall(_SetThreadPriority, windows.CurrentThread, windows.THREAD_PRIORITY_HIGHEST)
1072
1073 for {
1074 stdcall(_WaitForSingleObject, profiletimer, windows.INFINITE)
1075 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
1076 for mp := first; mp != nil; mp = mp.alllink {
1077 if mp == getg().m {
1078
1079 continue
1080 }
1081
1082 lock(&mp.threadLock)
1083
1084
1085
1086 if mp.thread == 0 || mp.profilehz == 0 || mp.blocked {
1087 unlock(&mp.threadLock)
1088 continue
1089 }
1090
1091 var thread uintptr
1092 if stdcall(_DuplicateHandle, windows.CurrentProcess, mp.thread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
1093 print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
1094 throw("duplicatehandle failed")
1095 }
1096 unlock(&mp.threadLock)
1097
1098
1099
1100
1101
1102 if int32(stdcall(_SuspendThread, thread)) == -1 {
1103
1104 stdcall(_CloseHandle, thread)
1105 continue
1106 }
1107 if mp.profilehz != 0 && !mp.blocked {
1108
1109
1110 profilem(mp, thread)
1111 }
1112 stdcall(_ResumeThread, thread)
1113 stdcall(_CloseHandle, thread)
1114 }
1115 }
1116 }
1117
1118 func setProcessCPUProfiler(hz int32) {
1119 if profiletimer == 0 {
1120 var timer uintptr
1121 if haveHighResTimer {
1122 timer = createHighResTimer()
1123 } else {
1124 timer = stdcall(_CreateWaitableTimerA, 0, 0, 0)
1125 }
1126 atomic.Storeuintptr(&profiletimer, timer)
1127 newm(profileLoop, nil, -1)
1128 }
1129 }
1130
1131 func setThreadCPUProfiler(hz int32) {
1132 ms := int32(0)
1133 due := ^int64(^uint64(1 << 63))
1134 if hz > 0 {
1135 ms = 1000 / hz
1136 if ms == 0 {
1137 ms = 1
1138 }
1139 due = int64(ms) * -10000
1140 }
1141 stdcall(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
1142 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
1143 }
1144
1145 const preemptMSupported = true
1146
1147
1148
1149 var suspendLock mutex
1150
1151 func preemptM(mp *m) {
1152 if mp == getg().m {
1153 throw("self-preempt")
1154 }
1155
1156
1157 if !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1158
1159
1160 mp.preemptGen.Add(1)
1161 return
1162 }
1163
1164
1165 lock(&mp.threadLock)
1166 if mp.thread == 0 {
1167
1168 unlock(&mp.threadLock)
1169 atomic.Store(&mp.preemptExtLock, 0)
1170 mp.preemptGen.Add(1)
1171 return
1172 }
1173 var thread uintptr
1174 if stdcall(_DuplicateHandle, windows.CurrentProcess, mp.thread, windows.CurrentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, windows.DUPLICATE_SAME_ACCESS) == 0 {
1175 print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
1176 throw("runtime.preemptM: duplicatehandle failed")
1177 }
1178 unlock(&mp.threadLock)
1179
1180
1181 var c *windows.Context
1182 var cbuf [unsafe.Sizeof(*c) + 15]byte
1183 c = (*windows.Context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1184 c.ContextFlags = windows.CONTEXT_CONTROL
1185
1186
1187
1188
1189
1190
1191 lock(&suspendLock)
1192
1193
1194 if int32(stdcall(_SuspendThread, thread)) == -1 {
1195 unlock(&suspendLock)
1196 stdcall(_CloseHandle, thread)
1197 atomic.Store(&mp.preemptExtLock, 0)
1198
1199
1200 mp.preemptGen.Add(1)
1201 return
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213 stdcall(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1214
1215 unlock(&suspendLock)
1216
1217
1218 gp := gFromSP(mp, c.SP())
1219 if gp != nil && wantAsyncPreempt(gp) {
1220 if ok, resumePC := isAsyncSafePoint(gp, c.PC(), c.SP(), c.LR()); ok {
1221
1222 targetPC := abi.FuncPCABI0(asyncPreempt)
1223 c.PushCall(targetPC, resumePC)
1224 stdcall(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1225 }
1226 }
1227
1228 atomic.Store(&mp.preemptExtLock, 0)
1229
1230
1231 mp.preemptGen.Add(1)
1232
1233 stdcall(_ResumeThread, thread)
1234 stdcall(_CloseHandle, thread)
1235 }
1236
1237
1238
1239
1240
1241
1242
1243
1244 func osPreemptExtEnter(mp *m) {
1245 for !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1246
1247
1248
1249
1250
1251
1252
1253
1254 osyield()
1255 }
1256
1257 }
1258
1259
1260
1261
1262
1263
1264
1265 func osPreemptExtExit(mp *m) {
1266 atomic.Store(&mp.preemptExtLock, 0)
1267 }
1268
View as plain text