Commit 0a7bc8f4 authored by Ian Lance Taylor's avatar Ian Lance Taylor

runtime: introduce and consistently use setNsec for timespec

The general code for setting a timespec value sometimes used set_nsec
and sometimes used a combination of set_sec and set_nsec. Standardize
on a setNsec function that takes a number of nanoseconds and splits
them up to set the tv_sec and tv_nsec fields. Consistently mark
setNsec as go:nosplit, since it has to be that way on some systems
including Darwin and GNU/Linux. Consistently use timediv on 32-bit
systems to help stay within split-stack limits on processors that
don't have a 64-bit division instruction.

Change-Id: I6396bb7ddbef171a96876bdeaf7a1c585a6d725b
Reviewed-on: https://go-review.googlesource.com/c/go/+/167389
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 829c140f
...@@ -106,12 +106,9 @@ type timespec struct { ...@@ -106,12 +106,9 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
func (ts *timespec) set_sec(x int32) { //go:nosplit
ts.tv_sec = int64(x) func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type timeval struct { type timeval struct {
......
...@@ -108,12 +108,10 @@ type timespec struct { ...@@ -108,12 +108,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int32) { //go:nosplit
ts.tv_sec = int64(x) func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -108,12 +108,9 @@ type timespec struct { ...@@ -108,12 +108,9 @@ type timespec struct {
_ [4]byte // EABI _ [4]byte // EABI
} }
func (ts *timespec) set_sec(x int32) { //go:nosplit
ts.tv_sec = int64(x) func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type timeval struct { type timeval struct {
......
...@@ -161,6 +161,12 @@ type timespec struct { ...@@ -161,6 +161,12 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct { type timeval struct {
tv_sec int64 tv_sec int64
tv_usec int64 tv_usec int64
......
...@@ -126,6 +126,13 @@ type timespec struct { ...@@ -126,6 +126,13 @@ type timespec struct {
tv_sec int64 tv_sec int64
tv_nsec int64 tv_nsec int64
} }
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct { type timeval struct {
tv_sec int64 tv_sec int64
tv_usec int32 tv_usec int32
......
...@@ -149,9 +149,8 @@ type timespec struct { ...@@ -149,9 +149,8 @@ type timespec struct {
} }
//go:nosplit //go:nosplit
func (t *timespec) set_nsec(ns int64) { func (ts *timespec) setNsec(ns int64) {
t.tv_sec = int32(ns / 1000000000) ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
t.tv_nsec = int32(ns % 1000000000)
} }
type fpcontrol struct { type fpcontrol struct {
......
...@@ -151,9 +151,9 @@ type timespec struct { ...@@ -151,9 +151,9 @@ type timespec struct {
} }
//go:nosplit //go:nosplit
func (t *timespec) set_nsec(ns int64) { func (ts *timespec) setNsec(ns int64) {
t.tv_sec = ns / 1000000000 ts.tv_sec = ns / 1e9
t.tv_nsec = ns % 1000000000 ts.tv_nsec = ns % 1e9
} }
type fpcontrol struct { type fpcontrol struct {
......
...@@ -151,9 +151,8 @@ type timespec struct { ...@@ -151,9 +151,8 @@ type timespec struct {
} }
//go:nosplit //go:nosplit
func (t *timespec) set_nsec(ns int64) { func (ts *timespec) setNsec(ns int64) {
t.tv_sec = int32(ns / 1000000000) ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
t.tv_nsec = int32(ns % 1000000000)
} }
type floatstate32 struct { type floatstate32 struct {
......
...@@ -151,9 +151,9 @@ type timespec struct { ...@@ -151,9 +151,9 @@ type timespec struct {
} }
//go:nosplit //go:nosplit
func (t *timespec) set_nsec(ns int64) { func (ts *timespec) setNsec(ns int64) {
t.tv_sec = ns / 1000000000 ts.tv_sec = ns / 1e9
t.tv_nsec = ns % 1000000000 ts.tv_nsec = ns % 1e9
} }
type exceptionstate64 struct { type exceptionstate64 struct {
......
...@@ -174,8 +174,10 @@ type timespec struct { ...@@ -174,8 +174,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
} }
type timeval struct { type timeval struct {
......
...@@ -191,8 +191,9 @@ type timespec struct { ...@@ -191,8 +191,9 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = int32(x) func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
} }
type timeval struct { type timeval struct {
......
...@@ -201,8 +201,10 @@ type timespec struct { ...@@ -201,8 +201,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
} }
type timeval struct { type timeval struct {
......
...@@ -163,8 +163,9 @@ type timespec struct { ...@@ -163,8 +163,9 @@ type timespec struct {
pad_cgo_0 [4]byte pad_cgo_0 [4]byte
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
} }
type timeval struct { type timeval struct {
......
...@@ -137,12 +137,9 @@ type timespec struct { ...@@ -137,12 +137,9 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = int32(x) func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type timeval struct { type timeval struct {
......
...@@ -99,12 +99,10 @@ type timespec struct { ...@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -94,12 +94,9 @@ type timespec struct { ...@@ -94,12 +94,9 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = int32(x) func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type stackt struct { type stackt struct {
......
...@@ -99,12 +99,10 @@ type timespec struct { ...@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -99,12 +99,10 @@ type timespec struct { ...@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -99,13 +99,8 @@ type timespec struct { ...@@ -99,13 +99,8 @@ type timespec struct {
} }
//go:nosplit //go:nosplit
func (ts *timespec) set_sec(x int64) { func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int32(x) ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
//go:nosplit
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type timeval struct { type timeval struct {
......
...@@ -99,12 +99,10 @@ type timespec struct { ...@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -99,12 +99,10 @@ type timespec struct { ...@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -95,12 +95,10 @@ type timespec struct { ...@@ -95,12 +95,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -14,6 +14,11 @@ type timespec struct { ...@@ -14,6 +14,11 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type excregs386 struct { type excregs386 struct {
eax uint32 eax uint32
ecx uint32 ecx uint32
......
...@@ -14,6 +14,12 @@ type timespec struct { ...@@ -14,6 +14,12 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = int32(ns % 1e9)
}
type excregs386 struct { type excregs386 struct {
eax uint32 eax uint32
ecx uint32 ecx uint32
......
...@@ -14,6 +14,11 @@ type timespec struct { ...@@ -14,6 +14,11 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type excregsarm struct { type excregsarm struct {
r0 uint32 r0 uint32
r1 uint32 r1 uint32
......
...@@ -134,12 +134,9 @@ type timespec struct { ...@@ -134,12 +134,9 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type timeval struct { type timeval struct {
......
...@@ -144,12 +144,10 @@ type timespec struct { ...@@ -144,12 +144,10 @@ type timespec struct {
tv_nsec int64 tv_nsec int64
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
} }
type timeval struct { type timeval struct {
......
...@@ -139,12 +139,9 @@ type timespec struct { ...@@ -139,12 +139,9 @@ type timespec struct {
pad_cgo_0 [4]byte pad_cgo_0 [4]byte
} }
func (ts *timespec) set_sec(x int64) { //go:nosplit
ts.tv_sec = x func (ts *timespec) setNsec(ns int64) {
} ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
} }
type timeval struct { type timeval struct {
......
...@@ -53,7 +53,7 @@ func semasleep(ns int64) int32 { ...@@ -53,7 +53,7 @@ func semasleep(ns int64) int32 {
return -1 return -1
} }
var t timespec var t timespec
t.set_nsec(ns - spent) t.setNsec(ns - spent)
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t) err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
if err == _ETIMEDOUT { if err == _ETIMEDOUT {
pthread_mutex_unlock(&mp.mutex) pthread_mutex_unlock(&mp.mutex)
......
...@@ -156,7 +156,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) { ...@@ -156,7 +156,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) {
if ns >= 0 { if ns >= 0 {
var ut umtx_time var ut umtx_time
ut._clockid = _CLOCK_MONOTONIC ut._clockid = _CLOCK_MONOTONIC
ut._timeout.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ut._timeout.tv_nsec))))) ut._timeout.setNsec(ns)
utp = &ut utp = &ut
} }
ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp) ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
......
...@@ -35,8 +35,6 @@ const ( ...@@ -35,8 +35,6 @@ const (
// Don't sleep longer than ns; ns < 0 means forever. // Don't sleep longer than ns; ns < 0 means forever.
//go:nosplit //go:nosplit
func futexsleep(addr *uint32, val uint32, ns int64) { func futexsleep(addr *uint32, val uint32, ns int64) {
var ts timespec
// Some Linux kernels have a bug where futex of // Some Linux kernels have a bug where futex of
// FUTEX_WAIT returns an internal error code // FUTEX_WAIT returns an internal error code
// as an errno. Libpthread ignores the return value // as an errno. Libpthread ignores the return value
...@@ -47,19 +45,8 @@ func futexsleep(addr *uint32, val uint32, ns int64) { ...@@ -47,19 +45,8 @@ func futexsleep(addr *uint32, val uint32, ns int64) {
return return
} }
// It's difficult to live within the no-split stack limits here. var ts timespec
// On ARM and 386, a 64-bit divide invokes a general software routine ts.setNsec(ns)
// that needs more stack than we can afford. So we use timediv instead.
// But on real 64-bit systems, where words are larger but the stack limit
// is not, even timediv is too heavy, and we really need to use just an
// ordinary machine instruction.
if sys.PtrSize == 8 {
ts.set_sec(ns / 1000000000)
ts.set_nsec(int32(ns % 1000000000))
} else {
ts.tv_nsec = 0
ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
}
futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, unsafe.Pointer(&ts), nil, 0) futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, unsafe.Pointer(&ts), nil, 0)
} }
......
...@@ -148,9 +148,7 @@ func semasleep(ns int64) int32 { ...@@ -148,9 +148,7 @@ func semasleep(ns int64) int32 {
if wait <= 0 { if wait <= 0 {
return -1 return -1
} }
var nsec int32 ts.setNsec(wait)
ts.set_sec(timediv(wait, 1000000000, &nsec))
ts.set_nsec(nsec)
tsp = &ts tsp = &ts
} }
ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
......
...@@ -139,10 +139,7 @@ func semasleep(ns int64) int32 { ...@@ -139,10 +139,7 @@ func semasleep(ns int64) int32 {
var tsp *timespec var tsp *timespec
if ns >= 0 { if ns >= 0 {
var ts timespec var ts timespec
var nsec int32 ts.setNsec(ns + nanotime())
ns += nanotime()
ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
ts.set_nsec(nsec)
tsp = &ts tsp = &ts
} }
......
...@@ -412,6 +412,7 @@ func setTraceback(level string) { ...@@ -412,6 +412,7 @@ func setTraceback(level string) {
// This is a very special function, do not use it if you are not sure what you are doing. // This is a very special function, do not use it if you are not sure what you are doing.
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions. // int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
// Handles overflow in a time-specific manner. // Handles overflow in a time-specific manner.
// This keeps us within no-split stack limits on 32-bit processors.
//go:nosplit //go:nosplit
func timediv(v int64, div int32, rem *int32) int32 { func timediv(v int64, div int32, rem *int32) int32 {
res := int32(0) res := int32(0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment