Imported Upstream version 4.7.2
[platform/upstream/gcc48.git] / libgo / go / net / fd_openbsd.go
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         // An event buffer for AddFD/DelFD.
20         // Must hold pollServer lock.
21         kbuf [1]syscall.Kevent_t
22 }
23
24 func newpollster() (p *pollster, err error) {
25         p = new(pollster)
26         if p.kq, err = syscall.Kqueue(); err != nil {
27                 return nil, os.NewSyscallError("kqueue", err)
28         }
29         syscall.CloseOnExec(p.kq)
30         p.events = p.eventbuf[0:0]
31         return p, nil
32 }
33
34 func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
35         // pollServer is locked.
36
37         var kmode int
38         if mode == 'r' {
39                 kmode = syscall.EVFILT_READ
40         } else {
41                 kmode = syscall.EVFILT_WRITE
42         }
43         ev := &p.kbuf[0]
44         // EV_ADD - add event to kqueue list
45         // EV_ONESHOT - delete the event the first time it triggers
46         flags := syscall.EV_ADD
47         if !repeat {
48                 flags |= syscall.EV_ONESHOT
49         }
50         syscall.SetKevent(ev, fd, kmode, flags)
51
52         n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
53         if err != nil {
54                 return false, os.NewSyscallError("kevent", err)
55         }
56         if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
57                 return false, os.NewSyscallError("kqueue phase error", err)
58         }
59         if ev.Data != 0 {
60                 return false, syscall.Errno(int(ev.Data))
61         }
62         return false, nil
63 }
64
65 func (p *pollster) DelFD(fd int, mode int) {
66         // pollServer is locked.
67
68         var kmode int
69         if mode == 'r' {
70                 kmode = syscall.EVFILT_READ
71         } else {
72                 kmode = syscall.EVFILT_WRITE
73         }
74         ev := &p.kbuf[0]
75         // EV_DELETE - delete event from kqueue list
76         syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
77         syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
78 }
79
80 func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
81         var t *syscall.Timespec
82         for len(p.events) == 0 {
83                 if nsec > 0 {
84                         if t == nil {
85                                 t = new(syscall.Timespec)
86                         }
87                         *t = syscall.NsecToTimespec(nsec)
88                 }
89
90                 s.Unlock()
91                 n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
92                 s.Lock()
93
94                 if err != nil {
95                         if err == syscall.EINTR {
96                                 continue
97                         }
98                         return -1, 0, os.NewSyscallError("kevent", err)
99                 }
100                 if n == 0 {
101                         return -1, 0, nil
102                 }
103                 p.events = p.eventbuf[:n]
104         }
105         ev := &p.events[0]
106         p.events = p.events[1:]
107         fd = int(ev.Ident)
108         if ev.Filter == syscall.EVFILT_READ {
109                 mode = 'r'
110         } else {
111                 mode = 'w'
112         }
113         return fd, mode, nil
114 }
115
116 func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }