...

Source file src/cmd/vendor/golang.org/x/sys/unix/epoll_zos.go

Documentation: cmd/vendor/golang.org/x/sys/unix

     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  
     7  package unix
     8  
     9  import (
    10  	"sync"
    11  )
    12  
    13  // This file simulates epoll on z/OS using poll.
    14  
    15  // Analogous to epoll_event on Linux.
    16  // TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove?
    17  type EpollEvent struct {
    18  	Events uint32
    19  	Fd     int32
    20  	Pad    int32
    21  }
    22  
    23  const (
    24  	EPOLLERR      = 0x8
    25  	EPOLLHUP      = 0x10
    26  	EPOLLIN       = 0x1
    27  	EPOLLMSG      = 0x400
    28  	EPOLLOUT      = 0x4
    29  	EPOLLPRI      = 0x2
    30  	EPOLLRDBAND   = 0x80
    31  	EPOLLRDNORM   = 0x40
    32  	EPOLLWRBAND   = 0x200
    33  	EPOLLWRNORM   = 0x100
    34  	EPOLL_CTL_ADD = 0x1
    35  	EPOLL_CTL_DEL = 0x2
    36  	EPOLL_CTL_MOD = 0x3
    37  	// The following constants are part of the epoll API, but represent
    38  	// currently unsupported functionality on z/OS.
    39  	// EPOLL_CLOEXEC  = 0x80000
    40  	// EPOLLET        = 0x80000000
    41  	// EPOLLONESHOT   = 0x40000000
    42  	// EPOLLRDHUP     = 0x2000     // Typically used with edge-triggered notis
    43  	// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode
    44  	// EPOLLWAKEUP    = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability
    45  )
    46  
    47  // TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL
    48  // constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16).
    49  
    50  // epToPollEvt converts epoll event field to poll equivalent.
    51  // In epoll, Events is a 32-bit field, while poll uses 16 bits.
    52  func epToPollEvt(events uint32) int16 {
    53  	var ep2p = map[uint32]int16{
    54  		EPOLLIN:  POLLIN,
    55  		EPOLLOUT: POLLOUT,
    56  		EPOLLHUP: POLLHUP,
    57  		EPOLLPRI: POLLPRI,
    58  		EPOLLERR: POLLERR,
    59  	}
    60  
    61  	var pollEvts int16 = 0
    62  	for epEvt, pEvt := range ep2p {
    63  		if (events & epEvt) != 0 {
    64  			pollEvts |= pEvt
    65  		}
    66  	}
    67  
    68  	return pollEvts
    69  }
    70  
    71  // pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
    72  func pToEpollEvt(revents int16) uint32 {
    73  	var p2ep = map[int16]uint32{
    74  		POLLIN:  EPOLLIN,
    75  		POLLOUT: EPOLLOUT,
    76  		POLLHUP: EPOLLHUP,
    77  		POLLPRI: EPOLLPRI,
    78  		POLLERR: EPOLLERR,
    79  	}
    80  
    81  	var epollEvts uint32 = 0
    82  	for pEvt, epEvt := range p2ep {
    83  		if (revents & pEvt) != 0 {
    84  			epollEvts |= epEvt
    85  		}
    86  	}
    87  
    88  	return epollEvts
    89  }
    90  
    91  // Per-process epoll implementation.
    92  type epollImpl struct {
    93  	mu       sync.Mutex
    94  	epfd2ep  map[int]*eventPoll
    95  	nextEpfd int
    96  }
    97  
    98  // eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances.
    99  // On Linux, this is an in-kernel data structure accessed through a fd.
   100  type eventPoll struct {
   101  	mu  sync.Mutex
   102  	fds map[int]*EpollEvent
   103  }
   104  
   105  // epoll impl for this process.
   106  var impl epollImpl = epollImpl{
   107  	epfd2ep:  make(map[int]*eventPoll),
   108  	nextEpfd: 0,
   109  }
   110  
   111  func (e *epollImpl) epollcreate(size int) (epfd int, err error) {
   112  	e.mu.Lock()
   113  	defer e.mu.Unlock()
   114  	epfd = e.nextEpfd
   115  	e.nextEpfd++
   116  
   117  	e.epfd2ep[epfd] = &eventPoll{
   118  		fds: make(map[int]*EpollEvent),
   119  	}
   120  	return epfd, nil
   121  }
   122  
   123  func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {
   124  	return e.epollcreate(4)
   125  }
   126  
   127  func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {
   128  	e.mu.Lock()
   129  	defer e.mu.Unlock()
   130  
   131  	ep, ok := e.epfd2ep[epfd]
   132  	if !ok {
   133  
   134  		return EBADF
   135  	}
   136  
   137  	switch op {
   138  	case EPOLL_CTL_ADD:
   139  		// TODO(neeilan): When we make epfds and fds disjoint, detect epoll
   140  		// loops here (instances watching each other) and return ELOOP.
   141  		if _, ok := ep.fds[fd]; ok {
   142  			return EEXIST
   143  		}
   144  		ep.fds[fd] = event
   145  	case EPOLL_CTL_MOD:
   146  		if _, ok := ep.fds[fd]; !ok {
   147  			return ENOENT
   148  		}
   149  		ep.fds[fd] = event
   150  	case EPOLL_CTL_DEL:
   151  		if _, ok := ep.fds[fd]; !ok {
   152  			return ENOENT
   153  		}
   154  		delete(ep.fds, fd)
   155  
   156  	}
   157  	return nil
   158  }
   159  
   160  // Must be called while holding ep.mu
   161  func (ep *eventPoll) getFds() []int {
   162  	fds := make([]int, len(ep.fds))
   163  	for fd := range ep.fds {
   164  		fds = append(fds, fd)
   165  	}
   166  	return fds
   167  }
   168  
   169  func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {
   170  	e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait
   171  	ep, ok := e.epfd2ep[epfd]
   172  
   173  	if !ok {
   174  		e.mu.Unlock()
   175  		return 0, EBADF
   176  	}
   177  
   178  	pollfds := make([]PollFd, 4)
   179  	for fd, epollevt := range ep.fds {
   180  		pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})
   181  	}
   182  	e.mu.Unlock()
   183  
   184  	n, err = Poll(pollfds, msec)
   185  	if err != nil {
   186  		return n, err
   187  	}
   188  
   189  	i := 0
   190  	for _, pFd := range pollfds {
   191  		if pFd.Revents != 0 {
   192  			events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}
   193  			i++
   194  		}
   195  
   196  		if i == n {
   197  			break
   198  		}
   199  	}
   200  
   201  	return n, nil
   202  }
   203  
   204  func EpollCreate(size int) (fd int, err error) {
   205  	return impl.epollcreate(size)
   206  }
   207  
   208  func EpollCreate1(flag int) (fd int, err error) {
   209  	return impl.epollcreate1(flag)
   210  }
   211  
   212  func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
   213  	return impl.epollctl(epfd, op, fd, event)
   214  }
   215  
   216  // Because EpollWait mutates events, the caller is expected to coordinate
   217  // concurrent access if calling with the same epfd from multiple goroutines.
   218  func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
   219  	return impl.epollwait(epfd, events, msec)
   220  }
   221  

View as plain text