63 lines
1.3 KiB
Go
63 lines
1.3 KiB
Go
//go:build darwin
|
|
|
|
package stopfd
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
type StopFD struct {
|
|
ReadFD int
|
|
WriteFD int
|
|
}
|
|
|
|
func New() (StopFD, error) {
|
|
fds := make([]int, 2)
|
|
err := unix.Pipe(fds)
|
|
if err != nil {
|
|
return StopFD{ReadFD: -1, WriteFD: -1}, fmt.Errorf("failed to create pipe: %w", err)
|
|
}
|
|
|
|
if err := unix.SetNonblock(fds[0], true); err != nil {
|
|
unix.Close(fds[0])
|
|
unix.Close(fds[1])
|
|
return StopFD{ReadFD: -1, WriteFD: -1}, fmt.Errorf("failed to set read end non-blocking: %w", err)
|
|
}
|
|
|
|
if err := unix.SetNonblock(fds[1], true); err != nil {
|
|
unix.Close(fds[0])
|
|
unix.Close(fds[1])
|
|
return StopFD{ReadFD: -1, WriteFD: -1}, fmt.Errorf("failed to set write end non-blocking: %w", err)
|
|
}
|
|
|
|
return StopFD{ReadFD: fds[0], WriteFD: fds[1]}, nil
|
|
}
|
|
|
|
func (sf *StopFD) Stop() {
|
|
signal := []byte{1}
|
|
if n, err := unix.Write(sf.WriteFD, signal); n != len(signal) || err != nil {
|
|
panic(fmt.Sprintf("write(WriteFD) = (%d, %s), want (%d, nil)", n, err, len(signal)))
|
|
}
|
|
}
|
|
|
|
func (sf *StopFD) Close() error {
|
|
var err1, err2 error
|
|
if sf.ReadFD != -1 {
|
|
err1 = unix.Close(sf.ReadFD)
|
|
sf.ReadFD = -1
|
|
}
|
|
if sf.WriteFD != -1 {
|
|
err2 = unix.Close(sf.WriteFD)
|
|
sf.WriteFD = -1
|
|
}
|
|
if err1 != nil {
|
|
return err1
|
|
}
|
|
return err2
|
|
}
|
|
|
|
func (sf *StopFD) EFD() int {
|
|
return sf.ReadFD
|
|
}
|