Devon H. O'Dell | 0489a26 | 2009-11-17 08:20:58 -0800 | [diff] [blame] | 1 | // 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 | |
| 7 | package net |
| 8 | |
| 9 | import ( |
| 10 | "os"; |
| 11 | "syscall"; |
| 12 | ) |
| 13 | |
| 14 | type pollster struct { |
| 15 | kq int; |
| 16 | eventbuf [10]syscall.Kevent_t; |
| 17 | events []syscall.Kevent_t; |
| 18 | } |
| 19 | |
| 20 | func 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 | |
| 30 | func (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 | |
| 60 | func (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 | |
| 74 | func (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 Cox | 9ac4449 | 2009-11-20 11:45:05 -0800 | [diff] [blame] | 96 | p.events = p.events[1:]; |
Devon H. O'Dell | 0489a26 | 2009-11-17 08:20:58 -0800 | [diff] [blame] | 97 | 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 | |
| 106 | func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) } |