So, I'm trying to read from stdin without busy waiting, ignoring EOF as clients in my case will come and go. In C I'd use a simple select() or poll() but I'm trying to learn Go, and I'm quite frustrated by the lack of select() or poll(). I can't find a good way using select and channels in Go because a Read() will return immediately on an EOF and I'm back to busy waiting. syscall.Select() seems the best way, but Go has not bothered to implement FD_SET! sigh
So, I'm trying with cgo.
package main
/*
#include <stdlib.h>
#include <sys/select.h>
void _FD_SET(int sysfd, void *set) {
FD_SET(sysfd, (fd_set*)set);
}
*/
import "C"
import (
"unsafe"
But when I try to build this on my Mac I get this.
# github.com/msoulier/mlogd
could not determine kind of name for C._FD_SET
clang errors for preamble:
src/github.com/msoulier/mlogd/mlogd.go:6:14: error: expected identifier or '('
void _FD_SET(int sysfd, void *set) {
^
src/github.com/msoulier/mlogd/mlogd.go:6:14: error: expected ')'
src/github.com/msoulier/mlogd/mlogd.go:6:13: note: to match this '('
void _FD_SET(int sysfd, void *set) {
^
2 errors generated.
If I merge the imports together then most of the errors go away.
package main
/*
#include <stdlib.h>
#include <sys/select.h>
void _FD_SET(int sysfd, void *set) {
FD_SET(sysfd, (fd_set*)set);
}
*/
import (
"C"
"unsafe"
"syscall"
But there's still one.
# github.com/msoulier/mlogd
could not determine kind of name for C._FD_SET
So, I'm looking for two things here.
- Why am I doing wrong with cgo here? From what I've read this should "just work".
- Is there a better way to read indefinitely from stdin, without busy waiting, and ignoring EOF?
My environment.
msoulier@merlin:~/work/go$ go version
go version go1.6.2 darwin/amd64
msoulier@merlin:~/work/go$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/msoulier/work/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.6.2/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.6.2/libexec/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"
Thanks in advance. Must be simpler than this.
I got this far with select.
// loop forever - we expect to be killed with a SIGTERM or SIGINT
for {
logger.Debug("going into select on stdin")
var r_fdset syscall.FdSet
for i := 0; i < 16; i++ {
r_fdset.Bits[i] = 0
}
r_fdset.Bits[0] = 1
selerr := syscall.Select(1, &r_fdset, nil, nil, nil)
if selerr != nil {
logger.Warning(selerr)
}
But it's returning immediately even when the input runs out.
Mike