diff options
Diffstat (limited to 'src/pkg/net/fd_openbsd.go')
| -rw-r--r-- | src/pkg/net/fd_openbsd.go | 116 | 
1 files changed, 116 insertions, 0 deletions
| diff --git a/src/pkg/net/fd_openbsd.go b/src/pkg/net/fd_openbsd.go new file mode 100644 index 000000000..e50883e94 --- /dev/null +++ b/src/pkg/net/fd_openbsd.go @@ -0,0 +1,116 @@ +// 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)) } | 
