github.com/nibnait/go-learn@v0.0.0-20220227013611-dfa47ea6d2da/src/pkg/mod/golang.org/x/sys@v0.0.0-20210630005230-0f9fa26af87c/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  // +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  }