-
-
Notifications
You must be signed in to change notification settings - Fork 240
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #167 from sio/ioctl
Avoid calls to (*os.File).Fd() and operations on raw file descriptor ints
- Loading branch information
Showing
14 changed files
with
214 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
//go:build go1.12 | ||
// +build go1.12 | ||
|
||
package pty | ||
|
||
import ( | ||
"testing" | ||
|
||
"context" | ||
"errors" | ||
"os" | ||
"runtime" | ||
"sync" | ||
"time" | ||
) | ||
|
||
const ( | ||
errMarker byte = 0xEE | ||
timeout = time.Second | ||
) | ||
|
||
var mu sync.Mutex | ||
|
||
// Check that SetDeadline() works for ptmx. | ||
// Outstanding Read() calls must be interrupted by deadline. | ||
// | ||
// https://github.com/creack/pty/issues/162 | ||
func TestReadDeadline(t *testing.T) { | ||
ptmx, success := prepare(t) | ||
|
||
err := ptmx.SetDeadline(time.Now().Add(timeout / 10)) | ||
if err != nil { | ||
if errors.Is(err, os.ErrNoDeadline) { | ||
t.Skipf("deadline is not supported on %s/%s", runtime.GOOS, runtime.GOARCH) | ||
} else { | ||
t.Fatalf("error: set deadline: %v\n", err) | ||
} | ||
} | ||
|
||
var buf = make([]byte, 1) | ||
n, err := ptmx.Read(buf) | ||
success() | ||
|
||
if n != 0 && buf[0] != errMarker { | ||
t.Errorf("received unexpected data from pmtx (%d bytes): 0x%X; err=%v", n, buf, err) | ||
} | ||
} | ||
|
||
// Check that ptmx.Close() interrupts outstanding ptmx.Read() calls | ||
// | ||
// https://github.com/creack/pty/issues/114 | ||
// https://github.com/creack/pty/issues/88 | ||
func TestReadClose(t *testing.T) { | ||
ptmx, success := prepare(t) | ||
|
||
go func() { | ||
time.Sleep(timeout / 10) | ||
err := ptmx.Close() | ||
if err != nil { | ||
t.Errorf("failed to close ptmx: %v", err) | ||
} | ||
}() | ||
|
||
var buf = make([]byte, 1) | ||
n, err := ptmx.Read(buf) | ||
success() | ||
|
||
if n != 0 && buf[0] != errMarker { | ||
t.Errorf("received unexpected data from pmtx (%d bytes): 0x%X; err=%v", n, buf, err) | ||
} | ||
} | ||
|
||
// Open pty and setup watchdogs for graceful and not so graceful failure modes | ||
func prepare(t *testing.T) (ptmx *os.File, done func()) { | ||
if runtime.GOOS == "darwin" { | ||
t.Log("creack/pty uses blocking i/o on darwin intentionally:") | ||
t.Log("> https://github.com/creack/pty/issues/52") | ||
t.Log("> https://github.com/creack/pty/pull/53") | ||
t.Log("> https://github.com/golang/go/issues/22099") | ||
t.SkipNow() | ||
} | ||
|
||
// Due to data race potential in (*os.File).Fd() | ||
// we should never run these two tests in parallel | ||
mu.Lock() | ||
t.Cleanup(mu.Unlock) | ||
|
||
ptmx, pts, err := Open() | ||
if err != nil { | ||
t.Fatalf("error: open: %v\n", err) | ||
} | ||
t.Cleanup(func() { _ = ptmx.Close() }) | ||
t.Cleanup(func() { _ = pts.Close() }) | ||
|
||
ctx, done := context.WithCancel(context.Background()) | ||
t.Cleanup(done) | ||
go func() { | ||
select { | ||
case <-ctx.Done(): | ||
// ptmx.Read() did not block forever, yay! | ||
case <-time.After(timeout): | ||
_, err := pts.Write([]byte{errMarker}) // unblock ptmx.Read() | ||
if err != nil { | ||
t.Errorf("failed to write to pts: %v", err) | ||
} | ||
t.Error("ptmx.Read() was not unblocked") | ||
done() // cancel panic() | ||
} | ||
}() | ||
go func() { | ||
select { | ||
case <-ctx.Done(): | ||
// Test has either failed or succeeded; it definitely did not hang | ||
case <-time.After(timeout * 10 / 9): // timeout +11% | ||
panic("ptmx.Read() was not unblocked; avoid hanging forever") // just in case | ||
} | ||
}() | ||
return ptmx, done | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,23 @@ | ||
//go:build !windows && !solaris && !aix | ||
// +build !windows,!solaris,!aix | ||
//go:build !windows && go1.12 | ||
// +build !windows,go1.12 | ||
|
||
package pty | ||
|
||
import "syscall" | ||
import "os" | ||
|
||
const ( | ||
TIOCGWINSZ = syscall.TIOCGWINSZ | ||
TIOCSWINSZ = syscall.TIOCSWINSZ | ||
) | ||
func ioctl(f *os.File, cmd, ptr uintptr) error { | ||
sc, e := f.SyscallConn() | ||
if e != nil { | ||
return ioctl_inner(f.Fd(), cmd, ptr) // fall back to blocking io (old behavior) | ||
} | ||
|
||
ch := make(chan error, 1) | ||
defer close(ch) | ||
|
||
func ioctl(fd, cmd, ptr uintptr) error { | ||
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr) | ||
if e != 0 { | ||
e = sc.Control(func(fd uintptr) { ch <- ioctl_inner(fd, cmd, ptr) }) | ||
if e != nil { | ||
return e | ||
} | ||
return nil | ||
e = <-ch | ||
return e | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//go:build !windows && !solaris && !aix | ||
// +build !windows,!solaris,!aix | ||
|
||
package pty | ||
|
||
import "syscall" | ||
|
||
const ( | ||
TIOCGWINSZ = syscall.TIOCGWINSZ | ||
TIOCSWINSZ = syscall.TIOCSWINSZ | ||
) | ||
|
||
func ioctl_inner(fd, cmd, ptr uintptr) error { | ||
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr) | ||
if e != 0 { | ||
return e | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
//go:build !windows && !go1.12 | ||
// +build !windows,!go1.12 | ||
|
||
package pty | ||
|
||
import "os" | ||
|
||
func ioctl(f *os.File, cmd, ptr uintptr) error { | ||
return ioctl_inner(f.Fd(), cmd, ptr) // fall back to blocking io (old behavior) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.