blob: 12a64014a816ff653c8442eeb78cc2058812fc86 [file] [log] [blame]
Devon H. O'Dell0489a262009-11-17 08:20:58 -08001// 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
5// Waiting for FDs via kqueue/kevent.
6
7package net
8
9import (
10 "os";
11 "syscall";
12)
13
14type pollster struct {
15 kq int;
16 eventbuf [10]syscall.Kevent_t;
17 events []syscall.Kevent_t;
18}
19
20func newpollster() (p *pollster, err os.Error) {
21 p = new(pollster);
22 var e int;
23 if p.kq, e = syscall.Kqueue(); e != 0 {
24 return nil, os.NewSyscallError("kqueue", e)
25 }
26 p.events = p.eventbuf[0:0];
27 return p, nil;
28}
29
30func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
31 var kmode int;
32 if mode == 'r' {
33 kmode = syscall.EVFILT_READ
34 } else {
35 kmode = syscall.EVFILT_WRITE
36 }
37 var events [1]syscall.Kevent_t;
38 ev := &events[0];
39 // EV_ADD - add event to kqueue list
40 // EV_ONESHOT - delete the event the first time it triggers
41 flags := syscall.EV_ADD;
42 if !repeat {
43 flags |= syscall.EV_ONESHOT
44 }
45 syscall.SetKevent(ev, fd, kmode, flags);
46
47 n, e := syscall.Kevent(p.kq, &events, nil, nil);
48 if e != 0 {
49 return os.NewSyscallError("kevent", e)
50 }
51 if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
52 return os.NewSyscallError("kqueue phase error", e)
53 }
54 if ev.Data != 0 {
55 return os.Errno(int(ev.Data))
56 }
57 return nil;
58}
59
60func (p *pollster) DelFD(fd int, mode int) {
61 var kmode int;
62 if mode == 'r' {
63 kmode = syscall.EVFILT_READ
64 } else {
65 kmode = syscall.EVFILT_WRITE
66 }
67 var events [1]syscall.Kevent_t;
68 ev := &events[0];
69 // EV_DELETE - delete event from kqueue list
70 syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE);
71 syscall.Kevent(p.kq, &events, nil, nil);
72}
73
74func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
75 var t *syscall.Timespec;
76 for len(p.events) == 0 {
77 if nsec > 0 {
78 if t == nil {
79 t = new(syscall.Timespec)
80 }
81 *t = syscall.NsecToTimespec(nsec);
82 }
83 nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t);
84 if e != 0 {
85 if e == syscall.EINTR {
86 continue
87 }
88 return -1, 0, os.NewSyscallError("kevent", e);
89 }
90 if nn == 0 {
91 return -1, 0, nil
92 }
93 p.events = p.eventbuf[0:nn];
94 }
95 ev := &p.events[0];
Russ Cox9ac44492009-11-20 11:45:05 -080096 p.events = p.events[1:];
Devon H. O'Dell0489a262009-11-17 08:20:58 -080097 fd = int(ev.Ident);
98 if ev.Filter == syscall.EVFILT_READ {
99 mode = 'r'
100 } else {
101 mode = 'w'
102 }
103 return fd, mode, nil;
104}
105
106func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }