-
Notifications
You must be signed in to change notification settings - Fork 10
/
kqueue.go
115 lines (105 loc) · 2.59 KB
/
kqueue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright (c) 2023 cheng-zhongliang. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package event
import (
"syscall"
"time"
"unsafe"
)
const (
initialNEvent = 0x20
maxNEvent = 0x1000
)
type poll struct {
fd int
changes []syscall.Kevent_t
events []syscall.Kevent_t
}
func openPoll() (*poll, error) {
kq := new(poll)
fd, err := syscall.Kqueue()
if err != nil {
return nil, err
}
kq.fd = fd
kq.changes = make([]syscall.Kevent_t, initialNEvent)
kq.events = make([]syscall.Kevent_t, initialNEvent)
return kq, nil
}
func (kq *poll) add(ev *Event) error {
if ev.events&EvRead != 0 {
kq.changes = append(kq.changes, syscall.Kevent_t{
Ident: uint64(ev.fd),
Filter: syscall.EVFILT_READ,
Flags: syscall.EV_ADD,
Udata: (*byte)(unsafe.Pointer(ev)),
})
}
if ev.events&EvWrite != 0 {
kq.changes = append(kq.changes, syscall.Kevent_t{
Ident: uint64(ev.fd),
Filter: syscall.EVFILT_WRITE,
Flags: syscall.EV_ADD,
Udata: (*byte)(unsafe.Pointer(ev)),
})
}
return nil
}
func (kq *poll) del(ev *Event) error {
if ev.events&EvRead != 0 {
kq.changes = append(kq.changes, syscall.Kevent_t{
Ident: uint64(ev.fd),
Filter: syscall.EVFILT_READ,
Flags: syscall.EV_DELETE,
})
}
if ev.events&EvWrite != 0 {
kq.changes = append(kq.changes, syscall.Kevent_t{
Ident: uint64(ev.fd),
Filter: syscall.EVFILT_WRITE,
Flags: syscall.EV_DELETE,
})
}
return nil
}
func (kq *poll) wait(cb func(ev *Event, res uint32), timeout time.Duration) error {
var timespec *syscall.Timespec
if timeout >= 0 {
ts := syscall.NsecToTimespec(timeout.Nanoseconds())
timespec = &ts
}
n, err := syscall.Kevent(kq.fd, kq.changes, kq.events, timespec)
if err != nil && !temporaryErr(err) {
return err
}
kq.changes = kq.changes[:0]
for i := 0; i < n; i++ {
flags := kq.events[i].Flags
if flags&syscall.EV_ERROR != 0 {
errno := syscall.Errno(kq.events[i].Data)
if errno&(syscall.EBADF|syscall.ENOENT|syscall.EINVAL) != 0 {
continue
}
return errno
}
which := uint32(0)
what := kq.events[i].Filter
ev := (*Event)(unsafe.Pointer(kq.events[i].Udata))
if what&syscall.EVFILT_READ != 0 {
which |= EvRead
} else if what&syscall.EVFILT_WRITE != 0 {
which |= EvWrite
}
cb(ev, ev.events&which)
}
if n == len(kq.events) && n < maxNEvent {
kq.events = make([]syscall.Kevent_t, n<<1)
}
return nil
}
func (kq *poll) close() error {
return syscall.Close(kq.fd)
}