epoll_zos.go 5.0 KB

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