cubefs
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
8package unix9
10import (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?
18type EpollEvent struct {19Events uint3220Fd int3221Pad int3222}
23
24const (25EPOLLERR = 0x826EPOLLHUP = 0x1027EPOLLIN = 0x128EPOLLMSG = 0x40029EPOLLOUT = 0x430EPOLLPRI = 0x231EPOLLRDBAND = 0x8032EPOLLRDNORM = 0x4033EPOLLWRBAND = 0x20034EPOLLWRNORM = 0x10035EPOLL_CTL_ADD = 0x136EPOLL_CTL_DEL = 0x237EPOLL_CTL_MOD = 0x338// The following constants are part of the epoll API, but represent39// currently unsupported functionality on z/OS.40// EPOLL_CLOEXEC = 0x8000041// EPOLLET = 0x8000000042// EPOLLONESHOT = 0x4000000043// EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis44// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode45// EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability46)
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.
53func epToPollEvt(events uint32) int16 {54var ep2p = map[uint32]int16{55EPOLLIN: POLLIN,56EPOLLOUT: POLLOUT,57EPOLLHUP: POLLHUP,58EPOLLPRI: POLLPRI,59EPOLLERR: POLLERR,60}61
62var pollEvts int16 = 063for epEvt, pEvt := range ep2p {64if (events & epEvt) != 0 {65pollEvts |= pEvt66}67}68
69return pollEvts70}
71
72// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
73func pToEpollEvt(revents int16) uint32 {74var p2ep = map[int16]uint32{75POLLIN: EPOLLIN,76POLLOUT: EPOLLOUT,77POLLHUP: EPOLLHUP,78POLLPRI: EPOLLPRI,79POLLERR: EPOLLERR,80}81
82var epollEvts uint32 = 083for pEvt, epEvt := range p2ep {84if (revents & pEvt) != 0 {85epollEvts |= epEvt86}87}88
89return epollEvts90}
91
92// Per-process epoll implementation.
93type epollImpl struct {94mu sync.Mutex95epfd2ep map[int]*eventPoll96nextEpfd int97}
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.
101type eventPoll struct {102mu sync.Mutex103fds map[int]*EpollEvent104}
105
106// epoll impl for this process.
107var impl epollImpl = epollImpl{108epfd2ep: make(map[int]*eventPoll),109nextEpfd: 0,110}
111
112func (e *epollImpl) epollcreate(size int) (epfd int, err error) {113e.mu.Lock()114defer e.mu.Unlock()115epfd = e.nextEpfd116e.nextEpfd++117
118e.epfd2ep[epfd] = &eventPoll{119fds: make(map[int]*EpollEvent),120}121return epfd, nil122}
123
124func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {125return e.epollcreate(4)126}
127
128func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {129e.mu.Lock()130defer e.mu.Unlock()131
132ep, ok := e.epfd2ep[epfd]133if !ok {134
135return EBADF136}137
138switch op {139case EPOLL_CTL_ADD:140// TODO(neeilan): When we make epfds and fds disjoint, detect epoll141// loops here (instances watching each other) and return ELOOP.142if _, ok := ep.fds[fd]; ok {143return EEXIST144}145ep.fds[fd] = event146case EPOLL_CTL_MOD:147if _, ok := ep.fds[fd]; !ok {148return ENOENT149}150ep.fds[fd] = event151case EPOLL_CTL_DEL:152if _, ok := ep.fds[fd]; !ok {153return ENOENT154}155delete(ep.fds, fd)156
157}158return nil159}
160
161// Must be called while holding ep.mu
162func (ep *eventPoll) getFds() []int {163fds := make([]int, len(ep.fds))164for fd := range ep.fds {165fds = append(fds, fd)166}167return fds168}
169
170func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {171e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait172ep, ok := e.epfd2ep[epfd]173
174if !ok {175e.mu.Unlock()176return 0, EBADF177}178
179pollfds := make([]PollFd, 4)180for fd, epollevt := range ep.fds {181pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})182}183e.mu.Unlock()184
185n, err = Poll(pollfds, msec)186if err != nil {187return n, err188}189
190i := 0191for _, pFd := range pollfds {192if pFd.Revents != 0 {193events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}194i++195}196
197if i == n {198break199}200}201
202return n, nil203}
204
205func EpollCreate(size int) (fd int, err error) {206return impl.epollcreate(size)207}
208
209func EpollCreate1(flag int) (fd int, err error) {210return impl.epollcreate1(flag)211}
212
213func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {214return 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.
219func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {220return impl.epollwait(epfd, events, msec)221}
222