Source file
src/runtime/os_windows.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "runtime/internal/atomic"
9 "runtime/internal/sys"
10 "unsafe"
11 )
12
13
14 const (
15 _NSIG = 65
16 )
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 type stdFunction unsafe.Pointer
63
64 var (
65
66
67
68 _AddVectoredExceptionHandler,
69 _CloseHandle,
70 _CreateEventA,
71 _CreateFileA,
72 _CreateIoCompletionPort,
73 _CreateThread,
74 _CreateWaitableTimerA,
75 _CreateWaitableTimerExW,
76 _DuplicateHandle,
77 _ExitProcess,
78 _FreeEnvironmentStringsW,
79 _GetConsoleMode,
80 _GetEnvironmentStringsW,
81 _GetProcAddress,
82 _GetProcessAffinityMask,
83 _GetQueuedCompletionStatusEx,
84 _GetStdHandle,
85 _GetSystemDirectoryA,
86 _GetSystemInfo,
87 _GetSystemTimeAsFileTime,
88 _GetThreadContext,
89 _SetThreadContext,
90 _LoadLibraryW,
91 _LoadLibraryA,
92 _PostQueuedCompletionStatus,
93 _QueryPerformanceCounter,
94 _QueryPerformanceFrequency,
95 _ResumeThread,
96 _SetConsoleCtrlHandler,
97 _SetErrorMode,
98 _SetEvent,
99 _SetProcessPriorityBoost,
100 _SetThreadPriority,
101 _SetUnhandledExceptionFilter,
102 _SetWaitableTimer,
103 _Sleep,
104 _SuspendThread,
105 _SwitchToThread,
106 _TlsAlloc,
107 _VirtualAlloc,
108 _VirtualFree,
109 _VirtualQuery,
110 _WaitForSingleObject,
111 _WaitForMultipleObjects,
112 _WriteConsoleW,
113 _WriteFile,
114 _ stdFunction
115
116
117
118 _AddDllDirectory,
119 _AddVectoredContinueHandler,
120 _LoadLibraryExA,
121 _LoadLibraryExW,
122 _ stdFunction
123
124
125
126
127
128
129
130
131
132 _RtlGenRandom stdFunction
133
134
135
136
137 _NtWaitForSingleObject stdFunction
138 _RtlGetCurrentPeb stdFunction
139 _RtlGetNtVersionNumbers stdFunction
140
141
142 _timeBeginPeriod,
143 _timeEndPeriod,
144 _WSAGetOverlappedResult,
145 _ stdFunction
146 )
147
148
149
150 func tstart_stdcall(newm *m)
151
152
153 func wintls()
154
155 type mOS struct {
156 threadLock mutex
157 thread uintptr
158
159 waitsema uintptr
160 resumesema uintptr
161
162 highResTimer uintptr
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 preemptExtLock uint32
186 }
187
188
189 func os_sigpipe() {
190 throw("too many writes on closed pipe")
191 }
192
193
194 func open(name *byte, mode, perm int32) int32 {
195 throw("unimplemented")
196 return -1
197 }
198 func closefd(fd int32) int32 {
199 throw("unimplemented")
200 return -1
201 }
202 func read(fd int32, p unsafe.Pointer, n int32) int32 {
203 throw("unimplemented")
204 return -1
205 }
206
207 type sigset struct{}
208
209
210
211 func asmstdcall(fn unsafe.Pointer)
212
213 var asmstdcallAddr unsafe.Pointer
214
215 func windowsFindfunc(lib uintptr, name []byte) stdFunction {
216 if name[len(name)-1] != 0 {
217 throw("usage")
218 }
219 f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
220 return stdFunction(unsafe.Pointer(f))
221 }
222
223 const _MAX_PATH = 260
224 var sysDirectory [_MAX_PATH + 1]byte
225 var sysDirectoryLen uintptr
226
227 func windowsLoadSystemLib(name []byte) uintptr {
228 if sysDirectoryLen == 0 {
229 l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
230 if l == 0 || l > uintptr(len(sysDirectory)-1) {
231 throw("Unable to determine system directory")
232 }
233 sysDirectory[l] = '\\'
234 sysDirectoryLen = l + 1
235 }
236 if useLoadLibraryEx {
237 return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
238 } else {
239 absName := append(sysDirectory[:sysDirectoryLen], name...)
240 return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
241 }
242 }
243
244 const haveCputicksAsm = GOARCH == "386" || GOARCH == "amd64"
245
246 func loadOptionalSyscalls() {
247 var kernel32dll = []byte("kernel32.dll\000")
248 k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
249 if k32 == 0 {
250 throw("kernel32.dll not found")
251 }
252 _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
253 _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
254 _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
255 _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
256 useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
257
258 var advapi32dll = []byte("advapi32.dll\000")
259 a32 := windowsLoadSystemLib(advapi32dll)
260 if a32 == 0 {
261 throw("advapi32.dll not found")
262 }
263 _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
264
265 var ntdll = []byte("ntdll.dll\000")
266 n32 := windowsLoadSystemLib(ntdll)
267 if n32 == 0 {
268 throw("ntdll.dll not found")
269 }
270 _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
271 _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
272 _RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000"))
273
274 if !haveCputicksAsm {
275 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
276 if _QueryPerformanceCounter == nil {
277 throw("could not find QPC syscalls")
278 }
279 }
280
281 var winmmdll = []byte("winmm.dll\000")
282 m32 := windowsLoadSystemLib(winmmdll)
283 if m32 == 0 {
284 throw("winmm.dll not found")
285 }
286 _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
287 _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
288 if _timeBeginPeriod == nil || _timeEndPeriod == nil {
289 throw("timeBegin/EndPeriod not found")
290 }
291
292 var ws232dll = []byte("ws2_32.dll\000")
293 ws232 := windowsLoadSystemLib(ws232dll)
294 if ws232 == 0 {
295 throw("ws2_32.dll not found")
296 }
297 _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
298 if _WSAGetOverlappedResult == nil {
299 throw("WSAGetOverlappedResult not found")
300 }
301
302 if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
303
304 initWine(k32)
305 }
306 }
307
308 func monitorSuspendResume() {
309 const (
310 _DEVICE_NOTIFY_CALLBACK = 2
311 )
312 type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
313 callback uintptr
314 context uintptr
315 }
316
317 powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
318 if powrprof == 0 {
319 return
320 }
321 powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
322 if powerRegisterSuspendResumeNotification == nil {
323 return
324 }
325 var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
326 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
327 if mp.resumesema != 0 {
328 stdcall1(_SetEvent, mp.resumesema)
329 }
330 }
331 return 0
332 }
333 params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
334 callback: compileCallback(*efaceOf(&fn), true),
335 }
336 handle := uintptr(0)
337 stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
338 uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle)))
339 }
340
341
342 func getLoadLibrary() uintptr {
343 return uintptr(unsafe.Pointer(_LoadLibraryW))
344 }
345
346
347 func getLoadLibraryEx() uintptr {
348 return uintptr(unsafe.Pointer(_LoadLibraryExW))
349 }
350
351
352 func getGetProcAddress() uintptr {
353 return uintptr(unsafe.Pointer(_GetProcAddress))
354 }
355
356 func getproccount() int32 {
357 var mask, sysmask uintptr
358 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
359 if ret != 0 {
360 n := 0
361 maskbits := int(unsafe.Sizeof(mask) * 8)
362 for i := 0; i < maskbits; i++ {
363 if mask&(1<<uint(i)) != 0 {
364 n++
365 }
366 }
367 if n != 0 {
368 return int32(n)
369 }
370 }
371
372 var info systeminfo
373 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
374 return int32(info.dwnumberofprocessors)
375 }
376
377 func getPageSize() uintptr {
378 var info systeminfo
379 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
380 return uintptr(info.dwpagesize)
381 }
382
383 const (
384 currentProcess = ^uintptr(0)
385 currentThread = ^uintptr(1)
386 )
387
388
389 func getlasterror() uint32
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405 var useLoadLibraryEx bool
406
407 var timeBeginPeriodRetValue uint32
408
409
410
411
412
413 const osRelaxMinNS = 60 * 1e6
414
415
416
417
418
419
420
421
422
423
424
425 func osRelax(relax bool) uint32 {
426 if haveHighResTimer {
427
428
429
430 return 0
431 }
432
433 if relax {
434 return uint32(stdcall1(_timeEndPeriod, 1))
435 } else {
436 return uint32(stdcall1(_timeBeginPeriod, 1))
437 }
438 }
439
440
441
442 var haveHighResTimer = false
443
444
445
446
447
448 func createHighResTimer() uintptr {
449 const (
450
451
452 _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002
453
454 _SYNCHRONIZE = 0x00100000
455 _TIMER_QUERY_STATE = 0x0001
456 _TIMER_MODIFY_STATE = 0x0002
457 )
458 return stdcall4(_CreateWaitableTimerExW, 0, 0,
459 _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
460 _SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
461 }
462
463 const highResTimerSupported = GOARCH == "386" || GOARCH == "amd64"
464
465 func initHighResTimer() {
466 if !highResTimerSupported {
467
468 return
469 }
470 h := createHighResTimer()
471 if h != 0 {
472 haveHighResTimer = true
473 stdcall1(_CloseHandle, h)
474 }
475 }
476
477
478 var canUseLongPaths bool
479
480
481
482 var longFileName [(_MAX_PATH+1)*2 + 1]byte
483
484
485
486
487
488
489
490
491
492
493
494 func initLongPathSupport() {
495 const (
496 IsLongPathAwareProcess = 0x80
497 PebBitFieldOffset = 3
498 OPEN_EXISTING = 3
499 ERROR_PATH_NOT_FOUND = 3
500 )
501
502
503 var maj, min, build uint32
504 stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build)))
505 if maj < 10 || (maj == 10 && min == 0 && build&0xffff < 15063) {
506 return
507 }
508
509
510 bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset))
511 originalBitField := *bitField
512 *bitField |= IsLongPathAwareProcess
513
514
515
516
517
518
519
520
521 getRandomData(longFileName[len(longFileName)-33 : len(longFileName)-1])
522 start := copy(longFileName[:], sysDirectory[:sysDirectoryLen])
523 const dig = "0123456789abcdef"
524 for i := 0; i < 32; i++ {
525 longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4]
526 longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf]
527 }
528 start += 64
529 for i := start; i < len(longFileName)-1; i++ {
530 longFileName[i] = 'A'
531 }
532 stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0)
533
534
535
536 if getlasterror() == ERROR_PATH_NOT_FOUND {
537 *bitField = originalBitField
538 println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode")
539 return
540 }
541
542 canUseLongPaths = true
543 }
544
545 func osinit() {
546 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
547
548 setBadSignalMsg()
549
550 loadOptionalSyscalls()
551
552 disableWER()
553
554 initExceptionHandler()
555
556 initHighResTimer()
557 timeBeginPeriodRetValue = osRelax(false)
558
559 initLongPathSupport()
560
561 ncpu = getproccount()
562
563 physPageSize = getPageSize()
564
565
566
567
568
569 stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
570 }
571
572
573
574 var useQPCTime uint8
575
576 var qpcStartCounter int64
577 var qpcMultiplier int64
578
579
580 func nanotimeQPC() int64 {
581 var counter int64 = 0
582 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
583
584
585 return (counter - qpcStartCounter) * qpcMultiplier
586 }
587
588
589 func nowQPC() (sec int64, nsec int32, mono int64) {
590 var ft int64
591 stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft)))
592
593 t := (ft - 116444736000000000) * 100
594
595 sec = t / 1000000000
596 nsec = int32(t - sec*1000000000)
597
598 mono = nanotimeQPC()
599 return
600 }
601
602 func initWine(k32 uintptr) {
603 _GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
604 if _GetSystemTimeAsFileTime == nil {
605 throw("could not find GetSystemTimeAsFileTime() syscall")
606 }
607
608 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
609 _QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000"))
610 if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil {
611 throw("could not find QPC syscalls")
612 }
613
614
615
616
617
618 var tmp int64
619 stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp)))
620 if tmp == 0 {
621 throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware")
622 }
623
624
625
626
627 if tmp > (1<<31 - 1) {
628 throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed")
629 }
630 qpcFrequency := int32(tmp)
631 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter)))
632
633
634
635
636
637
638 qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))
639
640 useQPCTime = 1
641 }
642
643
644 func getRandomData(r []byte) {
645 n := 0
646 if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
647 n = len(r)
648 }
649 extendRandom(r, n)
650 }
651
652 func goenvs() {
653
654
655
656 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
657 p := (*[1 << 24]uint16)(strings)[:]
658
659 n := 0
660 for from, i := 0, 0; true; i++ {
661 if p[i] == 0 {
662
663 if i == from {
664 break
665 }
666 from = i + 1
667 n++
668 }
669 }
670 envs = make([]string, n)
671
672 for i := range envs {
673 envs[i] = gostringw(&p[0])
674 for p[0] != 0 {
675 p = p[1:]
676 }
677 p = p[1:]
678 }
679
680 stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
681
682
683
684 var fn interface{} = ctrlHandler
685 ctrlHandlerPC := compileCallback(*efaceOf(&fn), true)
686 stdcall2(_SetConsoleCtrlHandler, ctrlHandlerPC, 1)
687
688 monitorSuspendResume()
689 }
690
691
692 var exiting uint32
693
694
695 func exit(code int32) {
696
697
698
699
700 lock(&suspendLock)
701 atomic.Store(&exiting, 1)
702 stdcall1(_ExitProcess, uintptr(code))
703 }
704
705
706
707
708
709
710 func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
711 const (
712 _STD_OUTPUT_HANDLE = ^uintptr(10)
713 _STD_ERROR_HANDLE = ^uintptr(11)
714 )
715 var handle uintptr
716 switch fd {
717 case 1:
718 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
719 case 2:
720 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
721 default:
722
723 handle = fd
724 }
725 isASCII := true
726 b := (*[1 << 30]byte)(buf)[:n]
727 for _, x := range b {
728 if x >= 0x80 {
729 isASCII = false
730 break
731 }
732 }
733
734 if !isASCII {
735 var m uint32
736 isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
737
738
739 if isConsole {
740 return int32(writeConsole(handle, buf, n))
741 }
742 }
743 var written uint32
744 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
745 return int32(written)
746 }
747
748 var (
749 utf16ConsoleBack [1000]uint16
750 utf16ConsoleBackLock mutex
751 )
752
753
754
755 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
756 const surr2 = (surrogateMin + surrogateMax + 1) / 2
757
758
759 lock(&utf16ConsoleBackLock)
760
761 b := (*[1 << 30]byte)(buf)[:bufLen]
762 s := *(*string)(unsafe.Pointer(&b))
763
764 utf16tmp := utf16ConsoleBack[:]
765
766 total := len(s)
767 w := 0
768 for _, r := range s {
769 if w >= len(utf16tmp)-2 {
770 writeConsoleUTF16(handle, utf16tmp[:w])
771 w = 0
772 }
773 if r < 0x10000 {
774 utf16tmp[w] = uint16(r)
775 w++
776 } else {
777 r -= 0x10000
778 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
779 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
780 w += 2
781 }
782 }
783 writeConsoleUTF16(handle, utf16tmp[:w])
784 unlock(&utf16ConsoleBackLock)
785 return total
786 }
787
788
789
790
791 func writeConsoleUTF16(handle uintptr, b []uint16) {
792 l := uint32(len(b))
793 if l == 0 {
794 return
795 }
796 var written uint32
797 stdcall5(_WriteConsoleW,
798 handle,
799 uintptr(unsafe.Pointer(&b[0])),
800 uintptr(l),
801 uintptr(unsafe.Pointer(&written)),
802 0,
803 )
804 return
805 }
806
807
808 func semasleep(ns int64) int32 {
809 const (
810 _WAIT_ABANDONED = 0x00000080
811 _WAIT_OBJECT_0 = 0x00000000
812 _WAIT_TIMEOUT = 0x00000102
813 _WAIT_FAILED = 0xFFFFFFFF
814 )
815
816 var result uintptr
817 if ns < 0 {
818 result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
819 } else {
820 start := nanotime()
821 elapsed := int64(0)
822 for {
823 ms := int64(timediv(ns-elapsed, 1000000, nil))
824 if ms == 0 {
825 ms = 1
826 }
827 result = stdcall4(_WaitForMultipleObjects, 2,
828 uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
829 0, uintptr(ms))
830 if result != _WAIT_OBJECT_0+1 {
831
832 break
833 }
834 elapsed = nanotime() - start
835 if elapsed >= ns {
836 return -1
837 }
838 }
839 }
840 switch result {
841 case _WAIT_OBJECT_0:
842 return 0
843
844 case _WAIT_TIMEOUT:
845 return -1
846
847 case _WAIT_ABANDONED:
848 systemstack(func() {
849 throw("runtime.semasleep wait_abandoned")
850 })
851
852 case _WAIT_FAILED:
853 systemstack(func() {
854 print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
855 throw("runtime.semasleep wait_failed")
856 })
857
858 default:
859 systemstack(func() {
860 print("runtime: waitforsingleobject unexpected; result=", result, "\n")
861 throw("runtime.semasleep unexpected")
862 })
863 }
864
865 return -1
866 }
867
868
869 func semawakeup(mp *m) {
870 if stdcall1(_SetEvent, mp.waitsema) == 0 {
871 systemstack(func() {
872 print("runtime: setevent failed; errno=", getlasterror(), "\n")
873 throw("runtime.semawakeup")
874 })
875 }
876 }
877
878
879 func semacreate(mp *m) {
880 if mp.waitsema != 0 {
881 return
882 }
883 mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
884 if mp.waitsema == 0 {
885 systemstack(func() {
886 print("runtime: createevent failed; errno=", getlasterror(), "\n")
887 throw("runtime.semacreate")
888 })
889 }
890 mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
891 if mp.resumesema == 0 {
892 systemstack(func() {
893 print("runtime: createevent failed; errno=", getlasterror(), "\n")
894 throw("runtime.semacreate")
895 })
896 stdcall1(_CloseHandle, mp.waitsema)
897 mp.waitsema = 0
898 }
899 }
900
901
902
903
904
905
906 func newosproc(mp *m) {
907
908 thandle := stdcall6(_CreateThread, 0, 0,
909 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
910 0, 0)
911
912 if thandle == 0 {
913 if atomic.Load(&exiting) != 0 {
914
915
916
917
918 lock(&deadlock)
919 lock(&deadlock)
920 }
921 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
922 throw("runtime.newosproc")
923 }
924
925
926 stdcall1(_CloseHandle, thandle)
927 }
928
929
930
931
932
933
934 func newosproc0(mp *m, stk unsafe.Pointer) {
935
936
937
938 throw("bad newosproc0")
939 }
940
941 func exitThread(wait *uint32) {
942
943
944 throw("exitThread")
945 }
946
947
948
949 func mpreinit(mp *m) {
950 }
951
952
953 func sigsave(p *sigset) {
954 }
955
956
957 func msigrestore(sigmask sigset) {
958 }
959
960
961
962 func clearSignalHandlers() {
963 }
964
965
966 func sigblock(exiting bool) {
967 }
968
969
970
971 func minit() {
972 var thandle uintptr
973 if stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
974 print("runtime.minit: duplicatehandle failed; errno=", getlasterror(), "\n")
975 throw("runtime.minit: duplicatehandle failed")
976 }
977
978 mp := getg().m
979 lock(&mp.threadLock)
980 mp.thread = thandle
981
982
983 if mp.highResTimer == 0 && haveHighResTimer {
984 mp.highResTimer = createHighResTimer()
985 if mp.highResTimer == 0 {
986 print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
987 throw("CreateWaitableTimerEx when creating timer failed")
988 }
989 }
990 unlock(&mp.threadLock)
991
992
993
994 var mbi memoryBasicInformation
995 res := stdcall3(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
996 if res == 0 {
997 print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
998 throw("VirtualQuery for stack base failed")
999 }
1000
1001
1002
1003
1004
1005
1006 base := mbi.allocationBase + 16<<10
1007
1008 g0 := getg()
1009 if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
1010 print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
1011 throw("bad g0 stack")
1012 }
1013 g0.stack.lo = base
1014 g0.stackguard0 = g0.stack.lo + _StackGuard
1015 g0.stackguard1 = g0.stackguard0
1016
1017 stackcheck()
1018 }
1019
1020
1021
1022 func unminit() {
1023 mp := getg().m
1024 lock(&mp.threadLock)
1025 if mp.thread != 0 {
1026 stdcall1(_CloseHandle, mp.thread)
1027 mp.thread = 0
1028 }
1029 unlock(&mp.threadLock)
1030 }
1031
1032
1033
1034
1035 func mdestroy(mp *m) {
1036 if mp.highResTimer != 0 {
1037 stdcall1(_CloseHandle, mp.highResTimer)
1038 mp.highResTimer = 0
1039 }
1040 if mp.waitsema != 0 {
1041 stdcall1(_CloseHandle, mp.waitsema)
1042 mp.waitsema = 0
1043 }
1044 if mp.resumesema != 0 {
1045 stdcall1(_CloseHandle, mp.resumesema)
1046 mp.resumesema = 0
1047 }
1048 }
1049
1050
1051
1052
1053
1054 func stdcall(fn stdFunction) uintptr {
1055 gp := getg()
1056 mp := gp.m
1057 mp.libcall.fn = uintptr(unsafe.Pointer(fn))
1058 resetLibcall := false
1059 if mp.profilehz != 0 && mp.libcallsp == 0 {
1060
1061 mp.libcallg.set(gp)
1062 mp.libcallpc = getcallerpc()
1063
1064
1065 mp.libcallsp = getcallersp()
1066 resetLibcall = true
1067 }
1068 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
1069 if resetLibcall {
1070 mp.libcallsp = 0
1071 }
1072 return mp.libcall.r1
1073 }
1074
1075
1076 func stdcall0(fn stdFunction) uintptr {
1077 mp := getg().m
1078 mp.libcall.n = 0
1079 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn)))
1080 return stdcall(fn)
1081 }
1082
1083
1084
1085 func stdcall1(fn stdFunction, a0 uintptr) uintptr {
1086 mp := getg().m
1087 mp.libcall.n = 1
1088 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1089 return stdcall(fn)
1090 }
1091
1092
1093
1094 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
1095 mp := getg().m
1096 mp.libcall.n = 2
1097 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1098 return stdcall(fn)
1099 }
1100
1101
1102
1103 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
1104 mp := getg().m
1105 mp.libcall.n = 3
1106 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1107 return stdcall(fn)
1108 }
1109
1110
1111
1112 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
1113 mp := getg().m
1114 mp.libcall.n = 4
1115 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1116 return stdcall(fn)
1117 }
1118
1119
1120
1121 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
1122 mp := getg().m
1123 mp.libcall.n = 5
1124 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1125 return stdcall(fn)
1126 }
1127
1128
1129
1130 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
1131 mp := getg().m
1132 mp.libcall.n = 6
1133 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1134 return stdcall(fn)
1135 }
1136
1137
1138
1139 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
1140 mp := getg().m
1141 mp.libcall.n = 7
1142 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
1143 return stdcall(fn)
1144 }
1145
1146
1147 func usleep2(dt int32)
1148 func usleep2HighRes(dt int32)
1149 func switchtothread()
1150
1151
1152 func osyield_no_g() {
1153 switchtothread()
1154 }
1155
1156
1157 func osyield() {
1158 systemstack(switchtothread)
1159 }
1160
1161
1162 func usleep_no_g(us uint32) {
1163 dt := -10 * int32(us)
1164 usleep2(dt)
1165 }
1166
1167
1168 func usleep(us uint32) {
1169 systemstack(func() {
1170 dt := -10 * int32(us)
1171
1172
1173 if haveHighResTimer && getg().m.highResTimer != 0 {
1174 usleep2HighRes(dt)
1175 } else {
1176 usleep2(dt)
1177 }
1178 })
1179 }
1180
1181 func ctrlHandler(_type uint32) uintptr {
1182 var s uint32
1183
1184 switch _type {
1185 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
1186 s = _SIGINT
1187 case _CTRL_CLOSE_EVENT, _CTRL_LOGOFF_EVENT, _CTRL_SHUTDOWN_EVENT:
1188 s = _SIGTERM
1189 default:
1190 return 0
1191 }
1192
1193 if sigsend(s) {
1194 if s == _SIGTERM {
1195
1196
1197 stdcall1(_Sleep, uintptr(_INFINITE))
1198 }
1199 return 1
1200 }
1201 return 0
1202 }
1203
1204
1205 func callbackasm1()
1206
1207 var profiletimer uintptr
1208
1209 func profilem(mp *m, thread uintptr) {
1210
1211 var c *context
1212 var cbuf [unsafe.Sizeof(*c) + 15]byte
1213 c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1214
1215 c.contextflags = _CONTEXT_CONTROL
1216 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1217
1218 gp := gFromSP(mp, c.sp())
1219
1220 sigprof(c.ip(), c.sp(), c.lr(), gp, mp)
1221 }
1222
1223 func gFromSP(mp *m, sp uintptr) *g {
1224 if gp := mp.g0; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1225 return gp
1226 }
1227 if gp := mp.gsignal; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1228 return gp
1229 }
1230 if gp := mp.curg; gp != nil && gp.stack.lo < sp && sp < gp.stack.hi {
1231 return gp
1232 }
1233 return nil
1234 }
1235
1236 func profileLoop() {
1237 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
1238
1239 for {
1240 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
1241 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
1242 for mp := first; mp != nil; mp = mp.alllink {
1243 if mp == getg().m {
1244
1245 continue
1246 }
1247
1248 lock(&mp.threadLock)
1249
1250
1251
1252 if mp.thread == 0 || mp.profilehz == 0 || mp.blocked {
1253 unlock(&mp.threadLock)
1254 continue
1255 }
1256
1257 var thread uintptr
1258 if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
1259 print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
1260 throw("duplicatehandle failed")
1261 }
1262 unlock(&mp.threadLock)
1263
1264
1265
1266
1267
1268 if int32(stdcall1(_SuspendThread, thread)) == -1 {
1269
1270 stdcall1(_CloseHandle, thread)
1271 continue
1272 }
1273 if mp.profilehz != 0 && !mp.blocked {
1274
1275
1276 profilem(mp, thread)
1277 }
1278 stdcall1(_ResumeThread, thread)
1279 stdcall1(_CloseHandle, thread)
1280 }
1281 }
1282 }
1283
1284 func setProcessCPUProfiler(hz int32) {
1285 if profiletimer == 0 {
1286 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
1287 atomic.Storeuintptr(&profiletimer, timer)
1288 newm(profileLoop, nil, -1)
1289 }
1290 }
1291
1292 func setThreadCPUProfiler(hz int32) {
1293 ms := int32(0)
1294 due := ^int64(^uint64(1 << 63))
1295 if hz > 0 {
1296 ms = 1000 / hz
1297 if ms == 0 {
1298 ms = 1
1299 }
1300 due = int64(ms) * -10000
1301 }
1302 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
1303 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
1304 }
1305
1306 const preemptMSupported = GOARCH == "386" || GOARCH == "amd64"
1307
1308
1309
1310 var suspendLock mutex
1311
1312 func preemptM(mp *m) {
1313 if !preemptMSupported {
1314
1315 return
1316 }
1317
1318 if mp == getg().m {
1319 throw("self-preempt")
1320 }
1321
1322
1323 if !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1324
1325
1326 atomic.Xadd(&mp.preemptGen, 1)
1327 return
1328 }
1329
1330
1331 lock(&mp.threadLock)
1332 if mp.thread == 0 {
1333
1334 unlock(&mp.threadLock)
1335 atomic.Store(&mp.preemptExtLock, 0)
1336 atomic.Xadd(&mp.preemptGen, 1)
1337 return
1338 }
1339 var thread uintptr
1340 if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
1341 print("runtime.preemptM: duplicatehandle failed; errno=", getlasterror(), "\n")
1342 throw("runtime.preemptM: duplicatehandle failed")
1343 }
1344 unlock(&mp.threadLock)
1345
1346
1347 var c *context
1348 var cbuf [unsafe.Sizeof(*c) + 15]byte
1349 c = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&cbuf[15]))) &^ 15))
1350 c.contextflags = _CONTEXT_CONTROL
1351
1352
1353
1354
1355
1356
1357 lock(&suspendLock)
1358
1359
1360 if int32(stdcall1(_SuspendThread, thread)) == -1 {
1361 unlock(&suspendLock)
1362 stdcall1(_CloseHandle, thread)
1363 atomic.Store(&mp.preemptExtLock, 0)
1364
1365
1366 atomic.Xadd(&mp.preemptGen, 1)
1367 return
1368 }
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1380
1381 unlock(&suspendLock)
1382
1383
1384 gp := gFromSP(mp, c.sp())
1385 if gp != nil && wantAsyncPreempt(gp) {
1386 if ok, newpc := isAsyncSafePoint(gp, c.ip(), c.sp(), c.lr()); ok {
1387
1388 targetPC := funcPC(asyncPreempt)
1389 switch GOARCH {
1390 default:
1391 throw("unsupported architecture")
1392 case "386", "amd64":
1393
1394 sp := c.sp()
1395 sp -= sys.PtrSize
1396 *(*uintptr)(unsafe.Pointer(sp)) = newpc
1397 c.set_sp(sp)
1398 c.set_ip(targetPC)
1399 }
1400
1401 stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
1402 }
1403 }
1404
1405 atomic.Store(&mp.preemptExtLock, 0)
1406
1407
1408 atomic.Xadd(&mp.preemptGen, 1)
1409
1410 stdcall1(_ResumeThread, thread)
1411 stdcall1(_CloseHandle, thread)
1412 }
1413
1414
1415
1416
1417
1418
1419
1420
1421 func osPreemptExtEnter(mp *m) {
1422 for !atomic.Cas(&mp.preemptExtLock, 0, 1) {
1423
1424
1425
1426
1427
1428
1429
1430
1431 osyield()
1432 }
1433
1434 }
1435
1436
1437
1438
1439
1440
1441
1442 func osPreemptExtExit(mp *m) {
1443 atomic.Store(&mp.preemptExtLock, 0)
1444 }
1445
View as plain text