select.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #
  2. # Copyright 2012 Facebook
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. """Select-based IOLoop implementation.
  16. Used as a fallback for systems that don't support epoll or kqueue.
  17. """
  18. from __future__ import absolute_import, division, print_function
  19. import select
  20. from tornado.ioloop import IOLoop, PollIOLoop
  21. class _Select(object):
  22. """A simple, select()-based IOLoop implementation for non-Linux systems"""
  23. def __init__(self):
  24. self.read_fds = set()
  25. self.write_fds = set()
  26. self.error_fds = set()
  27. self.fd_sets = (self.read_fds, self.write_fds, self.error_fds)
  28. def close(self):
  29. pass
  30. def register(self, fd, events):
  31. if fd in self.read_fds or fd in self.write_fds or fd in self.error_fds:
  32. raise IOError("fd %s already registered" % fd)
  33. if events & IOLoop.READ:
  34. self.read_fds.add(fd)
  35. if events & IOLoop.WRITE:
  36. self.write_fds.add(fd)
  37. if events & IOLoop.ERROR:
  38. self.error_fds.add(fd)
  39. # Closed connections are reported as errors by epoll and kqueue,
  40. # but as zero-byte reads by select, so when errors are requested
  41. # we need to listen for both read and error.
  42. # self.read_fds.add(fd)
  43. def modify(self, fd, events):
  44. self.unregister(fd)
  45. self.register(fd, events)
  46. def unregister(self, fd):
  47. self.read_fds.discard(fd)
  48. self.write_fds.discard(fd)
  49. self.error_fds.discard(fd)
  50. def poll(self, timeout):
  51. readable, writeable, errors = select.select(
  52. self.read_fds, self.write_fds, self.error_fds, timeout)
  53. events = {}
  54. for fd in readable:
  55. events[fd] = events.get(fd, 0) | IOLoop.READ
  56. for fd in writeable:
  57. events[fd] = events.get(fd, 0) | IOLoop.WRITE
  58. for fd in errors:
  59. events[fd] = events.get(fd, 0) | IOLoop.ERROR
  60. return events.items()
  61. class SelectIOLoop(PollIOLoop):
  62. def initialize(self, **kwargs):
  63. super(SelectIOLoop, self).initialize(impl=_Select(), **kwargs)