epoll_zos.go 5.0 KB

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