blob: 34fd90f0a401a51d8784b0667662efbf1a1e1669 [file] [log] [blame]
Russ Cox6201a962008-09-26 14:11:26 -07001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Russ Coxe4a61c62008-09-29 13:37:00 -07005// Waiting for FDs via kqueue/kevent.
Russ Cox6201a962008-09-26 14:11:26 -07006
7package net
8
9import (
Russ Cox43c5e632008-09-26 14:46:28 -070010 "net";
Russ Cox6201a962008-09-26 14:11:26 -070011 "os";
12 "syscall";
Russ Cox6201a962008-09-26 14:11:26 -070013)
14
Russ Coxe4a61c62008-09-29 13:37:00 -070015export type Pollster struct {
16 kq int64;
Rob Pike1a91b9a2009-01-16 11:36:44 -080017 eventbuf [10]syscall.Kevent_t;
18 events []syscall.Kevent_t;
Russ Cox6201a962008-09-26 14:11:26 -070019}
20
Russ Coxe4a61c62008-09-29 13:37:00 -070021export func NewPollster() (p *Pollster, err *os.Error) {
Russ Cox55645042009-01-06 15:19:02 -080022 p = new(Pollster);
Russ Coxe4a61c62008-09-29 13:37:00 -070023 var e int64;
Rob Pike1a91b9a2009-01-16 11:36:44 -080024 if p.kq, e = syscall.Kqueue(); e != 0 {
Russ Cox6201a962008-09-26 14:11:26 -070025 return nil, os.ErrnoToError(e)
26 }
Russ Coxd47d8882008-12-18 22:37:22 -080027 p.events = p.eventbuf[0:0];
Russ Coxe4a61c62008-09-29 13:37:00 -070028 return p, nil
Russ Cox6201a962008-09-26 14:11:26 -070029}
30
Russ Coxe4a61c62008-09-29 13:37:00 -070031func (p *Pollster) AddFD(fd int64, mode int, repeat bool) *os.Error {
Russ Cox43c5e632008-09-26 14:46:28 -070032 var kmode int16;
33 if mode == 'r' {
34 kmode = syscall.EVFILT_READ
35 } else {
36 kmode = syscall.EVFILT_WRITE
37 }
Rob Pike1a91b9a2009-01-16 11:36:44 -080038 var events [1]syscall.Kevent_t;
Russ Cox43c5e632008-09-26 14:46:28 -070039 ev := &events[0];
Rob Pike1a91b9a2009-01-16 11:36:44 -080040 ev.Ident = fd;
41 ev.Filter = kmode;
Russ Cox43c5e632008-09-26 14:46:28 -070042
43 // EV_ADD - add event to kqueue list
Russ Coxe4a61c62008-09-29 13:37:00 -070044 // EV_RECEIPT - generate fake EV_ERROR as result of add,
45 // rather than waiting for real event
Russ Cox43c5e632008-09-26 14:46:28 -070046 // EV_ONESHOT - delete the event the first time it triggers
Rob Pike1a91b9a2009-01-16 11:36:44 -080047 ev.Flags = syscall.EV_ADD | syscall.EV_RECEIPT;
Russ Cox43c5e632008-09-26 14:46:28 -070048 if !repeat {
Rob Pike1a91b9a2009-01-16 11:36:44 -080049 ev.Flags |= syscall.EV_ONESHOT
Russ Cox43c5e632008-09-26 14:46:28 -070050 }
51
Rob Pike1a91b9a2009-01-16 11:36:44 -080052 n, e := syscall.Kevent(p.kq, events, events, nil);
Russ Cox43c5e632008-09-26 14:46:28 -070053 if e != 0 {
54 return os.ErrnoToError(e)
55 }
Rob Pike1a91b9a2009-01-16 11:36:44 -080056 if n != 1 || (ev.Flags & syscall.EV_ERROR) == 0 || ev.Ident != fd || ev.Filter != kmode {
Russ Cox43c5e632008-09-26 14:46:28 -070057 return os.NewError("kqueue phase error")
58 }
Rob Pike1a91b9a2009-01-16 11:36:44 -080059 if ev.Data != 0 {
60 return os.ErrnoToError(ev.Data)
Russ Cox43c5e632008-09-26 14:46:28 -070061 }
62 return nil
63}
64
Russ Coxe4a61c62008-09-29 13:37:00 -070065func (p *Pollster) WaitFD() (fd int64, mode int, err *os.Error) {
66 for len(p.events) == 0 {
Rob Pike1a91b9a2009-01-16 11:36:44 -080067 nn, e := syscall.Kevent(p.kq, nil, p.eventbuf, nil);
Russ Coxe4a61c62008-09-29 13:37:00 -070068 if e != 0 {
69 if e == syscall.EAGAIN || e == syscall.EINTR {
70 continue
71 }
72 return -1, 0, os.ErrnoToError(e)
73 }
Russ Coxd47d8882008-12-18 22:37:22 -080074 p.events = p.eventbuf[0:nn]
Russ Cox43c5e632008-09-26 14:46:28 -070075 }
Russ Coxe4a61c62008-09-29 13:37:00 -070076 ev := &p.events[0];
77 p.events = p.events[1:len(p.events)];
Rob Pike1a91b9a2009-01-16 11:36:44 -080078 fd = ev.Ident;
79 if ev.Filter == syscall.EVFILT_READ {
Russ Cox43c5e632008-09-26 14:46:28 -070080 mode = 'r'
81 } else {
Russ Cox43c5e632008-09-26 14:46:28 -070082 mode = 'w'
83 }
Russ Coxe4a61c62008-09-29 13:37:00 -070084 return fd, mode, nil
Russ Cox43c5e632008-09-26 14:46:28 -070085}
86
Russ Coxe4a61c62008-09-29 13:37:00 -070087func (p *Pollster) Close() *os.Error {
Rob Pike1a91b9a2009-01-16 11:36:44 -080088 r, e := syscall.Close(p.kq);
Russ Coxe4a61c62008-09-29 13:37:00 -070089 return os.ErrnoToError(e)
Russ Cox43c5e632008-09-26 14:46:28 -070090}