]>
git.proxmox.com Git - mirror_ovs.git/blob - python/ovs/poller.py
1 # Copyright (c) 2010, 2015 Nicira, Inc.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
25 if sys
.platform
== "win32":
26 import ovs
.winutils
as winutils
29 from OpenSSL
import SSL
34 from eventlet
import patcher
as eventlet_patcher
36 def _using_eventlet_green_select():
37 return eventlet_patcher
.is_monkey_patched(select
)
39 eventlet_patcher
= None
41 def _using_eventlet_green_select():
45 from gevent
import monkey
as gevent_monkey
50 vlog
= ovs
.vlog
.Vlog("poller")
59 # eventlet/gevent doesn't support select.poll. If select.poll is used,
60 # python interpreter is blocked as a whole instead of switching from the
61 # current thread that is about to block to other runnable thread.
62 # So emulate select.poll by select.select because using python means that
63 # performance isn't so important.
64 class _SelectSelect(object):
65 """ select.poll emulation by using select.select.
66 Only register and poll are needed at the moment.
73 def register(self
, fd
, events
):
74 if isinstance(fd
, socket
.socket
):
76 if SSL
and isinstance(fd
, SSL
.Connection
):
79 if sys
.platform
!= 'win32':
80 # Skip this on Windows, it also register events
81 assert isinstance(fd
, int)
91 def poll(self
, timeout
):
92 # XXX workaround a bug in eventlet
93 # see https://github.com/eventlet/eventlet/pull/25
94 if timeout
== 0 and _using_eventlet_green_select():
96 if sys
.platform
== 'win32':
97 events
= self
.rlist
+ self
.wlist
+ self
.xlist
100 if len(events
) > winutils
.win32event
.MAXIMUM_WAIT_OBJECTS
:
101 raise WindowsError("Cannot handle more than maximum wait"
104 # win32event.INFINITE timeout is -1
105 # timeout must be an int number, expressed in ms
109 timeout
= int(timeout
)
111 # Wait until any of the events is set to signaled
113 retval
= winutils
.win32event
.WaitForMultipleObjects(
117 except winutils
.pywintypes
.error
:
118 return [(0, POLLERR
)]
120 if retval
== winutils
.winerror
.WAIT_TIMEOUT
:
123 if events
[retval
] in self
.rlist
:
125 elif events
[retval
] in self
.wlist
:
130 return [(events
[retval
], revent
)]
133 # epoll uses -1 for infinite timeout, select uses None.
136 timeout
= float(timeout
) / 1000
137 rlist
, wlist
, xlist
= select
.select(self
.rlist
,
143 events_dict
[fd
] = events_dict
.get(fd
, 0) | POLLIN
145 events_dict
[fd
] = events_dict
.get(fd
, 0) | POLLOUT
147 events_dict
[fd
] = events_dict
.get(fd
, 0) |
(POLLERR |
150 return list(events_dict
.items())
153 SelectPoll
= _SelectSelect
154 # If eventlet/gevent isn't used, we can use select.poll by replacing
155 # _SelectPoll with select.poll class
156 # _SelectPoll = select.poll
159 class Poller(object):
160 """High-level wrapper around the "poll" system call.
162 Intended usage is for the program's main loop to go about its business
163 servicing whatever events it needs to. Then, when it runs out of immediate
164 tasks, it calls each subordinate module or object's "wait" function, which
165 in turn calls one (or more) of the functions Poller.fd_wait(),
166 Poller.immediate_wake(), and Poller.timer_wait() to register to be awakened
167 when the appropriate event occurs. Then the main loop calls
168 Poller.block(), which blocks until one of the registered events happens."""
173 def fd_wait(self
, fd
, events
):
174 """Registers 'fd' as waiting for the specified 'events' (which should
175 be select.POLLIN or select.POLLOUT or their bitwise-OR). The following
176 call to self.block() will wake up when 'fd' becomes ready for one or
177 more of the requested events.
179 The event registration is one-shot: only the following call to
180 self.block() is affected. The event will need to be re-registered
181 after self.block() is called if it is to persist.
183 'fd' may be an integer file descriptor or an object with a fileno()
184 method that returns an integer file descriptor."""
185 self
.poll
.register(fd
, events
)
187 def __timer_wait(self
, msec
):
188 if self
.timeout
< 0 or msec
< self
.timeout
:
191 def timer_wait(self
, msec
):
192 """Causes the following call to self.block() to block for no more than
193 'msec' milliseconds. If 'msec' is nonpositive, the following call to
194 self.block() will not block at all.
196 The timer registration is one-shot: only the following call to
197 self.block() is affected. The timer will need to be re-registered
198 after self.block() is called if it is to persist."""
200 self
.immediate_wake()
202 self
.__timer
_wait
(msec
)
204 def timer_wait_until(self
, msec
):
205 """Causes the following call to self.block() to wake up when the
206 current time, as returned by ovs.timeval.msec(), reaches 'msec' or
207 later. If 'msec' is earlier than the current time, the following call
208 to self.block() will not block at all.
210 The timer registration is one-shot: only the following call to
211 self.block() is affected. The timer will need to be re-registered
212 after self.block() is called if it is to persist."""
213 now
= ovs
.timeval
.msec()
215 self
.immediate_wake()
217 self
.__timer
_wait
(msec
- now
)
219 def immediate_wake(self
):
220 """Causes the following call to self.block() to wake up immediately,
225 """Blocks until one or more of the events registered with
226 self.fd_wait() occurs, or until the minimum duration registered with
227 self.timer_wait() elapses, or not at all if self.immediate_wake() has
231 events
= self
.poll
.poll(self
.timeout
)
232 self
.__log
_wakeup
(events
)
234 """ On Windows, the select function from poll raises OSError
235 exception if the polled array is empty."""
236 if e
.errno
!= errno
.EINTR
:
237 vlog
.err("poll: %s" % os
.strerror(e
.errno
))
238 except select
.error
as e
:
241 if error
!= errno
.EINTR
:
242 vlog
.err("poll: %s" % e
[1])
246 def __log_wakeup(self
, events
):
248 vlog
.dbg("%d-ms timeout" % self
.timeout
)
250 for fd
, revents
in events
:
255 if revents
& POLLOUT
:
257 if revents
& POLLERR
:
259 if revents
& POLLHUP
:
261 if revents
& POLLNVAL
:
263 vlog
.dbg("%s on fd %d" % (s
, fd
))
266 self
.poll
= SelectPoll()
270 def get_system_poll():
271 """Returns the original select.poll() object. If select.poll is
272 monkey patched by eventlet or gevent library, it gets the original
273 select.poll and returns an object of it using the
274 eventlet.patcher.original/gevent.monkey.get_original functions.
276 As a last resort, if there is any exception it returns the
280 if _using_eventlet_green_select():
281 _system_poll
= eventlet_patcher
.original("select").poll
282 elif gevent_monkey
and gevent_monkey
.is_object_patched(
284 _system_poll
= gevent_monkey
.get_original('select', 'poll')
286 _system_poll
= select
.poll
288 _system_poll
= SelectPoll
290 return _system_poll()