66
|
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 }
|