/pypy/module/select/interp_epoll.py

https://github.com/alemacgo/pypy · Python · 176 lines · 141 code · 35 blank · 0 comment · 17 complexity · 6d8c114841cf530fd1c0ba2f9aa7bc31 MD5 · raw file

  1. from __future__ import with_statement
  2. import errno
  3. from pypy.interpreter.baseobjspace import Wrappable
  4. from pypy.interpreter.gateway import interp2app, unwrap_spec
  5. from pypy.interpreter.error import OperationError, operationerrfmt, exception_from_errno
  6. from pypy.interpreter.typedef import TypeDef, GetSetProperty
  7. from pypy.rpython.lltypesystem import lltype, rffi
  8. from pypy.rpython.tool import rffi_platform
  9. from pypy.rlib._rsocket_rffi import socketclose, FD_SETSIZE
  10. from pypy.rlib.rposix import get_errno
  11. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  12. eci = ExternalCompilationInfo(
  13. includes = ['sys/epoll.h']
  14. )
  15. class CConfig:
  16. _compilation_info_ = eci
  17. CConfig.epoll_data = rffi_platform.Struct("union epoll_data", [
  18. ("fd", rffi.INT),
  19. ])
  20. CConfig.epoll_event = rffi_platform.Struct("struct epoll_event", [
  21. ("events", rffi.UINT),
  22. ("data", CConfig.epoll_data)
  23. ])
  24. for symbol in ["EPOLL_CTL_ADD", "EPOLL_CTL_MOD", "EPOLL_CTL_DEL"]:
  25. setattr(CConfig, symbol, rffi_platform.DefinedConstantInteger(symbol))
  26. cconfig = rffi_platform.configure(CConfig)
  27. epoll_event = cconfig["epoll_event"]
  28. EPOLL_CTL_ADD = cconfig["EPOLL_CTL_ADD"]
  29. EPOLL_CTL_MOD = cconfig["EPOLL_CTL_MOD"]
  30. EPOLL_CTL_DEL = cconfig["EPOLL_CTL_DEL"]
  31. epoll_create = rffi.llexternal(
  32. "epoll_create", [rffi.INT], rffi.INT, compilation_info=eci
  33. )
  34. epoll_ctl = rffi.llexternal(
  35. "epoll_ctl",
  36. [rffi.INT, rffi.INT, rffi.INT, lltype.Ptr(epoll_event)],
  37. rffi.INT,
  38. compilation_info=eci
  39. )
  40. epoll_wait = rffi.llexternal(
  41. "epoll_wait",
  42. [rffi.INT, lltype.Ptr(rffi.CArray(epoll_event)), rffi.INT, rffi.INT],
  43. rffi.INT,
  44. compilation_info=eci,
  45. )
  46. class W_Epoll(Wrappable):
  47. def __init__(self, space, epfd):
  48. self.epfd = epfd
  49. @unwrap_spec(sizehint=int)
  50. def descr__new__(space, w_subtype, sizehint=-1):
  51. if sizehint == -1:
  52. sizehint = FD_SETSIZE - 1
  53. elif sizehint < 0:
  54. raise operationerrfmt(space.w_ValueError,
  55. "sizehint must be greater than zero, got %d", sizehint
  56. )
  57. epfd = epoll_create(sizehint)
  58. if epfd < 0:
  59. raise exception_from_errno(space, space.w_IOError)
  60. return space.wrap(W_Epoll(space, epfd))
  61. @unwrap_spec(fd=int)
  62. def descr_fromfd(space, w_cls, fd):
  63. return space.wrap(W_Epoll(space, fd))
  64. def __del__(self):
  65. self.close()
  66. def check_closed(self, space):
  67. if self.get_closed():
  68. raise OperationError(space.w_ValueError,
  69. space.wrap("I/O operation on closed epoll fd")
  70. )
  71. def get_closed(self):
  72. return self.epfd < 0
  73. def close(self):
  74. if not self.get_closed():
  75. socketclose(self.epfd)
  76. self.epfd = -1
  77. def epoll_ctl(self, space, ctl, w_fd, eventmask, ignore_ebadf=False):
  78. fd = space.c_filedescriptor_w(w_fd)
  79. with lltype.scoped_alloc(epoll_event) as ev:
  80. ev.c_events = rffi.cast(rffi.UINT, eventmask)
  81. rffi.setintfield(ev.c_data, 'c_fd', fd)
  82. result = epoll_ctl(self.epfd, ctl, fd, ev)
  83. if ignore_ebadf and get_errno() == errno.EBADF:
  84. result = 0
  85. if result < 0:
  86. raise exception_from_errno(space, space.w_IOError)
  87. def descr_get_closed(self, space):
  88. return space.wrap(self.get_closed())
  89. def descr_fileno(self, space):
  90. self.check_closed(space)
  91. return space.wrap(self.epfd)
  92. def descr_close(self, space):
  93. self.check_closed(space)
  94. self.close()
  95. @unwrap_spec(eventmask=int)
  96. def descr_register(self, space, w_fd, eventmask=-1):
  97. self.check_closed(space)
  98. self.epoll_ctl(space, EPOLL_CTL_ADD, w_fd, eventmask)
  99. def descr_unregister(self, space, w_fd):
  100. self.check_closed(space)
  101. self.epoll_ctl(space, EPOLL_CTL_DEL, w_fd, 0, ignore_ebadf=True)
  102. @unwrap_spec(eventmask=int)
  103. def descr_modify(self, space, w_fd, eventmask=-1):
  104. self.check_closed(space)
  105. self.epoll_ctl(space, EPOLL_CTL_MOD, w_fd, eventmask)
  106. @unwrap_spec(timeout=float, maxevents=int)
  107. def descr_poll(self, space, timeout=-1.0, maxevents=-1):
  108. self.check_closed(space)
  109. if timeout < 0:
  110. timeout = -1.0
  111. else:
  112. timeout *= 1000.0
  113. if maxevents == -1:
  114. maxevents = FD_SETSIZE - 1
  115. elif maxevents < 1:
  116. raise operationerrfmt(space.w_ValueError,
  117. "maxevents must be greater than 0, not %d", maxevents
  118. )
  119. with lltype.scoped_alloc(rffi.CArray(epoll_event), maxevents) as evs:
  120. nfds = epoll_wait(self.epfd, evs, maxevents, int(timeout))
  121. if nfds < 0:
  122. raise exception_from_errno(space, space.w_IOError)
  123. elist_w = [None] * nfds
  124. for i in xrange(nfds):
  125. event = evs[i]
  126. elist_w[i] = space.newtuple(
  127. [space.wrap(event.c_data.c_fd), space.wrap(event.c_events)]
  128. )
  129. return space.newlist(elist_w)
  130. W_Epoll.typedef = TypeDef("select.epoll",
  131. __new__ = interp2app(W_Epoll.descr__new__.im_func),
  132. fromfd = interp2app(W_Epoll.descr_fromfd.im_func, as_classmethod=True),
  133. closed = GetSetProperty(W_Epoll.descr_get_closed),
  134. fileno = interp2app(W_Epoll.descr_fileno),
  135. close = interp2app(W_Epoll.descr_close),
  136. register = interp2app(W_Epoll.descr_register),
  137. unregister = interp2app(W_Epoll.descr_unregister),
  138. modify = interp2app(W_Epoll.descr_modify),
  139. poll = interp2app(W_Epoll.descr_poll),
  140. )
  141. W_Epoll.typedef.acceptable_as_base_class = False