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