epoll_zos.go (5158B)
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 }