| 
									
										
										
										
											2015-06-10 09:04:22 -07:00
										 |  |  | # Copyright (c) 2010, 2015 Nicira, Inc. | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  | # | 
					
						
							|  |  |  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | # you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | # You may obtain a copy of the License at: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | # distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | # See the License for the specific language governing permissions and | 
					
						
							|  |  |  | # limitations under the License. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import errno | 
					
						
							| 
									
										
										
										
											2017-02-24 10:03:26 +08:00
										 |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  | import select | 
					
						
							|  |  |  | import socket | 
					
						
							| 
									
										
										
										
											2017-01-03 20:10:51 +00:00
										 |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 10:03:26 +08:00
										 |  |  | import ovs.timeval | 
					
						
							|  |  |  | import ovs.vlog | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 20:10:51 +00:00
										 |  |  | if sys.platform == "win32": | 
					
						
							|  |  |  |     import ovs.winutils as winutils | 
					
						
							| 
									
										
										
										
											2011-09-24 17:53:30 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-05 17:50:24 +05:30
										 |  |  | try: | 
					
						
							|  |  |  |     from OpenSSL import SSL | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     SSL = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-16 15:56:31 +09:00
										 |  |  | try: | 
					
						
							|  |  |  |     import eventlet.patcher | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _using_eventlet_green_select(): | 
					
						
							|  |  |  |         return eventlet.patcher.is_monkey_patched(select) | 
					
						
							|  |  |  | except: | 
					
						
							|  |  |  |     def _using_eventlet_green_select(): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-24 17:53:30 -07:00
										 |  |  | vlog = ovs.vlog.Vlog("poller") | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  | POLLIN = 0x001 | 
					
						
							|  |  |  | POLLOUT = 0x004 | 
					
						
							|  |  |  | POLLERR = 0x008 | 
					
						
							|  |  |  | POLLHUP = 0x010 | 
					
						
							|  |  |  | POLLNVAL = 0x020 | 
					
						
							| 
									
										
										
										
											2011-09-23 23:43:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 22:28:31 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  | # eventlet/gevent doesn't support select.poll. If select.poll is used, | 
					
						
							|  |  |  | # python interpreter is blocked as a whole instead of switching from the | 
					
						
							|  |  |  | # current thread that is about to block to other runnable thread. | 
					
						
							|  |  |  | # So emulate select.poll by select.select because using python means that | 
					
						
							|  |  |  | # performance isn't so important. | 
					
						
							|  |  |  | class _SelectSelect(object): | 
					
						
							|  |  |  |     """ select.poll emulation by using select.select.
 | 
					
						
							|  |  |  |     Only register and poll are needed at the moment. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self.rlist = [] | 
					
						
							|  |  |  |         self.wlist = [] | 
					
						
							|  |  |  |         self.xlist = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def register(self, fd, events): | 
					
						
							|  |  |  |         if isinstance(fd, socket.socket): | 
					
						
							|  |  |  |             fd = fd.fileno() | 
					
						
							| 
									
										
										
										
											2016-10-05 17:50:24 +05:30
										 |  |  |         if SSL and isinstance(fd, SSL.Connection): | 
					
						
							|  |  |  |             fd = fd.fileno() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 20:10:51 +00:00
										 |  |  |         if sys.platform != 'win32': | 
					
						
							|  |  |  |             # Skip this on Windows, it also register events | 
					
						
							|  |  |  |             assert isinstance(fd, int) | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |         if events & POLLIN: | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  |             self.rlist.append(fd) | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |             events &= ~POLLIN | 
					
						
							|  |  |  |         if events & POLLOUT: | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  |             self.wlist.append(fd) | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |             events &= ~POLLOUT | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  |         if events: | 
					
						
							|  |  |  |             self.xlist.append(fd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def poll(self, timeout): | 
					
						
							| 
									
										
										
										
											2013-04-16 15:56:31 +09:00
										 |  |  |         # XXX workaround a bug in eventlet | 
					
						
							|  |  |  |         # see https://github.com/eventlet/eventlet/pull/25 | 
					
						
							|  |  |  |         if timeout == 0 and _using_eventlet_green_select(): | 
					
						
							|  |  |  |             timeout = 0.1 | 
					
						
							| 
									
										
										
										
											2017-01-03 20:10:51 +00:00
										 |  |  |         if sys.platform == 'win32': | 
					
						
							|  |  |  |             events = self.rlist + self.wlist + self.xlist | 
					
						
							|  |  |  |             if not events: | 
					
						
							|  |  |  |                 return [] | 
					
						
							|  |  |  |             if len(events) > winutils.win32event.MAXIMUM_WAIT_OBJECTS: | 
					
						
							|  |  |  |                 raise WindowsError("Cannot handle more than maximum wait" | 
					
						
							|  |  |  |                                    "objects\n") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # win32event.INFINITE timeout is -1 | 
					
						
							|  |  |  |             # timeout must be an int number, expressed in ms | 
					
						
							|  |  |  |             if timeout == 0.1: | 
					
						
							|  |  |  |                 timeout = 100 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 timeout = int(timeout) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Wait until any of the events is set to signaled | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 retval = winutils.win32event.WaitForMultipleObjects( | 
					
						
							|  |  |  |                     events, | 
					
						
							|  |  |  |                     False,  # Wait all | 
					
						
							|  |  |  |                     timeout) | 
					
						
							|  |  |  |             except winutils.pywintypes.error: | 
					
						
							|  |  |  |                     return [(0, POLLERR)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if retval == winutils.winerror.WAIT_TIMEOUT: | 
					
						
							|  |  |  |                 return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return [(events[retval], 0)] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if timeout == -1: | 
					
						
							|  |  |  |                 # epoll uses -1 for infinite timeout, select uses None. | 
					
						
							|  |  |  |                 timeout = None | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 timeout = float(timeout) / 1000 | 
					
						
							|  |  |  |             rlist, wlist, xlist = select.select(self.rlist, | 
					
						
							|  |  |  |                                                 self.wlist, | 
					
						
							|  |  |  |                                                 self.xlist, | 
					
						
							|  |  |  |                                                 timeout) | 
					
						
							|  |  |  |             events_dict = {} | 
					
						
							|  |  |  |             for fd in rlist: | 
					
						
							|  |  |  |                 events_dict[fd] = events_dict.get(fd, 0) | POLLIN | 
					
						
							|  |  |  |             for fd in wlist: | 
					
						
							|  |  |  |                 events_dict[fd] = events_dict.get(fd, 0) | POLLOUT | 
					
						
							|  |  |  |             for fd in xlist: | 
					
						
							|  |  |  |                 events_dict[fd] = events_dict.get(fd, 0) | (POLLERR | | 
					
						
							|  |  |  |                                                             POLLHUP | | 
					
						
							|  |  |  |                                                             POLLNVAL) | 
					
						
							|  |  |  |             return list(events_dict.items()) | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-12 15:17:21 +09:00
										 |  |  | SelectPoll = _SelectSelect | 
					
						
							| 
									
										
										
										
											2012-09-05 19:38:26 +09:00
										 |  |  | # If eventlet/gevent isn't used, we can use select.poll by replacing | 
					
						
							|  |  |  | # _SelectPoll with select.poll class | 
					
						
							|  |  |  | # _SelectPoll = select.poll | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  | class Poller(object): | 
					
						
							|  |  |  |     """High-level wrapper around the "poll" system call.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Intended usage is for the program's main loop to go about its business | 
					
						
							|  |  |  |     servicing whatever events it needs to.  Then, when it runs out of immediate | 
					
						
							|  |  |  |     tasks, it calls each subordinate module or object's "wait" function, which | 
					
						
							|  |  |  |     in turn calls one (or more) of the functions Poller.fd_wait(), | 
					
						
							|  |  |  |     Poller.immediate_wake(), and Poller.timer_wait() to register to be awakened | 
					
						
							|  |  |  |     when the appropriate event occurs.  Then the main loop calls | 
					
						
							|  |  |  |     Poller.block(), which blocks until one of the registered events happens."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self.__reset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fd_wait(self, fd, events): | 
					
						
							|  |  |  |         """Registers 'fd' as waiting for the specified 'events' (which should
 | 
					
						
							|  |  |  |         be select.POLLIN or select.POLLOUT or their bitwise-OR).  The following | 
					
						
							|  |  |  |         call to self.block() will wake up when 'fd' becomes ready for one or | 
					
						
							|  |  |  |         more of the requested events. | 
					
						
							| 
									
										
										
										
											2011-09-23 23:43:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |         The event registration is one-shot: only the following call to | 
					
						
							|  |  |  |         self.block() is affected.  The event will need to be re-registered | 
					
						
							|  |  |  |         after self.block() is called if it is to persist. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         'fd' may be an integer file descriptor or an object with a fileno() | 
					
						
							|  |  |  |         method that returns an integer file descriptor."""
 | 
					
						
							|  |  |  |         self.poll.register(fd, events) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __timer_wait(self, msec): | 
					
						
							|  |  |  |         if self.timeout < 0 or msec < self.timeout: | 
					
						
							|  |  |  |             self.timeout = msec | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def timer_wait(self, msec): | 
					
						
							|  |  |  |         """Causes the following call to self.block() to block for no more than
 | 
					
						
							|  |  |  |         'msec' milliseconds.  If 'msec' is nonpositive, the following call to | 
					
						
							|  |  |  |         self.block() will not block at all. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The timer registration is one-shot: only the following call to | 
					
						
							|  |  |  |         self.block() is affected.  The timer will need to be re-registered | 
					
						
							|  |  |  |         after self.block() is called if it is to persist."""
 | 
					
						
							|  |  |  |         if msec <= 0: | 
					
						
							|  |  |  |             self.immediate_wake() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.__timer_wait(msec) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def timer_wait_until(self, msec): | 
					
						
							| 
									
										
										
										
											2011-09-23 23:43:12 -07:00
										 |  |  |         """Causes the following call to self.block() to wake up when the
 | 
					
						
							|  |  |  |         current time, as returned by ovs.timeval.msec(), reaches 'msec' or | 
					
						
							|  |  |  |         later.  If 'msec' is earlier than the current time, the following call | 
					
						
							|  |  |  |         to self.block() will not block at all. | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         The timer registration is one-shot: only the following call to | 
					
						
							|  |  |  |         self.block() is affected.  The timer will need to be re-registered | 
					
						
							|  |  |  |         after self.block() is called if it is to persist."""
 | 
					
						
							| 
									
										
										
										
											2010-09-17 15:06:17 -07:00
										 |  |  |         now = ovs.timeval.msec() | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |         if msec <= now: | 
					
						
							|  |  |  |             self.immediate_wake() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.__timer_wait(msec - now) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def immediate_wake(self): | 
					
						
							|  |  |  |         """Causes the following call to self.block() to wake up immediately,
 | 
					
						
							|  |  |  |         without blocking."""
 | 
					
						
							|  |  |  |         self.timeout = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def block(self): | 
					
						
							|  |  |  |         """Blocks until one or more of the events registered with
 | 
					
						
							|  |  |  |         self.fd_wait() occurs, or until the minimum duration registered with | 
					
						
							|  |  |  |         self.timer_wait() elapses, or not at all if self.immediate_wake() has | 
					
						
							|  |  |  |         been called."""
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 events = self.poll.poll(self.timeout) | 
					
						
							|  |  |  |                 self.__log_wakeup(events) | 
					
						
							| 
									
										
										
										
											2016-08-02 17:45:43 +00:00
										 |  |  |             except OSError as e: | 
					
						
							|  |  |  |                 """ On Windows, the select function from poll raises OSError
 | 
					
						
							|  |  |  |                 exception if the polled array is empty."""
 | 
					
						
							|  |  |  |                 if e.errno != errno.EINTR: | 
					
						
							|  |  |  |                     vlog.err("poll: %s" % os.strerror(e.errno)) | 
					
						
							| 
									
										
										
										
											2015-07-29 21:12:45 -05:00
										 |  |  |             except select.error as e: | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |                 # XXX rate-limit | 
					
						
							|  |  |  |                 error, msg = e | 
					
						
							|  |  |  |                 if error != errno.EINTR: | 
					
						
							| 
									
										
										
										
											2011-09-24 17:53:30 -07:00
										 |  |  |                     vlog.err("poll: %s" % e[1]) | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |         finally: | 
					
						
							|  |  |  |             self.__reset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __log_wakeup(self, events): | 
					
						
							|  |  |  |         if not events: | 
					
						
							| 
									
										
										
										
											2011-09-24 17:53:30 -07:00
										 |  |  |             vlog.dbg("%d-ms timeout" % self.timeout) | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |         else: | 
					
						
							|  |  |  |             for fd, revents in events: | 
					
						
							|  |  |  |                 if revents != 0: | 
					
						
							|  |  |  |                     s = "" | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |                     if revents & POLLIN: | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |                         s += "[POLLIN]" | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |                     if revents & POLLOUT: | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |                         s += "[POLLOUT]" | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |                     if revents & POLLERR: | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |                         s += "[POLLERR]" | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |                     if revents & POLLHUP: | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |                         s += "[POLLHUP]" | 
					
						
							| 
									
										
										
										
											2012-11-19 03:50:52 +09:00
										 |  |  |                     if revents & POLLNVAL: | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  |                         s += "[POLLNVAL]" | 
					
						
							| 
									
										
										
										
											2011-09-24 17:53:30 -07:00
										 |  |  |                     vlog.dbg("%s on fd %d" % (s, fd)) | 
					
						
							| 
									
										
										
										
											2010-08-25 10:26:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __reset(self): | 
					
						
							| 
									
										
										
										
											2012-09-12 15:17:21 +09:00
										 |  |  |         self.poll = SelectPoll() | 
					
						
							| 
									
										
										
										
											2011-09-23 23:43:12 -07:00
										 |  |  |         self.timeout = -1 |