256
|
1 |
// Copyright 2020 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 |
//go:build zos && s390x |
|
6 |
// +build zos,s390x |
|
7 |
|
|
8 |
package unix |
|
9 |
|
|
10 |
import ( |
|
11 |
"sync" |
|
12 |
) |
|
13 |
|
|
14 |
// This file simulates epoll on z/OS using poll. |
|
15 |
|
|
16 |
// Analogous to epoll_event on Linux. |
|
17 |
// TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove? |
|
18 |
type EpollEvent struct { |
|
19 |
Events uint32 |
|
20 |
Fd int32 |
|
21 |
Pad int32 |
|
22 |
} |
|
23 |
|
|
24 |
const ( |
|
25 |
EPOLLERR = 0x8 |
|
26 |
EPOLLHUP = 0x10 |
|
27 |
EPOLLIN = 0x1 |
|
28 |
EPOLLMSG = 0x400 |
|
29 |
EPOLLOUT = 0x4 |
|
30 |
EPOLLPRI = 0x2 |
|
31 |
EPOLLRDBAND = 0x80 |
|
32 |
EPOLLRDNORM = 0x40 |
|
33 |
EPOLLWRBAND = 0x200 |
|
34 |
EPOLLWRNORM = 0x100 |
|
35 |
EPOLL_CTL_ADD = 0x1 |
|
36 |
EPOLL_CTL_DEL = 0x2 |
|
37 |
EPOLL_CTL_MOD = 0x3 |
|
38 |
// The following constants are part of the epoll API, but represent |
|
39 |
// currently unsupported functionality on z/OS. |
|
40 |
// EPOLL_CLOEXEC = 0x80000 |
|
41 |
// EPOLLET = 0x80000000 |
|
42 |
// EPOLLONESHOT = 0x40000000 |
|
43 |
// EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis |
|
44 |
// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode |
|
45 |
// EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability |
|
46 |
) |
|
47 |
|
|
48 |
// TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL |
|
49 |
// constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16). |
|
50 |
|
|
51 |
// epToPollEvt converts epoll event field to poll equivalent. |
|
52 |
// In epoll, Events is a 32-bit field, while poll uses 16 bits. |
|
53 |
func epToPollEvt(events uint32) int16 { |
|
54 |
var ep2p = map[uint32]int16{ |
|
55 |
EPOLLIN: POLLIN, |
|
56 |
EPOLLOUT: POLLOUT, |
|
57 |
EPOLLHUP: POLLHUP, |
|
58 |
EPOLLPRI: POLLPRI, |
|
59 |
EPOLLERR: POLLERR, |
|
60 |
} |
|
61 |
|
|
62 |
var pollEvts int16 = 0 |
|
63 |
for epEvt, pEvt := range ep2p { |
|
64 |
if (events & epEvt) != 0 { |
|
65 |
pollEvts |= pEvt |
|
66 |
} |
|
67 |
} |
|
68 |
|
|
69 |
return pollEvts |
|
70 |
} |
|
71 |
|
|
72 |
// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields. |
|
73 |
func pToEpollEvt(revents int16) uint32 { |
|
74 |
var p2ep = map[int16]uint32{ |
|
75 |
POLLIN: EPOLLIN, |
|
76 |
POLLOUT: EPOLLOUT, |
|
77 |
POLLHUP: EPOLLHUP, |
|
78 |
POLLPRI: EPOLLPRI, |
|
79 |
POLLERR: EPOLLERR, |
|
80 |
} |
|
81 |
|
|
82 |
var epollEvts uint32 = 0 |
|
83 |
for pEvt, epEvt := range p2ep { |
|
84 |
if (revents & pEvt) != 0 { |
|
85 |
epollEvts |= epEvt |
|
86 |
} |
|
87 |
} |
|
88 |
|
|
89 |
return epollEvts |
|
90 |
} |
|
91 |
|
|
92 |
// Per-process epoll implementation. |
|
93 |
type epollImpl struct { |
|
94 |
mu sync.Mutex |
|
95 |
epfd2ep map[int]*eventPoll |
|
96 |
nextEpfd int |
|
97 |
} |
|
98 |
|
|
99 |
// eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances. |
|
100 |
// On Linux, this is an in-kernel data structure accessed through a fd. |
|
101 |
type eventPoll struct { |
|
102 |
mu sync.Mutex |
|
103 |
fds map[int]*EpollEvent |
|
104 |
} |
|
105 |
|
|
106 |
// epoll impl for this process. |
|
107 |
var impl epollImpl = epollImpl{ |
|
108 |
epfd2ep: make(map[int]*eventPoll), |
|
109 |
nextEpfd: 0, |
|
110 |
} |
|
111 |
|
|
112 |
func (e *epollImpl) epollcreate(size int) (epfd int, err error) { |
|
113 |
e.mu.Lock() |
|
114 |
defer e.mu.Unlock() |
|
115 |
epfd = e.nextEpfd |
|
116 |
e.nextEpfd++ |
|
117 |
|
|
118 |
e.epfd2ep[epfd] = &eventPoll{ |
|
119 |
fds: make(map[int]*EpollEvent), |
|
120 |
} |
|
121 |
return epfd, nil |
|
122 |
} |
|
123 |
|
|
124 |
func (e *epollImpl) epollcreate1(flag int) (fd int, err error) { |
|
125 |
return e.epollcreate(4) |
|
126 |
} |
|
127 |
|
|
128 |
func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) { |
|
129 |
e.mu.Lock() |
|
130 |
defer e.mu.Unlock() |
|
131 |
|
|
132 |
ep, ok := e.epfd2ep[epfd] |
|
133 |
if !ok { |
|
134 |
|
|
135 |
return EBADF |
|
136 |
} |
|
137 |
|
|
138 |
switch op { |
|
139 |
case EPOLL_CTL_ADD: |
|
140 |
// TODO(neeilan): When we make epfds and fds disjoint, detect epoll |
|
141 |
// loops here (instances watching each other) and return ELOOP. |
|
142 |
if _, ok := ep.fds[fd]; ok { |
|
143 |
return EEXIST |
|
144 |
} |
|
145 |
ep.fds[fd] = event |
|
146 |
case EPOLL_CTL_MOD: |
|
147 |
if _, ok := ep.fds[fd]; !ok { |
|
148 |
return ENOENT |
|
149 |
} |
|
150 |
ep.fds[fd] = event |
|
151 |
case EPOLL_CTL_DEL: |
|
152 |
if _, ok := ep.fds[fd]; !ok { |
|
153 |
return ENOENT |
|
154 |
} |
|
155 |
delete(ep.fds, fd) |
|
156 |
|
|
157 |
} |
|
158 |
return nil |
|
159 |
} |
|
160 |
|
|
161 |
// Must be called while holding ep.mu |
|
162 |
func (ep *eventPoll) getFds() []int { |
|
163 |
fds := make([]int, len(ep.fds)) |
|
164 |
for fd := range ep.fds { |
|
165 |
fds = append(fds, fd) |
|
166 |
} |
|
167 |
return fds |
|
168 |
} |
|
169 |
|
|
170 |
func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) { |
|
171 |
e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait |
|
172 |
ep, ok := e.epfd2ep[epfd] |
|
173 |
|
|
174 |
if !ok { |
|
175 |
e.mu.Unlock() |
|
176 |
return 0, EBADF |
|
177 |
} |
|
178 |
|
|
179 |
pollfds := make([]PollFd, 4) |
|
180 |
for fd, epollevt := range ep.fds { |
|
181 |
pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)}) |
|
182 |
} |
|
183 |
e.mu.Unlock() |
|
184 |
|
|
185 |
n, err = Poll(pollfds, msec) |
|
186 |
if err != nil { |
|
187 |
return n, err |
|
188 |
} |
|
189 |
|
|
190 |
i := 0 |
|
191 |
for _, pFd := range pollfds { |
|
192 |
if pFd.Revents != 0 { |
|
193 |
events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)} |
|
194 |
i++ |
|
195 |
} |
|
196 |
|
|
197 |
if i == n { |
|
198 |
break |
|
199 |
} |
|
200 |
} |
|
201 |
|
|
202 |
return n, nil |
|
203 |
} |
|
204 |
|
|
205 |
func EpollCreate(size int) (fd int, err error) { |
|
206 |
return impl.epollcreate(size) |
|
207 |
} |
|
208 |
|
|
209 |
func EpollCreate1(flag int) (fd int, err error) { |
|
210 |
return impl.epollcreate1(flag) |
|
211 |
} |
|
212 |
|
|
213 |
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { |
|
214 |
return impl.epollctl(epfd, op, fd, event) |
|
215 |
} |
|
216 |
|
|
217 |
// Because EpollWait mutates events, the caller is expected to coordinate |
|
218 |
// concurrent access if calling with the same epfd from multiple goroutines. |
|
219 |
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { |
|
220 |
return impl.epollwait(epfd, events, msec) |
|
221 |
} |