Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syscall: timeout parameter to Select is treated as Timespec instead of Timeval on linux/arm64 #22246

Closed
tklauser opened this issue Oct 13, 2017 · 3 comments

Comments

@tklauser
Copy link
Member

@tklauser tklauser commented Oct 13, 2017

What version of Go are you using (go version)?

go version go1.9.1 linux/arm64

Does this issue reproduce with the latest release?

Yes (reproduced on current tip).

What operating system and processor architecture are you using (go env)?

GOARCH="arm64"
GOBIN=""
GOEXE=""
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/tklauser/gopath"
GORACE=""
GOROOT="/home/tklauser/go"
GOTOOLDIR="/home/tklauser/go/pkg/tool/linux_arm64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build256498452=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

What did you do?

Consider the following program which uses syscall.Select to unconditionally sleep for 2 milliseconds:

package main

import (
        "fmt"
        "syscall"
        "time"
)

func main() {
        t := syscall.Timeval{0 /*sec*/, 2000 /*usec*/}

        start := time.Now()
        _, err := syscall.Select(0, nil, nil, nil, &t)
        end := time.Now()

        if err == nil {
                fmt.Printf("select returned after %v\n", end.Sub(start))
        }
}

What did you expect to see?

I'd expect the program to print something similar to select returned after 2.0535ms (the exact number may obviously vary, but should be around 2ms). Running the program e.g. on linux/amd64 indeed produces the expected output.

What did you see instead?

Running the above program on linux/arm64 produces the output select returned after 249.68µs, i.e. the expired timeout is much less than 2ms.

The cause for this is that syscall.Select uses the SYS_PSELECT6 on linux/arm64 (and linux/mips64 for that matter, but I didn't check there). pselect6 expects the timeout argument of type struct timespec with nanosecond precision, while the classic select syscall expects a struct timeval with microsecond precision (see http://man7.org/linux/man-pages/man2/select.2.html, section "The timeout" for details).

Indeed, changing t := syscall.Timeval{0 /*sec*/, 2000 /*usec*/} to t := syscall.Timeval{0 /*sec*/, 2000 * 1000 /*usec*/} in the program above produces the expected output.

SYS_SELECT or SYS__NEWSELECT don't exist on linux/arm64, so the easiest solution is probably to add syscall.pselect and make syscall.Select a wrapper around it, converting the timeout argument. FWIW this is what glibc also does if neither __NR_select nor __NR__newselect is defined for a particular architecture.

Note that the same problem also exists in golang.org/x/sys/unix

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 13, 2017

Change https://golang.org/cl/70590 mentions this issue: syscall: correct type for timeout argument to Select on linux/{arm64,mips64x}

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 13, 2017

Change https://golang.org/cl/70610 mentions this issue: unix: correct type for timeout argument to Select on linux/{arm64,mips64x}

gopherbot pushed a commit to golang/sys that referenced this issue Oct 13, 2017
…s64x}

Follow CL 70590 which did the same for syscall.

unix.Select uses SYS_PSELECT6 on arm64 and mipx64x, however this
syscall expects its 5th argument to be of type Timespec (with seconds
and nanoseconds) instead of type Timeval (with seconds and microseconds)
This leads to the timeout being too short by a factor of 1000.

This CL fixes this by adjusting the timeout argument accordingly,
similarly to how glibc does it for architectures where neither
SYS_SELECT nor SYS__NEWSELECT are available. It also makes Pselect
generaly available on linux.

Updates golang/go#22246

Change-Id: I69f8821a40c59ee469b8a986d784a4db8727ee9a
Reviewed-on: https://go-review.googlesource.com/70610
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
@gopherbot gopherbot closed this in bf237f5 Oct 13, 2017
@gopherbot
Copy link

@gopherbot gopherbot commented Dec 20, 2017

Change https://golang.org/cl/84955 mentions this issue: unix: add timeout tests for Select and Pselect on Linux

gopherbot pushed a commit to golang/sys that referenced this issue Dec 20, 2017
Test for correct timeout behavior of Select and Pselect

Updates golang/go#22246

Change-Id: I86d1804c6ddf5072e93f3ef4f359198e732fae94
Reviewed-on: https://go-review.googlesource.com/84955
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@golang golang locked and limited conversation to collaborators Apr 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.