1
0
mirror of https://github.com/golang/go synced 2024-11-20 10:54:49 -07:00
go/src/pkg/net/fd_freebsd.go
Ian Lance Taylor 0caa0c0923 net: let OS-specific AddFD routine wake up polling thread.
With gccgo some operating systems require using select rather
than epoll or kevent.  Using select means that we have to wake
up the polling thread each time we add a new file descriptor.
This implements that in the generic code rather than adding
another wakeup channel, even though nothing in the current net
package uses the capability.

R=rsc, iant2
CC=golang-dev
https://golang.org/cl/4284069
2011-03-28 12:39:09 -07:00

117 lines
2.5 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Waiting for FDs via kqueue/kevent.
package net
import (
"os"
"syscall"
)
type pollster struct {
kq int
eventbuf [10]syscall.Kevent_t
events []syscall.Kevent_t
// An event buffer for AddFD/DelFD.
// Must hold pollServer lock.
kbuf [1]syscall.Kevent_t
}
func newpollster() (p *pollster, err os.Error) {
p = new(pollster)
var e int
if p.kq, e = syscall.Kqueue(); e != 0 {
return nil, os.NewSyscallError("kqueue", e)
}
p.events = p.eventbuf[0:0]
return p, nil
}
func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
// pollServer is locked.
var kmode int
if mode == 'r' {
kmode = syscall.EVFILT_READ
} else {
kmode = syscall.EVFILT_WRITE
}
ev := &p.kbuf[0]
// EV_ADD - add event to kqueue list
// EV_ONESHOT - delete the event the first time it triggers
flags := syscall.EV_ADD
if !repeat {
flags |= syscall.EV_ONESHOT
}
syscall.SetKevent(ev, fd, kmode, flags)
n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
if e != 0 {
return false, os.NewSyscallError("kevent", e)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
return false, os.NewSyscallError("kqueue phase error", e)
}
if ev.Data != 0 {
return false, os.Errno(int(ev.Data))
}
return false, nil
}
func (p *pollster) DelFD(fd int, mode int) {
// pollServer is locked.
var kmode int
if mode == 'r' {
kmode = syscall.EVFILT_READ
} else {
kmode = syscall.EVFILT_WRITE
}
ev := &p.kbuf[0]
// EV_DELETE - delete event from kqueue list
syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
}
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
var t *syscall.Timespec
for len(p.events) == 0 {
if nsec > 0 {
if t == nil {
t = new(syscall.Timespec)
}
*t = syscall.NsecToTimespec(nsec)
}
s.Unlock()
nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
s.Lock()
if e != 0 {
if e == syscall.EINTR {
continue
}
return -1, 0, os.NewSyscallError("kevent", e)
}
if nn == 0 {
return -1, 0, nil
}
p.events = p.eventbuf[0:nn]
}
ev := &p.events[0]
p.events = p.events[1:]
fd = int(ev.Ident)
if ev.Filter == syscall.EVFILT_READ {
mode = 'r'
} else {
mode = 'w'
}
return fd, mode, nil
}
func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }