Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [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 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 5 | // Waiting for FDs via kqueue/kevent. |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 6 | |
| 7 | package net |
| 8 | |
| 9 | import ( |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 10 | "net"; |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 11 | "os"; |
| 12 | "syscall"; |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 13 | ) |
| 14 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 15 | export type Pollster struct { |
| 16 | kq int64; |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 17 | eventbuf [10]syscall.Kevent_t; |
| 18 | events []syscall.Kevent_t; |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 19 | } |
| 20 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 21 | export func NewPollster() (p *Pollster, err *os.Error) { |
Russ Cox | 5564504 | 2009-01-06 15:19:02 -0800 | [diff] [blame] | 22 | p = new(Pollster); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 23 | var e int64; |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 24 | if p.kq, e = syscall.Kqueue(); e != 0 { |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 25 | return nil, os.ErrnoToError(e) |
| 26 | } |
Russ Cox | d47d888 | 2008-12-18 22:37:22 -0800 | [diff] [blame] | 27 | p.events = p.eventbuf[0:0]; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 28 | return p, nil |
Russ Cox | 6201a96 | 2008-09-26 14:11:26 -0700 | [diff] [blame] | 29 | } |
| 30 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 31 | func (p *Pollster) AddFD(fd int64, mode int, repeat bool) *os.Error { |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 32 | var kmode int16; |
| 33 | if mode == 'r' { |
| 34 | kmode = syscall.EVFILT_READ |
| 35 | } else { |
| 36 | kmode = syscall.EVFILT_WRITE |
| 37 | } |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 38 | var events [1]syscall.Kevent_t; |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 39 | ev := &events[0]; |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 40 | ev.Ident = fd; |
| 41 | ev.Filter = kmode; |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 42 | |
| 43 | // EV_ADD - add event to kqueue list |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 44 | // EV_RECEIPT - generate fake EV_ERROR as result of add, |
| 45 | // rather than waiting for real event |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 46 | // EV_ONESHOT - delete the event the first time it triggers |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 47 | ev.Flags = syscall.EV_ADD | syscall.EV_RECEIPT; |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 48 | if !repeat { |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 49 | ev.Flags |= syscall.EV_ONESHOT |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 50 | } |
| 51 | |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 52 | n, e := syscall.Kevent(p.kq, events, events, nil); |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 53 | if e != 0 { |
| 54 | return os.ErrnoToError(e) |
| 55 | } |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 56 | if n != 1 || (ev.Flags & syscall.EV_ERROR) == 0 || ev.Ident != fd || ev.Filter != kmode { |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 57 | return os.NewError("kqueue phase error") |
| 58 | } |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 59 | if ev.Data != 0 { |
| 60 | return os.ErrnoToError(ev.Data) |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 61 | } |
| 62 | return nil |
| 63 | } |
| 64 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 65 | func (p *Pollster) WaitFD() (fd int64, mode int, err *os.Error) { |
| 66 | for len(p.events) == 0 { |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 67 | nn, e := syscall.Kevent(p.kq, nil, p.eventbuf, nil); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 68 | if e != 0 { |
| 69 | if e == syscall.EAGAIN || e == syscall.EINTR { |
| 70 | continue |
| 71 | } |
| 72 | return -1, 0, os.ErrnoToError(e) |
| 73 | } |
Russ Cox | d47d888 | 2008-12-18 22:37:22 -0800 | [diff] [blame] | 74 | p.events = p.eventbuf[0:nn] |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 75 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 76 | ev := &p.events[0]; |
| 77 | p.events = p.events[1:len(p.events)]; |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 78 | fd = ev.Ident; |
| 79 | if ev.Filter == syscall.EVFILT_READ { |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 80 | mode = 'r' |
| 81 | } else { |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 82 | mode = 'w' |
| 83 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 84 | return fd, mode, nil |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 85 | } |
| 86 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 87 | func (p *Pollster) Close() *os.Error { |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame^] | 88 | r, e := syscall.Close(p.kq); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 89 | return os.ErrnoToError(e) |
Russ Cox | 43c5e63 | 2008-09-26 14:46:28 -0700 | [diff] [blame] | 90 | } |