Source file src/runtime/os_windows.go
1
2
3
4
5 package runtime
6
7 import (
8 "runtime/internal/atomic"
9 "unsafe"
10 )
11
12
13 const (
14 _NSIG = 65
15 )
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 type stdFunction unsafe.Pointer
57
58 var (
59
60
61
62 _AddVectoredExceptionHandler,
63 _CloseHandle,
64 _CreateEventA,
65 _CreateIoCompletionPort,
66 _CreateThread,
67 _CreateWaitableTimerA,
68 _DuplicateHandle,
69 _ExitProcess,
70 _FreeEnvironmentStringsW,
71 _GetConsoleMode,
72 _GetEnvironmentStringsW,
73 _GetProcAddress,
74 _GetProcessAffinityMask,
75 _GetQueuedCompletionStatus,
76 _GetStdHandle,
77 _GetSystemDirectoryA,
78 _GetSystemInfo,
79 _GetSystemTimeAsFileTime,
80 _GetThreadContext,
81 _LoadLibraryW,
82 _LoadLibraryA,
83 _QueryPerformanceCounter,
84 _QueryPerformanceFrequency,
85 _ResumeThread,
86 _SetConsoleCtrlHandler,
87 _SetErrorMode,
88 _SetEvent,
89 _SetProcessPriorityBoost,
90 _SetThreadPriority,
91 _SetUnhandledExceptionFilter,
92 _SetWaitableTimer,
93 _SuspendThread,
94 _SwitchToThread,
95 _TlsAlloc,
96 _VirtualAlloc,
97 _VirtualFree,
98 _VirtualQuery,
99 _WaitForSingleObject,
100 _WaitForMultipleObjects,
101 _WriteConsoleW,
102 _WriteFile,
103 _ stdFunction
104
105
106
107 _AddDllDirectory,
108 _AddVectoredContinueHandler,
109 _GetQueuedCompletionStatusEx,
110 _LoadLibraryExA,
111 _LoadLibraryExW,
112 _ stdFunction
113
114
115
116
117
118
119
120
121
122 _RtlGenRandom stdFunction
123
124
125
126
127 _NtWaitForSingleObject stdFunction
128
129
130 _timeBeginPeriod,
131 _timeEndPeriod,
132 _WSAGetOverlappedResult,
133 _ stdFunction
134 )
135
136
137
138 func tstart_stdcall(newm *m)
139
140
141 func ctrlhandler()
142
143 type mOS struct {
144 waitsema uintptr
145 resumesema uintptr
146 }
147
148
149 func os_sigpipe() {
150 throw("too many writes on closed pipe")
151 }
152
153
154 func open(name *byte, mode, perm int32) int32 {
155 throw("unimplemented")
156 return -1
157 }
158 func closefd(fd int32) int32 {
159 throw("unimplemented")
160 return -1
161 }
162 func read(fd int32, p unsafe.Pointer, n int32) int32 {
163 throw("unimplemented")
164 return -1
165 }
166
167 type sigset struct{}
168
169
170
171 func asmstdcall(fn unsafe.Pointer)
172
173 var asmstdcallAddr unsafe.Pointer
174
175 func windowsFindfunc(lib uintptr, name []byte) stdFunction {
176 if name[len(name)-1] != 0 {
177 throw("usage")
178 }
179 f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
180 return stdFunction(unsafe.Pointer(f))
181 }
182
183 var sysDirectory [521]byte
184 var sysDirectoryLen uintptr
185
186 func windowsLoadSystemLib(name []byte) uintptr {
187 if useLoadLibraryEx {
188 return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
189 } else {
190 if sysDirectoryLen == 0 {
191 l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
192 if l == 0 || l > uintptr(len(sysDirectory)-1) {
193 throw("Unable to determine system directory")
194 }
195 sysDirectory[l] = '\\'
196 sysDirectoryLen = l + 1
197 }
198 absName := append(sysDirectory[:sysDirectoryLen], name...)
199 return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
200 }
201 }
202
203 func loadOptionalSyscalls() {
204 var kernel32dll = []byte("kernel32.dll\000")
205 k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
206 if k32 == 0 {
207 throw("kernel32.dll not found")
208 }
209 _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
210 _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
211 _GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
212 _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
213 _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
214 useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
215
216 var advapi32dll = []byte("advapi32.dll\000")
217 a32 := windowsLoadSystemLib(advapi32dll)
218 if a32 == 0 {
219 throw("advapi32.dll not found")
220 }
221 _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
222
223 var ntdll = []byte("ntdll.dll\000")
224 n32 := windowsLoadSystemLib(ntdll)
225 if n32 == 0 {
226 throw("ntdll.dll not found")
227 }
228 _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
229
230 if GOARCH == "arm" {
231 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
232 if _QueryPerformanceCounter == nil {
233 throw("could not find QPC syscalls")
234 }
235 }
236
237 var winmmdll = []byte("winmm.dll\000")
238 m32 := windowsLoadSystemLib(winmmdll)
239 if m32 == 0 {
240 throw("winmm.dll not found")
241 }
242 _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
243 _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
244 if _timeBeginPeriod == nil || _timeEndPeriod == nil {
245 throw("timeBegin/EndPeriod not found")
246 }
247
248 var ws232dll = []byte("ws2_32.dll\000")
249 ws232 := windowsLoadSystemLib(ws232dll)
250 if ws232 == 0 {
251 throw("ws2_32.dll not found")
252 }
253 _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
254 if _WSAGetOverlappedResult == nil {
255 throw("WSAGetOverlappedResult not found")
256 }
257
258 if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
259
260 initWine(k32)
261 }
262 }
263
264 func monitorSuspendResume() {
265 const (
266 _DEVICE_NOTIFY_CALLBACK = 2
267 _ERROR_FILE_NOT_FOUND = 2
268 )
269 type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
270 callback uintptr
271 context uintptr
272 }
273
274 powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
275 if powrprof == 0 {
276 return
277 }
278 powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
279 if powerRegisterSuspendResumeNotification == nil {
280 return
281 }
282 var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
283 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
284 if mp.resumesema != 0 {
285 stdcall1(_SetEvent, mp.resumesema)
286 }
287 }
288 return 0
289 }
290 params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
291 callback: compileCallback(*efaceOf(&fn), true),
292 }
293 handle := uintptr(0)
294 ret := stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
295 uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle)))
296
297 switch ret {
298 case 0:
299 return
300 case _ERROR_FILE_NOT_FOUND:
301
302
303
304 return
305 default:
306 println("runtime: PowerRegisterSuspendResumeNotification failed with errno=", ret)
307 throw("runtime: PowerRegisterSuspendResumeNotification failure")
308 }
309 }
310
311
312 func getLoadLibrary() uintptr {
313 return uintptr(unsafe.Pointer(_LoadLibraryW))
314 }
315
316
317 func getLoadLibraryEx() uintptr {
318 return uintptr(unsafe.Pointer(_LoadLibraryExW))
319 }
320
321
322 func getGetProcAddress() uintptr {
323 return uintptr(unsafe.Pointer(_GetProcAddress))
324 }
325
326 func getproccount() int32 {
327 var mask, sysmask uintptr
328 ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
329 if ret != 0 {
330 n := 0
331 maskbits := int(unsafe.Sizeof(mask) * 8)
332 for i := 0; i < maskbits; i++ {
333 if mask&(1<<uint(i)) != 0 {
334 n++
335 }
336 }
337 if n != 0 {
338 return int32(n)
339 }
340 }
341
342 var info systeminfo
343 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
344 return int32(info.dwnumberofprocessors)
345 }
346
347 func getPageSize() uintptr {
348 var info systeminfo
349 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
350 return uintptr(info.dwpagesize)
351 }
352
353 const (
354 currentProcess = ^uintptr(0)
355 currentThread = ^uintptr(1)
356 )
357
358
359 func externalthreadhandler()
360 func getlasterror() uint32
361 func setlasterror(err uint32)
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377 var useLoadLibraryEx bool
378
379 var timeBeginPeriodRetValue uint32
380
381
382
383
384
385 const osRelaxMinNS = 60 * 1e6
386
387
388
389
390
391
392
393
394 func osRelax(relax bool) uint32 {
395 if relax {
396 return uint32(stdcall1(_timeEndPeriod, 1))
397 } else {
398 return uint32(stdcall1(_timeBeginPeriod, 1))
399 }
400 }
401
402 func osinit() {
403 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
404 usleep2Addr = unsafe.Pointer(funcPC(usleep2))
405 switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread))
406
407 setBadSignalMsg()
408
409 loadOptionalSyscalls()
410
411 disableWER()
412
413 initExceptionHandler()
414
415 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
416
417 timeBeginPeriodRetValue = osRelax(false)
418
419 ncpu = getproccount()
420
421 physPageSize = getPageSize()
422
423
424
425
426
427 stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
428 }
429
430 func nanotime() int64
431
432
433
434 var useQPCTime uint8
435
436 var qpcStartCounter int64
437 var qpcMultiplier int64
438
439
440 func nanotimeQPC() int64 {
441 var counter int64 = 0
442 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
443
444
445 return (counter - qpcStartCounter) * qpcMultiplier
446 }
447
448
449 func nowQPC() (sec int64, nsec int32, mono int64) {
450 var ft int64
451 stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft)))
452
453 t := (ft - 116444736000000000) * 100
454
455 sec = t / 1000000000
456 nsec = int32(t - sec*1000000000)
457
458 mono = nanotimeQPC()
459 return
460 }
461
462 func initWine(k32 uintptr) {
463 _GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
464 if _GetSystemTimeAsFileTime == nil {
465 throw("could not find GetSystemTimeAsFileTime() syscall")
466 }
467
468 _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
469 _QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000"))
470 if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil {
471 throw("could not find QPC syscalls")
472 }
473
474
475
476
477
478 var tmp int64
479 stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp)))
480 if tmp == 0 {
481 throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware")
482 }
483
484
485
486
487 if tmp > (1<<31 - 1) {
488 throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed")
489 }
490 qpcFrequency := int32(tmp)
491 stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter)))
492
493
494
495
496
497
498 qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))
499
500 useQPCTime = 1
501 }
502
503
504 func getRandomData(r []byte) {
505 n := 0
506 if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
507 n = len(r)
508 }
509 extendRandom(r, n)
510 }
511
512 func goenvs() {
513
514
515
516 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
517 p := (*[1 << 24]uint16)(strings)[:]
518
519 n := 0
520 for from, i := 0, 0; true; i++ {
521 if p[i] == 0 {
522
523 if i == from {
524 break
525 }
526 from = i + 1
527 n++
528 }
529 }
530 envs = make([]string, n)
531
532 for i := range envs {
533 envs[i] = gostringw(&p[0])
534 for p[0] != 0 {
535 p = p[1:]
536 }
537 p = p[1:]
538 }
539
540 stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
541
542
543
544 monitorSuspendResume()
545 }
546
547
548 var exiting uint32
549
550
551 func exit(code int32) {
552 atomic.Store(&exiting, 1)
553 stdcall1(_ExitProcess, uintptr(code))
554 }
555
556
557 func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
558 const (
559 _STD_OUTPUT_HANDLE = ^uintptr(10)
560 _STD_ERROR_HANDLE = ^uintptr(11)
561 )
562 var handle uintptr
563 switch fd {
564 case 1:
565 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
566 case 2:
567 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
568 default:
569
570 handle = fd
571 }
572 isASCII := true
573 b := (*[1 << 30]byte)(buf)[:n]
574 for _, x := range b {
575 if x >= 0x80 {
576 isASCII = false
577 break
578 }
579 }
580
581 if !isASCII {
582 var m uint32
583 isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
584
585
586 if isConsole {
587 return int32(writeConsole(handle, buf, n))
588 }
589 }
590 var written uint32
591 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
592 return int32(written)
593 }
594
595 var (
596 utf16ConsoleBack [1000]uint16
597 utf16ConsoleBackLock mutex
598 )
599
600
601
602 func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
603 const surr2 = (surrogateMin + surrogateMax + 1) / 2
604
605
606 lock(&utf16ConsoleBackLock)
607
608 b := (*[1 << 30]byte)(buf)[:bufLen]
609 s := *(*string)(unsafe.Pointer(&b))
610
611 utf16tmp := utf16ConsoleBack[:]
612
613 total := len(s)
614 w := 0
615 for _, r := range s {
616 if w >= len(utf16tmp)-2 {
617 writeConsoleUTF16(handle, utf16tmp[:w])
618 w = 0
619 }
620 if r < 0x10000 {
621 utf16tmp[w] = uint16(r)
622 w++
623 } else {
624 r -= 0x10000
625 utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
626 utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
627 w += 2
628 }
629 }
630 writeConsoleUTF16(handle, utf16tmp[:w])
631 unlock(&utf16ConsoleBackLock)
632 return total
633 }
634
635
636
637
638 func writeConsoleUTF16(handle uintptr, b []uint16) {
639 l := uint32(len(b))
640 if l == 0 {
641 return
642 }
643 var written uint32
644 stdcall5(_WriteConsoleW,
645 handle,
646 uintptr(unsafe.Pointer(&b[0])),
647 uintptr(l),
648 uintptr(unsafe.Pointer(&written)),
649 0,
650 )
651 return
652 }
653
654
655 func semasleep(ns int64) int32 {
656 const (
657 _WAIT_ABANDONED = 0x00000080
658 _WAIT_OBJECT_0 = 0x00000000
659 _WAIT_TIMEOUT = 0x00000102
660 _WAIT_FAILED = 0xFFFFFFFF
661 )
662
663 var result uintptr
664 if ns < 0 {
665 result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
666 } else {
667 start := nanotime()
668 elapsed := int64(0)
669 for {
670 ms := int64(timediv(ns-elapsed, 1000000, nil))
671 if ms == 0 {
672 ms = 1
673 }
674 result = stdcall4(_WaitForMultipleObjects, 2,
675 uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
676 0, uintptr(ms))
677 if result != _WAIT_OBJECT_0+1 {
678
679 break
680 }
681 elapsed = nanotime() - start
682 if elapsed >= ns {
683 return -1
684 }
685 }
686 }
687 switch result {
688 case _WAIT_OBJECT_0:
689 return 0
690
691 case _WAIT_TIMEOUT:
692 return -1
693
694 case _WAIT_ABANDONED:
695 systemstack(func() {
696 throw("runtime.semasleep wait_abandoned")
697 })
698
699 case _WAIT_FAILED:
700 systemstack(func() {
701 print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
702 throw("runtime.semasleep wait_failed")
703 })
704
705 default:
706 systemstack(func() {
707 print("runtime: waitforsingleobject unexpected; result=", result, "\n")
708 throw("runtime.semasleep unexpected")
709 })
710 }
711
712 return -1
713 }
714
715
716 func semawakeup(mp *m) {
717 if stdcall1(_SetEvent, mp.waitsema) == 0 {
718 systemstack(func() {
719 print("runtime: setevent failed; errno=", getlasterror(), "\n")
720 throw("runtime.semawakeup")
721 })
722 }
723 }
724
725
726 func semacreate(mp *m) {
727 if mp.waitsema != 0 {
728 return
729 }
730 mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
731 if mp.waitsema == 0 {
732 systemstack(func() {
733 print("runtime: createevent failed; errno=", getlasterror(), "\n")
734 throw("runtime.semacreate")
735 })
736 }
737 mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
738 if mp.resumesema == 0 {
739 systemstack(func() {
740 print("runtime: createevent failed; errno=", getlasterror(), "\n")
741 throw("runtime.semacreate")
742 })
743 stdcall1(_CloseHandle, mp.waitsema)
744 mp.waitsema = 0
745 }
746 }
747
748
749
750
751
752
753 func newosproc(mp *m) {
754
755 thandle := stdcall6(_CreateThread, 0, 0,
756 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
757 0, 0)
758
759 if thandle == 0 {
760 if atomic.Load(&exiting) != 0 {
761
762
763
764
765 lock(&deadlock)
766 lock(&deadlock)
767 }
768 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
769 throw("runtime.newosproc")
770 }
771
772
773 stdcall1(_CloseHandle, thandle)
774 }
775
776
777
778
779
780
781 func newosproc0(mp *m, stk unsafe.Pointer) {
782
783
784
785 throw("bad newosproc0")
786 }
787
788 func exitThread(wait *uint32) {
789
790
791 throw("exitThread")
792 }
793
794
795
796 func mpreinit(mp *m) {
797 }
798
799
800 func msigsave(mp *m) {
801 }
802
803
804 func msigrestore(sigmask sigset) {
805 }
806
807
808
809 func clearSignalHandlers() {
810 }
811
812
813 func sigblock() {
814 }
815
816
817
818 func minit() {
819 var thandle uintptr
820 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
821 atomic.Storeuintptr(&getg().m.thread, thandle)
822
823
824
825 var mbi memoryBasicInformation
826 res := stdcall3(_VirtualQuery, uintptr(unsafe.Pointer(&mbi)), uintptr(unsafe.Pointer(&mbi)), unsafe.Sizeof(mbi))
827 if res == 0 {
828 print("runtime: VirtualQuery failed; errno=", getlasterror(), "\n")
829 throw("VirtualQuery for stack base failed")
830 }
831
832
833
834
835
836
837 base := mbi.allocationBase + 16<<10
838
839 g0 := getg()
840 if base > g0.stack.hi || g0.stack.hi-base > 64<<20 {
841 print("runtime: g0 stack [", hex(base), ",", hex(g0.stack.hi), ")\n")
842 throw("bad g0 stack")
843 }
844 g0.stack.lo = base
845 g0.stackguard0 = g0.stack.lo + _StackGuard
846 g0.stackguard1 = g0.stackguard0
847
848 stackcheck()
849 }
850
851
852
853 func unminit() {
854 tp := &getg().m.thread
855 stdcall1(_CloseHandle, *tp)
856 *tp = 0
857 }
858
859
860
861
862
863 func stdcall(fn stdFunction) uintptr {
864 gp := getg()
865 mp := gp.m
866 mp.libcall.fn = uintptr(unsafe.Pointer(fn))
867 resetLibcall := false
868 if mp.profilehz != 0 && mp.libcallsp == 0 {
869
870 mp.libcallg.set(gp)
871 mp.libcallpc = getcallerpc()
872
873
874 mp.libcallsp = getcallersp()
875 resetLibcall = true
876 }
877 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
878 if resetLibcall {
879 mp.libcallsp = 0
880 }
881 return mp.libcall.r1
882 }
883
884
885 func stdcall0(fn stdFunction) uintptr {
886 mp := getg().m
887 mp.libcall.n = 0
888 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn)))
889 return stdcall(fn)
890 }
891
892
893 func stdcall1(fn stdFunction, a0 uintptr) uintptr {
894 mp := getg().m
895 mp.libcall.n = 1
896 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
897 return stdcall(fn)
898 }
899
900
901 func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
902 mp := getg().m
903 mp.libcall.n = 2
904 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
905 return stdcall(fn)
906 }
907
908
909 func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
910 mp := getg().m
911 mp.libcall.n = 3
912 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
913 return stdcall(fn)
914 }
915
916
917 func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
918 mp := getg().m
919 mp.libcall.n = 4
920 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
921 return stdcall(fn)
922 }
923
924
925 func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
926 mp := getg().m
927 mp.libcall.n = 5
928 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
929 return stdcall(fn)
930 }
931
932
933 func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
934 mp := getg().m
935 mp.libcall.n = 6
936 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
937 return stdcall(fn)
938 }
939
940
941 func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
942 mp := getg().m
943 mp.libcall.n = 7
944 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
945 return stdcall(fn)
946 }
947
948
949 func onosstack(fn unsafe.Pointer, arg uint32)
950 func usleep2(usec uint32)
951 func switchtothread()
952
953 var usleep2Addr unsafe.Pointer
954 var switchtothreadAddr unsafe.Pointer
955
956
957 func osyield() {
958 onosstack(switchtothreadAddr, 0)
959 }
960
961
962 func usleep(us uint32) {
963
964 onosstack(usleep2Addr, 10*us)
965 }
966
967 func ctrlhandler1(_type uint32) uint32 {
968 var s uint32
969
970 switch _type {
971 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
972 s = _SIGINT
973 default:
974 return 0
975 }
976
977 if sigsend(s) {
978 return 1
979 }
980 exit(2)
981 return 0
982 }
983
984
985 func profileloop()
986
987
988 func callbackasm1()
989
990 var profiletimer uintptr
991
992 func profilem(mp *m, thread uintptr) {
993 var r *context
994 rbuf := make([]byte, unsafe.Sizeof(*r)+15)
995
996
997 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
998 r.contextflags = _CONTEXT_CONTROL
999 stdcall2(_GetThreadContext, thread, uintptr(unsafe.Pointer(r)))
1000
1001 var gp *g
1002 switch GOARCH {
1003 default:
1004 panic("unsupported architecture")
1005 case "arm":
1006 tls := &mp.tls[0]
1007 gp = **((***g)(unsafe.Pointer(tls)))
1008 case "386", "amd64":
1009 tls := &mp.tls[0]
1010 gp = *((**g)(unsafe.Pointer(tls)))
1011 }
1012
1013 sigprof(r.ip(), r.sp(), r.lr(), gp, mp)
1014 }
1015
1016 func profileloop1(param uintptr) uint32 {
1017 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
1018
1019 for {
1020 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
1021 first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
1022 for mp := first; mp != nil; mp = mp.alllink {
1023 thread := atomic.Loaduintptr(&mp.thread)
1024
1025
1026
1027 if thread == 0 || mp.profilehz == 0 || mp.blocked {
1028 continue
1029 }
1030
1031
1032 if int32(stdcall1(_SuspendThread, thread)) == -1 {
1033
1034 continue
1035 }
1036 if mp.profilehz != 0 && !mp.blocked {
1037
1038
1039 profilem(mp, thread)
1040 }
1041 stdcall1(_ResumeThread, thread)
1042 }
1043 }
1044 }
1045
1046 func setProcessCPUProfiler(hz int32) {
1047 if profiletimer == 0 {
1048 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
1049 atomic.Storeuintptr(&profiletimer, timer)
1050 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
1051 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
1052 stdcall1(_CloseHandle, thread)
1053 }
1054 }
1055
1056 func setThreadCPUProfiler(hz int32) {
1057 ms := int32(0)
1058 due := ^int64(^uint64(1 << 63))
1059 if hz > 0 {
1060 ms = 1000 / hz
1061 if ms == 0 {
1062 ms = 1
1063 }
1064 due = int64(ms) * -10000
1065 }
1066 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
1067 atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
1068 }
1069
View as plain text