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 {
tv_nsec int32
}
func (ts *timespec) set_sec(x int32) {
ts.tv_sec = int64(x)
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type timeval struct {
......
......@@ -108,12 +108,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int32) {
ts.tv_sec = int64(x)
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -108,12 +108,9 @@ type timespec struct {
_ [4]byte // EABI
}
func (ts *timespec) set_sec(x int32) {
ts.tv_sec = int64(x)
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type timeval struct {
......
......@@ -161,6 +161,12 @@ type timespec struct {
tv_nsec int64
}
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
tv_sec int64
tv_usec int64
......
......@@ -126,6 +126,13 @@ type timespec struct {
tv_sec 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 {
tv_sec int64
tv_usec int32
......
......@@ -149,9 +149,8 @@ type timespec struct {
}
//go:nosplit
func (t *timespec) set_nsec(ns int64) {
t.tv_sec = int32(ns / 1000000000)
t.tv_nsec = int32(ns % 1000000000)
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
type fpcontrol struct {
......
......@@ -151,9 +151,9 @@ type timespec struct {
}
//go:nosplit
func (t *timespec) set_nsec(ns int64) {
t.tv_sec = ns / 1000000000
t.tv_nsec = ns % 1000000000
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type fpcontrol struct {
......
......@@ -151,9 +151,8 @@ type timespec struct {
}
//go:nosplit
func (t *timespec) set_nsec(ns int64) {
t.tv_sec = int32(ns / 1000000000)
t.tv_nsec = int32(ns % 1000000000)
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
type floatstate32 struct {
......
......@@ -151,9 +151,9 @@ type timespec struct {
}
//go:nosplit
func (t *timespec) set_nsec(ns int64) {
t.tv_sec = ns / 1000000000
t.tv_nsec = ns % 1000000000
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type exceptionstate64 struct {
......
......@@ -174,8 +174,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -191,8 +191,9 @@ type timespec struct {
tv_nsec int32
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = int32(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
type timeval struct {
......
......@@ -201,8 +201,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -163,8 +163,9 @@ type timespec struct {
pad_cgo_0 [4]byte
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type timeval struct {
......
......@@ -137,12 +137,9 @@ type timespec struct {
tv_nsec int32
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = int32(x)
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
type timeval struct {
......
......@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -94,12 +94,9 @@ type timespec struct {
tv_nsec int32
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = int32(x)
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
type stackt struct {
......
......@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -99,13 +99,8 @@ type timespec struct {
}
//go:nosplit
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = int32(x)
}
//go:nosplit
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
}
type timeval struct {
......
......@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -99,12 +99,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -95,12 +95,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -14,6 +14,11 @@ type timespec struct {
tv_nsec int32
}
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type excregs386 struct {
eax uint32
ecx uint32
......
......@@ -14,6 +14,12 @@ type timespec struct {
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 {
eax uint32
ecx uint32
......
......@@ -14,6 +14,11 @@ type timespec struct {
tv_nsec int32
}
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type excregsarm struct {
r0 uint32
r1 uint32
......
......@@ -134,12 +134,9 @@ type timespec struct {
tv_nsec int32
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type timeval struct {
......
......@@ -144,12 +144,10 @@ type timespec struct {
tv_nsec int64
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = int64(x)
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = ns / 1e9
ts.tv_nsec = ns % 1e9
}
type timeval struct {
......
......@@ -139,12 +139,9 @@ type timespec struct {
pad_cgo_0 [4]byte
}
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = x
}
func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
//go:nosplit
func (ts *timespec) setNsec(ns int64) {
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
}
type timeval struct {
......
......@@ -53,7 +53,7 @@ func semasleep(ns int64) int32 {
return -1
}
var t timespec
t.set_nsec(ns - spent)
t.setNsec(ns - spent)
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
if err == _ETIMEDOUT {
pthread_mutex_unlock(&mp.mutex)
......
......@@ -156,7 +156,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) {
if ns >= 0 {
var ut umtx_time
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
}
ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
......
......@@ -35,8 +35,6 @@ const (
// Don't sleep longer than ns; ns < 0 means forever.
//go:nosplit
func futexsleep(addr *uint32, val uint32, ns int64) {
var ts timespec
// Some Linux kernels have a bug where futex of
// FUTEX_WAIT returns an internal error code
// as an errno. Libpthread ignores the return value
......@@ -47,19 +45,8 @@ func futexsleep(addr *uint32, val uint32, ns int64) {
return
}
// It's difficult to live within the no-split stack limits here.
// On ARM and 386, a 64-bit divide invokes a general software routine
// 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)))))
}
var ts timespec
ts.setNsec(ns)
futex(unsafe.Pointer(addr), _FUTEX_WAIT_PRIVATE, val, unsafe.Pointer(&ts), nil, 0)
}
......
......@@ -148,9 +148,7 @@ func semasleep(ns int64) int32 {
if wait <= 0 {
return -1
}
var nsec int32
ts.set_sec(timediv(wait, 1000000000, &nsec))
ts.set_nsec(nsec)
ts.setNsec(wait)
tsp = &ts
}
ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
......
......@@ -139,10 +139,7 @@ func semasleep(ns int64) int32 {
var tsp *timespec
if ns >= 0 {
var ts timespec
var nsec int32
ns += nanotime()
ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
ts.set_nsec(nsec)
ts.setNsec(ns + nanotime())
tsp = &ts
}
......
......@@ -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.
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
// Handles overflow in a time-specific manner.
// This keeps us within no-split stack limits on 32-bit processors.
//go:nosplit
func timediv(v int64, div int32, rem *int32) int32 {
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