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