github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/sys/unix/epoll_zos.go (about) 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 7 package unix 8 9 import ( 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? 17 type EpollEvent struct { 18 Events uint32 19 Fd int32 20 Pad int32 21 } 22 23 const ( 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. 52 func 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. 72 func 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. 92 type 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. 100 type eventPoll struct { 101 mu sync.Mutex 102 fds map[int]*EpollEvent 103 } 104 105 // epoll impl for this process. 106 var impl epollImpl = epollImpl{ 107 epfd2ep: make(map[int]*eventPoll), 108 nextEpfd: 0, 109 } 110 111 func (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 123 func (e *epollImpl) epollcreate1(flag int) (fd int, err error) { 124 return e.epollcreate(4) 125 } 126 127 func (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 161 func (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 169 func (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 204 func EpollCreate(size int) (fd int, err error) { 205 return impl.epollcreate(size) 206 } 207 208 func EpollCreate1(flag int) (fd int, err error) { 209 return impl.epollcreate1(flag) 210 } 211 212 func 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. 218 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { 219 return impl.epollwait(epfd, events, msec) 220 }