gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }