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