]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: clean up system calls during cgo callback init
authorRuss Cox <rsc@golang.org>
Sat, 30 Jan 2021 12:07:42 +0000 (07:07 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 19 Feb 2021 00:01:25 +0000 (00:01 +0000)
During a cgocallback, the runtime calls needm to get an m.
The calls made during needm cannot themselves assume that
there is an m or a g (which is attached to the m).

In the old days of making direct system calls, the only thing
you had to do for such functions was mark them //go:nosplit,
to avoid the use of g in the stack split prologue.

But now, on operating systems that make system calls through
shared libraries and use code that saves state in the g or m
before doing so, it's not safe to assume g exists. In fact, it is
not even safe to call getg(), because it might fault deferencing
the TLS storage to find the g pointer (that storage may not be
initialized yet, at least on Windows, and perhaps on other systems
in the future).

The specific routines that are problematic are usleep and osyield,
which are called during lock contention in lockextra, called
from needm.

All this is rather subtle and hidden, so in addition to fixing the
problem on Windows, this CL makes the fact of not running on
a g much clearer by introducing variants usleep_no_g and
osyield_no_g whose names should make clear that there is no g.
And then we can remove the various sketchy getg() == nil checks
in the existing routines.

As part of this cleanup, this CL also deletes onosstack on Windows.
onosstack is from back when the runtime was implemented in C.
It predates systemstack but does essentially the same thing.
Instead of having two different copies of this code, we can use
systemstack consistently. This way we need not port onosstack
to each architecture.

This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.

Change-Id: I3352de1fd0a3c26267c6e209063e6e86abd26187
Reviewed-on: https://go-review.googlesource.com/c/go/+/288793
Trust: Russ Cox <rsc@golang.org>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
30 files changed:
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_arm.s
src/runtime/asm_arm64.s
src/runtime/asm_mips64x.s
src/runtime/os2_aix.go
src/runtime/os3_solaris.go
src/runtime/os_darwin.go
src/runtime/os_dragonfly.go
src/runtime/os_freebsd.go
src/runtime/os_js.go
src/runtime/os_linux.go
src/runtime/os_netbsd.go
src/runtime/os_openbsd_syscall1.go
src/runtime/os_openbsd_syscall2.go
src/runtime/os_plan9.go
src/runtime/os_windows.go
src/runtime/proc.go
src/runtime/stubs2.go
src/runtime/stubs_386.go
src/runtime/stubs_amd64.go
src/runtime/stubs_arm.go
src/runtime/stubs_arm64.go
src/runtime/stubs_mips64x.go
src/runtime/sys_darwin.go
src/runtime/sys_openbsd1.go
src/runtime/sys_openbsd2.go
src/runtime/sys_windows_386.s
src/runtime/sys_windows_amd64.s
src/runtime/sys_windows_arm.s

index 471451df282c05bcead7bac901d03717e31c60cc..3030101f03d971d911f52eab94aaa94419c248c0 100644 (file)
@@ -621,6 +621,22 @@ TEXT gosave<>(SB),NOSPLIT,$0
        POPL    AX
        RET
 
+// func asmcgocall_no_g(fn, arg unsafe.Pointer)
+// Call fn(arg) aligned appropriately for the gcc ABI.
+// Called on a system stack, and there may be no g yet (during needm).
+TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-8
+       MOVL    fn+0(FP), AX
+       MOVL    arg+4(FP), BX
+       MOVL    SP, DX
+       SUBL    $32, SP
+       ANDL    $~15, SP        // alignment, perhaps unnecessary
+       MOVL    DX, 8(SP)       // save old SP
+       MOVL    BX, 0(SP)       // first argument in x86-32 ABI
+       CALL    AX
+       MOVL    8(SP), DX
+       MOVL    DX, SP
+       RET
+
 // func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
index 05422c9699c45640efe3583662e88f80fd91b7c6..9362ce121372aaea14392417268dc83d8c9e2804 100644 (file)
@@ -679,6 +679,23 @@ TEXT gosave<>(SB),NOSPLIT,$0
        CALL    runtime·badctxt(SB)
        RET
 
+// func asmcgocall_no_g(fn, arg unsafe.Pointer)
+// Call fn(arg) aligned appropriately for the gcc ABI.
+// Called on a system stack, and there may be no g yet (during needm).
+TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16
+       MOVQ    fn+0(FP), AX
+       MOVQ    arg+8(FP), BX
+       MOVQ    SP, DX
+       SUBQ    $32, SP
+       ANDQ    $~15, SP        // alignment
+       MOVQ    DX, 8(SP)
+       MOVQ    BX, DI          // DI = first argument in AMD64 ABI
+       MOVQ    BX, CX          // CX = first argument in Win64
+       CALL    AX
+       MOVQ    8(SP), DX
+       MOVQ    DX, SP
+       RET
+
 // func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
index 23619b14084962e3e0bcd419e647db87221430a5..109030aada467bf892a43739de61422d075cb480 100644 (file)
@@ -552,6 +552,21 @@ TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
        CALL    runtime·badctxt(SB)
        RET
 
+// func asmcgocall_no_g(fn, arg unsafe.Pointer)
+// Call fn(arg) aligned appropriately for the gcc ABI.
+// Called on a system stack, and there may be no g yet (during needm).
+TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-8
+       MOVW    fn+0(FP), R1
+       MOVW    arg+4(FP), R0
+       MOVW    R13, R2
+       SUB     $32, R13
+       BIC     $0x7, R13       // alignment for gcc ABI
+       MOVW    R2, 8(R13)
+       BL      (R1)
+       MOVW    8(R13), R2
+       MOVW    R2, R13
+       RET
+
 // func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
index 0ab92be1e4b95de77e14805fd4864de9f09316fd..79efd4cb17a85d3e23c8e674169fe3e106f65c81 100644 (file)
@@ -873,6 +873,17 @@ TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
        CALL    runtime·badctxt(SB)
        RET
 
+// func asmcgocall_no_g(fn, arg unsafe.Pointer)
+// Call fn(arg) aligned appropriately for the gcc ABI.
+// Called on a system stack, and there may be no g yet (during needm).
+TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16
+       MOVD    fn+0(FP), R1
+       MOVD    arg+8(FP), R0
+       SUB     $16, RSP        // skip over saved frame pointer below RSP
+       BL      (R1)
+       ADD     $16, RSP        // skip over saved frame pointer below RSP
+       RET
+
 // func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
@@ -951,7 +962,7 @@ nosave:
        BL      (R1)
        // Restore stack pointer.
        MOVD    8(RSP), R2
-       MOVD    R2, RSP 
+       MOVD    R2, RSP
        MOVD    R0, ret+16(FP)
        RET
 
index 694950663a920f746e4d5c4d4460dba4a4057703..6e1d25cd90cbb552cb372ca7e2de3a8084aa62aa 100644 (file)
@@ -413,6 +413,15 @@ TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
        JAL     runtime·badctxt(SB)
        RET
 
+// func asmcgocall_no_g(fn, arg unsafe.Pointer)
+// Call fn(arg) aligned appropriately for the gcc ABI.
+// Called on a system stack, and there may be no g yet (during needm).
+TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16
+       MOVV    fn+0(FP), R25
+       MOVV    arg+8(FP), R4
+       JAL     (R25)
+       RET
+
 // func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
index abd1010be93d75a1e8c574c53f878825b065477d..4d77f0de6dd2fea3b50da21268f6d934fcdbb4da 100644 (file)
@@ -527,20 +527,17 @@ func internal_cpu_getsystemcfg(label uint) uint {
 func usleep1(us uint32)
 
 //go:nosplit
-func usleep(us uint32) {
-       _g_ := getg()
+func usleep_no_g(us uint32) {
+       usleep1(us)
+}
 
-       // Check the validity of m because we might be called in cgo callback
-       // path early enough where there isn't a g or a m available yet.
-       if _g_ != nil && _g_.m != nil {
-               r, err := syscall1(&libc_usleep, uintptr(us))
-               if int32(r) == -1 {
-                       println("syscall usleep failed: ", hex(err))
-                       throw("syscall usleep")
-               }
-               return
+//go:nosplit
+func usleep(us uint32) {
+       r, err := syscall1(&libc_usleep, uintptr(us))
+       if int32(r) == -1 {
+               println("syscall usleep failed: ", hex(err))
+               throw("syscall usleep")
        }
-       usleep1(us)
 }
 
 //go:nosplit
@@ -611,20 +608,17 @@ func raiseproc(sig uint32) {
 func osyield1()
 
 //go:nosplit
-func osyield() {
-       _g_ := getg()
+func osyield_no_g() {
+       osyield1()
+}
 
-       // Check the validity of m because it might be called during a cgo
-       // callback early enough where m isn't available yet.
-       if _g_ != nil && _g_.m != nil {
-               r, err := syscall0(&libc_sched_yield)
-               if int32(r) == -1 {
-                       println("syscall osyield failed: ", hex(err))
-                       throw("syscall osyield")
-               }
-               return
+//go:nosplit
+func osyield() {
+       r, err := syscall0(&libc_sched_yield)
+       if int32(r) == -1 {
+               println("syscall osyield failed: ", hex(err))
+               throw("syscall osyield")
        }
-       osyield1()
 }
 
 //go:nosplit
index 6ba11afd93ca439785d05a1e9a3d112beb1ec7a5..4b65139eb81075c543e7bc867ff84dc41ebfef3c 100644 (file)
@@ -521,6 +521,11 @@ func sysconf(name int32) int64 {
 
 func usleep1(usec uint32)
 
+//go:nosplit
+func usleep_no_g(µs uint32) {
+       usleep1(µs)
+}
+
 //go:nosplit
 func usleep(µs uint32) {
        usleep1(µs)
@@ -569,18 +574,15 @@ func setNonblock(fd int32) {
 func osyield1()
 
 //go:nosplit
-func osyield() {
-       _g_ := getg()
-
-       // Check the validity of m because we might be called in cgo callback
-       // path early enough where there isn't a m available yet.
-       if _g_ != nil && _g_.m != nil {
-               sysvicall0(&libc_sched_yield)
-               return
-       }
+func osyield_no_g() {
        osyield1()
 }
 
+//go:nosplit
+func osyield() {
+       sysvicall0(&libc_sched_yield)
+}
+
 //go:linkname executablePath os.executablePath
 var executablePath string
 
index 9ca17c20dff02988b55cd24c9824ba775abe3a45..470698d0a3ab6922ae93edb9539ac9a05e5069bf 100644 (file)
@@ -330,6 +330,11 @@ func unminit() {
 func mdestroy(mp *m) {
 }
 
+//go:nosplit
+func osyield_no_g() {
+       usleep_no_g(1)
+}
+
 //go:nosplit
 func osyield() {
        usleep(1)
index 383df54bd4322a4e6593e17c1bf2a9ac15fd1ca7..b786c8ab5f79e1ba703534301e912c4556fce999 100644 (file)
@@ -51,6 +51,11 @@ func sys_umtx_wakeup(addr *uint32, val int32) int32
 
 func osyield()
 
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
+
 func kqueue() int32
 
 //go:noescape
index 09065ccb68232df785f2d7e33abe1fca46fd3668..09dd50ce59477583ff418da334e3769f191890a4 100644 (file)
@@ -36,6 +36,11 @@ func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_
 
 func osyield()
 
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
+
 func kqueue() int32
 
 //go:noescape
index 24261e88a2060310ea155375c1e17673ebc9c9c3..5b2c53795a2d32f8bf6c38e8933de231d3324817 100644 (file)
@@ -30,12 +30,22 @@ func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
 
 func usleep(usec uint32)
 
+//go:nosplit
+func usleep_no_g(usec uint32) {
+       usleep(usec)
+}
+
 func exitThread(wait *uint32)
 
 type mOS struct{}
 
 func osyield()
 
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
+
 const _SIGSEGV = 0xb
 
 func sigpanic() {
index 058c7daf9c60d19d51545aceed41148e56f7f0c4..21d3ae653ec9d48ff58ad5f4fc23f36135c57a3e 100644 (file)
@@ -410,6 +410,11 @@ func raiseproc(sig uint32)
 func sched_getaffinity(pid, len uintptr, buf *byte) int32
 func osyield()
 
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
+
 func pipe() (r, w int32, errno int32)
 func pipe2(flags int32) (r, w int32, errno int32)
 func setNonblock(fd int32)
index 2b742a37116ba575a28c97fbc65379a7251d8974..0328fa57ae67082b05e054b45a93877a924c4898 100644 (file)
@@ -67,6 +67,11 @@ func lwp_self() int32
 
 func osyield()
 
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
+
 func kqueue() int32
 
 //go:noescape
index b0bef4c5043bd100303728af085dc9e5bc63cee2..f37da04194ecc929ebae305379d6eaa4448d65a0 100644 (file)
@@ -13,3 +13,8 @@ func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort
 func thrwakeup(ident uintptr, n int32) int32
 
 func osyield()
+
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
index ab940510af152cfa19448d4dcb71718bf696fb49..81cfb085aa4256a8a4863fffbfe7620f7e92dd50 100644 (file)
@@ -32,6 +32,11 @@ func closefd(fd int32) int32
 func exit(code int32)
 func usleep(usec uint32)
 
+//go:nosplit
+func usleep_no_g(usec uint32) {
+       usleep(usec)
+}
+
 // write calls the write system call.
 // It returns a non-negative number of bytes written or a negative errno value.
 //go:noescape
index 2a84a73716078fe9fec3ea169aff505d4079f689..77665f461ae1924a38194f95e01808c95b75d1f8 100644 (file)
@@ -339,6 +339,11 @@ func osyield() {
        sleep(0)
 }
 
+//go:nosplit
+func osyield_no_g() {
+       osyield()
+}
+
 //go:nosplit
 func usleep(µs uint32) {
        ms := int32(µs / 1000)
@@ -348,6 +353,11 @@ func usleep(µs uint32) {
        sleep(ms)
 }
 
+//go:nosplit
+func usleep_no_g(usec uint32) {
+       usleep(usec)
+}
+
 //go:nosplit
 func nanotime1() int64 {
        var scratch int64
index e6b22e316716982101fe0c92b3208e41e0fa7ed2..1bf3309dfd9cf55fa3a2c4c4e410a43a29833c6f 100644 (file)
@@ -461,15 +461,12 @@ func initHighResTimer() {
        h := createHighResTimer()
        if h != 0 {
                haveHighResTimer = true
-               usleep2Addr = unsafe.Pointer(funcPC(usleep2HighRes))
                stdcall1(_CloseHandle, h)
        }
 }
 
 func osinit() {
        asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
-       usleep2Addr = unsafe.Pointer(funcPC(usleep2))
-       switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread))
 
        setBadSignalMsg()
 
@@ -1061,26 +1058,39 @@ func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
        return stdcall(fn)
 }
 
-// In sys_windows_386.s and sys_windows_amd64.s.
-func onosstack(fn unsafe.Pointer, arg uint32)
-
-// These are not callable functions. They should only be called via onosstack.
-func usleep2(usec uint32)
-func usleep2HighRes(usec uint32)
+// These must run on the system stack only.
+func usleep2(dt int32)
+func usleep2HighRes(dt int32)
 func switchtothread()
 
-var usleep2Addr unsafe.Pointer
-var switchtothreadAddr unsafe.Pointer
+//go:nosplit
+func osyield_no_g() {
+       switchtothread()
+}
 
 //go:nosplit
 func osyield() {
-       onosstack(switchtothreadAddr, 0)
+       systemstack(switchtothread)
+}
+
+//go:nosplit
+func usleep_no_g(us uint32) {
+       dt := -10 * int32(us) // relative sleep (negative), 100ns units
+       usleep2(dt)
 }
 
 //go:nosplit
 func usleep(us uint32) {
-       // Have 1us units; want 100ns units.
-       onosstack(usleep2Addr, 10*us)
+       systemstack(func() {
+               dt := -10 * int32(us) // relative sleep (negative), 100ns units
+               // If the high-res timer is available and its handle has been allocated for this m, use it.
+               // Otherwise fall back to the low-res one, which doesn't need a handle.
+               if haveHighResTimer && getg().m.highResTimer != 0 {
+                       usleep2HighRes(dt)
+               } else {
+                       usleep2(dt)
+               }
+       })
 }
 
 func ctrlhandler1(_type uint32) uint32 {
index 73a789c18973e793bda325d3769bfc0ecbb0e98c..4092dd55cbf7f41564d213ee80efcc4043ecc1cc 100644 (file)
@@ -2012,7 +2012,7 @@ func lockextra(nilokay bool) *m {
        for {
                old := atomic.Loaduintptr(&extram)
                if old == locked {
-                       osyield()
+                       osyield_no_g()
                        continue
                }
                if old == 0 && !nilokay {
@@ -2023,13 +2023,13 @@ func lockextra(nilokay bool) *m {
                                atomic.Xadd(&extraMWaiters, 1)
                                incr = true
                        }
-                       usleep(1)
+                       usleep_no_g(1)
                        continue
                }
                if atomic.Casuintptr(&extram, old, locked) {
                        return (*m)(unsafe.Pointer(old))
                }
-               osyield()
+               osyield_no_g()
                continue
        }
 }
index 85088b3ab9f9265ea8612ed9f643bc6c36acf02d..96096d236b8cb23589f58f8ce06e341c64f73b27 100644 (file)
@@ -23,6 +23,11 @@ func closefd(fd int32) int32
 func exit(code int32)
 func usleep(usec uint32)
 
+//go:nosplit
+func usleep_no_g(usec uint32) {
+       usleep(usec)
+}
+
 // write calls the write system call.
 // It returns a non-negative number of bytes written or a negative errno value.
 //go:noescape
index 5108294d83375750819c817b8a06e82658e7407c..300f167fff3132ec2a2d4a53e2b7ac7a5f85cc5c 100644 (file)
@@ -15,3 +15,6 @@ func stackcheck()
 // Called from assembly only; declared for go vet.
 func setldt(slot uintptr, base unsafe.Pointer, size uintptr)
 func emptyfunc()
+
+//go:noescape
+func asmcgocall_no_g(fn, arg unsafe.Pointer)
index 8c14bc227162691631014dd005f9dad60968e96c..bf98493e9dd590b020a1c63409bbe23b868cd85b 100644 (file)
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 // Called from compiled code; declared for vet; do NOT call from Go.
 func gcWriteBarrierCX()
 func gcWriteBarrierDX()
@@ -35,3 +37,6 @@ func retpolineR12()
 func retpolineR13()
 func retpolineR14()
 func retpolineR15()
+
+//go:noescape
+func asmcgocall_no_g(fn, arg unsafe.Pointer)
index c13bf16de2f420c4a4094440acc4df01c0c03e98..52c32937aead8ca998408e265adef8c42c2786cd 100644 (file)
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 // Called from compiler-generated code; declared for go vet.
 func udiv()
 func _div()
@@ -18,3 +20,6 @@ func save_g()
 func emptyfunc()
 func _initcgo()
 func read_tls_fallback()
+
+//go:noescape
+func asmcgocall_no_g(fn, arg unsafe.Pointer)
index 44c566e602d5a3033093a4a4a93b16f85a60401e..6e6e7df6b8129fef9c14a91d48443d91af9fe7d9 100644 (file)
@@ -4,6 +4,11 @@
 
 package runtime
 
+import "unsafe"
+
 // Called from assembly only; declared for go vet.
 func load_g()
 func save_g()
+
+//go:noescape
+func asmcgocall_no_g(fn, arg unsafe.Pointer)
index 4e62c1ce908934eac01987e00e18a5d3afcd7fab..652e7a9e34b612596b85adaf9a7f76a2977b60b0 100644 (file)
@@ -6,6 +6,11 @@
 
 package runtime
 
+import "unsafe"
+
 // Called from assembly only; declared for go vet.
 func load_g()
 func save_g()
+
+//go:noescape
+func asmcgocall_no_g(fn, arg unsafe.Pointer)
index 4a3f2fc453d30935cc71755ce0994bd7e7facdd2..dacce2ee1abb5149c21f4b4239b41f81c851659f 100644 (file)
@@ -227,6 +227,12 @@ func usleep(usec uint32) {
 }
 func usleep_trampoline()
 
+//go:nosplit
+//go:cgo_unsafe_args
+func usleep_no_g(usec uint32) {
+       asmcgocall_no_g(unsafe.Pointer(funcPC(usleep_trampoline)), unsafe.Pointer(&usec))
+}
+
 //go:nosplit
 //go:cgo_unsafe_args
 func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
index e2886218db5da06b1893e73d1b5c08db8c61f461..44c7871ceb1527cf396a53e3850b64d7b38c783a 100644 (file)
@@ -27,6 +27,11 @@ func osyield() {
 }
 func sched_yield_trampoline()
 
+//go:nosplit
+func osyield_no_g() {
+       asmcgocall_no_g(unsafe.Pointer(funcPC(sched_yield_trampoline)), unsafe.Pointer(nil))
+}
+
 //go:cgo_import_dynamic libc_thrsleep __thrsleep "libc.so"
 //go:cgo_import_dynamic libc_thrwakeup __thrwakeup "libc.so"
 //go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"
index 474e7145e796220187bba2817a7eb0e513d27ea2..33032596c3f6884648055af329be3009dfa6d305 100644 (file)
@@ -128,6 +128,12 @@ func usleep(usec uint32) {
 }
 func usleep_trampoline()
 
+//go:nosplit
+//go:cgo_unsafe_args
+func usleep_no_g(usec uint32) {
+       asmcgocall_no_g(unsafe.Pointer(funcPC(usleep_trampoline)), unsafe.Pointer(&usec))
+}
+
 //go:nosplit
 //go:cgo_unsafe_args
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 {
index ef8a3dd3c27d67a2358c2d8f931ea9326abb719b..b3972ac78d2dfd737a1ecc2a18b26adde7ca901f 100644 (file)
@@ -347,60 +347,11 @@ TEXT runtime·setldt(SB),NOSPLIT,$0
        MOVL    CX, 0x14(FS)
        RET
 
-// onosstack calls fn on OS stack.
-// func onosstack(fn unsafe.Pointer, arg uint32)
-TEXT runtime·onosstack(SB),NOSPLIT,$0
-       MOVL    fn+0(FP), AX            // to hide from 8l
-       MOVL    arg+4(FP), BX
-
-       // Execute call on m->g0 stack, in case we are not actually
-       // calling a system call wrapper, like when running under WINE.
-       get_tls(CX)
-       CMPL    CX, $0
-       JNE     3(PC)
-       // Not a Go-managed thread. Do not switch stack.
-       CALL    AX
-       RET
-
-       MOVL    g(CX), BP
-       MOVL    g_m(BP), BP
-
-       // leave pc/sp for cpu profiler
-       MOVL    (SP), SI
-       MOVL    SI, m_libcallpc(BP)
-       MOVL    g(CX), SI
-       MOVL    SI, m_libcallg(BP)
-       // sp must be the last, because once async cpu profiler finds
-       // all three values to be non-zero, it will use them
-       LEAL    fn+0(FP), SI
-       MOVL    SI, m_libcallsp(BP)
-
-       MOVL    m_g0(BP), SI
-       CMPL    g(CX), SI
-       JNE     switch
-       // executing on m->g0 already
-       CALL    AX
-       JMP     ret
-
-switch:
-       // Switch to m->g0 stack and back.
-       MOVL    (g_sched+gobuf_sp)(SI), SI
-       MOVL    SP, -4(SI)
-       LEAL    -4(SI), SP
-       CALL    AX
-       MOVL    0(SP), SP
-
-ret:
-       get_tls(CX)
-       MOVL    g(CX), BP
-       MOVL    g_m(BP), BP
-       MOVL    $0, m_libcallsp(BP)
-       RET
-
-// Runs on OS stack. duration (in 100ns units) is in BX.
-TEXT runtime·usleep2(SB),NOSPLIT,$20
-       // Want negative 100ns units.
-       NEGL    BX
+// Runs on OS stack.
+// duration (in -100ns units) is in dt+0(FP).
+// g may be nil.
+TEXT runtime·usleep2(SB),NOSPLIT,$20-4
+       MOVL    dt+0(FP), BX
        MOVL    $-1, hi-4(SP)
        MOVL    BX, lo-8(SP)
        LEAL    lo-8(SP), BX
@@ -413,17 +364,15 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
        MOVL    BP, SP
        RET
 
-// Runs on OS stack. duration (in 100ns units) is in BX.
-TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36
-       get_tls(CX)
-       CMPL    CX, $0
-       JE      gisnotset
-
-       // Want negative 100ns units.
-       NEGL    BX
+// Runs on OS stack.
+// duration (in -100ns units) is in dt+0(FP).
+// g is valid.
+TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36-4
+       MOVL    dt+0(FP), BX
        MOVL    $-1, hi-4(SP)
        MOVL    BX, lo-8(SP)
 
+       get_tls(CX)
        MOVL    g(CX), CX
        MOVL    g_m(CX), CX
        MOVL    (m_mOS+mOS_highResTimer)(CX), CX
@@ -452,12 +401,6 @@ TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36
 
        RET
 
-gisnotset:
-       // TLS is not configured. Call usleep2 instead.
-       MOVL    $runtime·usleep2(SB), AX
-       CALL    AX
-       RET
-
 // Runs on OS stack.
 TEXT runtime·switchtothread(SB),NOSPLIT,$0
        MOVL    SP, BP
index d1690cad587ba844094ab3bcfabad6406ebae0ea..2bd7b748483594c41411ae05748f6c32a3583726 100644 (file)
@@ -388,61 +388,16 @@ TEXT runtime·settls(SB),NOSPLIT,$0
        MOVQ    DI, 0x28(GS)
        RET
 
-// func onosstack(fn unsafe.Pointer, arg uint32)
-TEXT runtime·onosstack(SB),NOSPLIT,$0
-       MOVQ    fn+0(FP), AX            // to hide from 6l
-       MOVL    arg+8(FP), BX
-
-       // Execute call on m->g0 stack, in case we are not actually
-       // calling a system call wrapper, like when running under WINE.
-       get_tls(R15)
-       CMPQ    R15, $0
-       JNE     3(PC)
-       // Not a Go-managed thread. Do not switch stack.
-       CALL    AX
-       RET
-
-       MOVQ    g(R15), R13
-       MOVQ    g_m(R13), R13
-
-       // leave pc/sp for cpu profiler
-       MOVQ    (SP), R12
-       MOVQ    R12, m_libcallpc(R13)
-       MOVQ    g(R15), R12
-       MOVQ    R12, m_libcallg(R13)
-       // sp must be the last, because once async cpu profiler finds
-       // all three values to be non-zero, it will use them
-       LEAQ    fn+0(FP), R12
-       MOVQ    R12, m_libcallsp(R13)
-
-       MOVQ    m_g0(R13), R14
-       CMPQ    g(R15), R14
-       JNE     switch
-       // executing on m->g0 already
-       CALL    AX
-       JMP     ret
-
-switch:
-       // Switch to m->g0 stack and back.
-       MOVQ    (g_sched+gobuf_sp)(R14), R14
-       MOVQ    SP, -8(R14)
-       LEAQ    -8(R14), SP
-       CALL    AX
-       MOVQ    0(SP), SP
-
-ret:
-       MOVQ    $0, m_libcallsp(R13)
-       RET
-
-// Runs on OS stack. duration (in 100ns units) is in BX.
+// Runs on OS stack.
+// duration (in -100ns units) is in dt+0(FP).
+// g may be nil.
 // The function leaves room for 4 syscall parameters
 // (as per windows amd64 calling convention).
-TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
+TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48-4
+       MOVLQSX dt+0(FP), BX
        MOVQ    SP, AX
        ANDQ    $~15, SP        // alignment as per Windows requirement
        MOVQ    AX, 40(SP)
-       // Want negative 100ns units.
-       NEGQ    BX
        LEAQ    32(SP), R8  // ptime
        MOVQ    BX, (R8)
        MOVQ    $-1, CX // handle
@@ -452,11 +407,11 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
        MOVQ    40(SP), SP
        RET
 
-// Runs on OS stack. duration (in 100ns units) is in BX.
-TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
+// Runs on OS stack. duration (in -100ns units) is in dt+0(FP).
+// g is valid.
+TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72-4
+       MOVLQSX dt+0(FP), BX
        get_tls(CX)
-       CMPQ    CX, $0
-       JE      gisnotset
 
        MOVQ    SP, AX
        ANDQ    $~15, SP        // alignment as per Windows requirement
@@ -466,8 +421,6 @@ TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
        MOVQ    g_m(CX), CX
        MOVQ    (m_mOS+mOS_highResTimer)(CX), CX        // hTimer
        MOVQ    CX, 48(SP)                              // save hTimer for later
-       // Want negative 100ns units.
-       NEGQ    BX
        LEAQ    56(SP), DX                              // lpDueTime
        MOVQ    BX, (DX)
        MOVQ    $0, R8                                  // lPeriod
@@ -487,12 +440,6 @@ TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
        MOVQ    64(SP), SP
        RET
 
-gisnotset:
-       // TLS is not configured. Call usleep2 instead.
-       MOVQ    $runtime·usleep2(SB), AX
-       CALL    AX
-       RET
-
 // Runs on OS stack.
 TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
        MOVQ    SP, AX
index fe267080ccab8e1e7593d0e3a46408a5bf2a362f..1d928a4f7d35dacb60867ca5429b323cb3a8b4b7 100644 (file)
@@ -377,79 +377,11 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0
        MOVW    $0, R0
        MOVM.IA.W (R13), [R4-R11, R15]          // pop {r4-r11, pc}
 
-// onosstack calls fn on OS stack.
-// adapted from asm_arm.s : systemstack
-// func onosstack(fn unsafe.Pointer, arg uint32)
-TEXT runtime·onosstack(SB),NOSPLIT,$0
-       MOVW    fn+0(FP), R5            // R5 = fn
-       MOVW    arg+4(FP), R6           // R6 = arg
-
-       // This function can be called when there is no g,
-       // for example, when we are handling a callback on a non-go thread.
-       // In this case we're already on the system stack.
-       CMP     $0, g
-       BEQ     noswitch
-
-       MOVW    g_m(g), R1              // R1 = m
-
-       MOVW    m_gsignal(R1), R2       // R2 = gsignal
-       CMP     g, R2
-       B.EQ    noswitch
-
-       MOVW    m_g0(R1), R2            // R2 = g0
-       CMP     g, R2
-       B.EQ    noswitch
-
-       MOVW    m_curg(R1), R3
-       CMP     g, R3
-       B.EQ    switch
-
-       // Bad: g is not gsignal, not g0, not curg. What is it?
-       // Hide call from linker nosplit analysis.
-       MOVW    $runtime·badsystemstack(SB), R0
-       BL      (R0)
-       B       runtime·abort(SB)
-
-switch:
-       // save our state in g->sched. Pretend to
-       // be systemstack_switch if the G stack is scanned.
-       MOVW    $runtime·systemstack_switch(SB), R3
-       ADD     $4, R3, R3 // get past push {lr}
-       MOVW    R3, (g_sched+gobuf_pc)(g)
-       MOVW    R13, (g_sched+gobuf_sp)(g)
-       MOVW    LR, (g_sched+gobuf_lr)(g)
-       MOVW    g, (g_sched+gobuf_g)(g)
-
-       // switch to g0
-       MOVW    R2, g
-       MOVW    (g_sched+gobuf_sp)(R2), R3
-       // make it look like mstart called systemstack on g0, to stop traceback
-       SUB     $4, R3, R3
-       MOVW    $runtime·mstart(SB), R4
-       MOVW    R4, 0(R3)
-       MOVW    R3, R13
-
-       // call target function
-       MOVW    R6, R0          // arg
-       BL      (R5)
-
-       // switch back to g
-       MOVW    g_m(g), R1
-       MOVW    m_curg(R1), g
-       MOVW    (g_sched+gobuf_sp)(g), R13
-       MOVW    $0, R3
-       MOVW    R3, (g_sched+gobuf_sp)(g)
-       RET
-
-noswitch:
-       // Using a tail call here cleans up tracebacks since we won't stop
-       // at an intermediate systemstack.
-       MOVW.P  4(R13), R14     // restore LR
-       MOVW    R6, R0          // arg
-       B       (R5)
-
-// Runs on OS stack. Duration (in 100ns units) is in R0.
-TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0
+// Runs on OS stack.
+// duration (in -100ns units) is in dt+0(FP).
+// g may be nil.
+TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0-4
+       MOVW    dt+0(FP), R0
        MOVM.DB.W [R4, R14], (R13)      // push {r4, lr}
        MOVW    R13, R4                 // Save SP
        SUB     $8, R13                 // R13 = R13 - 8
@@ -465,9 +397,11 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0
        MOVW    R4, R13                 // Restore SP
        MOVM.IA.W (R13), [R4, R15]      // pop {R4, pc}
 
-// Runs on OS stack. Duration (in 100ns units) is in R0.
+// Runs on OS stack.
+// duration (in -100ns units) is in dt+0(FP).
+// g is valid.
 // TODO: neeeds to be implemented properly.
-TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0
+TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0-4
        B       runtime·abort(SB)
 
 // Runs on OS stack.