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