123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // Copyright 2020 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- //go:build zos && s390x
- package unix
- import (
- "sync"
- )
- // This file simulates epoll on z/OS using poll.
- // Analogous to epoll_event on Linux.
- // TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove?
- type EpollEvent struct {
- Events uint32
- Fd int32
- Pad int32
- }
- const (
- EPOLLERR = 0x8
- EPOLLHUP = 0x10
- EPOLLIN = 0x1
- EPOLLMSG = 0x400
- EPOLLOUT = 0x4
- EPOLLPRI = 0x2
- EPOLLRDBAND = 0x80
- EPOLLRDNORM = 0x40
- EPOLLWRBAND = 0x200
- EPOLLWRNORM = 0x100
- EPOLL_CTL_ADD = 0x1
- EPOLL_CTL_DEL = 0x2
- EPOLL_CTL_MOD = 0x3
- // The following constants are part of the epoll API, but represent
- // currently unsupported functionality on z/OS.
- // EPOLL_CLOEXEC = 0x80000
- // EPOLLET = 0x80000000
- // EPOLLONESHOT = 0x40000000
- // EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis
- // EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode
- // EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability
- )
- // TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL
- // constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16).
- // epToPollEvt converts epoll event field to poll equivalent.
- // In epoll, Events is a 32-bit field, while poll uses 16 bits.
- func epToPollEvt(events uint32) int16 {
- var ep2p = map[uint32]int16{
- EPOLLIN: POLLIN,
- EPOLLOUT: POLLOUT,
- EPOLLHUP: POLLHUP,
- EPOLLPRI: POLLPRI,
- EPOLLERR: POLLERR,
- }
- var pollEvts int16 = 0
- for epEvt, pEvt := range ep2p {
- if (events & epEvt) != 0 {
- pollEvts |= pEvt
- }
- }
- return pollEvts
- }
- // pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
- func pToEpollEvt(revents int16) uint32 {
- var p2ep = map[int16]uint32{
- POLLIN: EPOLLIN,
- POLLOUT: EPOLLOUT,
- POLLHUP: EPOLLHUP,
- POLLPRI: EPOLLPRI,
- POLLERR: EPOLLERR,
- }
- var epollEvts uint32 = 0
- for pEvt, epEvt := range p2ep {
- if (revents & pEvt) != 0 {
- epollEvts |= epEvt
- }
- }
- return epollEvts
- }
- // Per-process epoll implementation.
- type epollImpl struct {
- mu sync.Mutex
- epfd2ep map[int]*eventPoll
- nextEpfd int
- }
- // eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances.
- // On Linux, this is an in-kernel data structure accessed through a fd.
- type eventPoll struct {
- mu sync.Mutex
- fds map[int]*EpollEvent
- }
- // epoll impl for this process.
- var impl epollImpl = epollImpl{
- epfd2ep: make(map[int]*eventPoll),
- nextEpfd: 0,
- }
- func (e *epollImpl) epollcreate(size int) (epfd int, err error) {
- e.mu.Lock()
- defer e.mu.Unlock()
- epfd = e.nextEpfd
- e.nextEpfd++
- e.epfd2ep[epfd] = &eventPoll{
- fds: make(map[int]*EpollEvent),
- }
- return epfd, nil
- }
- func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {
- return e.epollcreate(4)
- }
- func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {
- e.mu.Lock()
- defer e.mu.Unlock()
- ep, ok := e.epfd2ep[epfd]
- if !ok {
- return EBADF
- }
- switch op {
- case EPOLL_CTL_ADD:
- // TODO(neeilan): When we make epfds and fds disjoint, detect epoll
- // loops here (instances watching each other) and return ELOOP.
- if _, ok := ep.fds[fd]; ok {
- return EEXIST
- }
- ep.fds[fd] = event
- case EPOLL_CTL_MOD:
- if _, ok := ep.fds[fd]; !ok {
- return ENOENT
- }
- ep.fds[fd] = event
- case EPOLL_CTL_DEL:
- if _, ok := ep.fds[fd]; !ok {
- return ENOENT
- }
- delete(ep.fds, fd)
- }
- return nil
- }
- // Must be called while holding ep.mu
- func (ep *eventPoll) getFds() []int {
- fds := make([]int, len(ep.fds))
- for fd := range ep.fds {
- fds = append(fds, fd)
- }
- return fds
- }
- func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait
- ep, ok := e.epfd2ep[epfd]
- if !ok {
- e.mu.Unlock()
- return 0, EBADF
- }
- pollfds := make([]PollFd, 4)
- for fd, epollevt := range ep.fds {
- pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})
- }
- e.mu.Unlock()
- n, err = Poll(pollfds, msec)
- if err != nil {
- return n, err
- }
- i := 0
- for _, pFd := range pollfds {
- if pFd.Revents != 0 {
- events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}
- i++
- }
- if i == n {
- break
- }
- }
- return n, nil
- }
- func EpollCreate(size int) (fd int, err error) {
- return impl.epollcreate(size)
- }
- func EpollCreate1(flag int) (fd int, err error) {
- return impl.epollcreate1(flag)
- }
- func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
- return impl.epollctl(epfd, op, fd, event)
- }
- // Because EpollWait mutates events, the caller is expected to coordinate
- // concurrent access if calling with the same epfd from multiple goroutines.
- func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- return impl.epollwait(epfd, events, msec)
- }
|