Commit 063fe8e3 authored by Tim Peters's avatar Tim Peters

Duplicate asyncore.loop again, this time a meld of 2.3's and 2.4's, in

an attempt to be compatible with both.
parent e75e2c06
...@@ -89,6 +89,13 @@ FileStorage ...@@ -89,6 +89,13 @@ FileStorage
ThreadedAsync.LoopCallback ThreadedAsync.LoopCallback
-------------------------- --------------------------
- (3.4.1a6) This once again physically replaces Python's ``asyncore.loop``
function with its own loop function, because it turns out Zope relied on
the seemingly unused ``LoopCallback.exit_status`` global, which was
removed in the change described below. Python's ``asyncore.loop`` is again
not invoked, so any breakpoints or debugging prints added to that are again
"lost".
- (3.4.1a1) This replaces Python's ``asyncore.loop`` function with its own, - (3.4.1a1) This replaces Python's ``asyncore.loop`` function with its own,
in order to get notified when ``loop()`` is first called. The signature of in order to get notified when ``loop()`` is first called. The signature of
``asyncore.loop`` changed in Python 2.4, but ``LoopCallback.loop``'s ``asyncore.loop`` changed in Python 2.4, but ``LoopCallback.loop``'s
......
...@@ -29,7 +29,10 @@ socket map as its first argument. ...@@ -29,7 +29,10 @@ socket map as its first argument.
import asyncore import asyncore
import thread import thread
_original_asyncore_loop = asyncore.loop # Zope pokes a non-None value into exit_status when it wants the loop()
# function to exit. Indeed, there appears to be no other way to tell
# Zope3 to shut down.
exit_status = None
_loop_lock = thread.allocate_lock() _loop_lock = thread.allocate_lock()
_looping = None # changes to socket map when loop() starts _looping = None # changes to socket map when loop() starts
...@@ -66,14 +69,36 @@ def remove_loop_callback(callback): ...@@ -66,14 +69,36 @@ def remove_loop_callback(callback):
del _loop_callbacks[i] del _loop_callbacks[i]
return return
# Caution: the signature of asyncore.loop changed in Python 2.4. # Because of the exit_status magic, we can't just invoke asyncore.loop(),
# That's why we use `args` and `kws` instead of spelling out the # and that's a shame.
# "intended" arguments. Since we _replace_ asyncore.loop with this # The signature of asyncore.loop changed between Python 2.3 and 2.4, and
# loop(), we need to be compatible with all signatures. # this loop() has 2.4's signature, which added the optional `count` argument.
def loop(*args, **kws): # Since we physically replace asyncore.loop with this `loop`, and want
# compatibility with both Pythons, we need to support the most recent
# signature. Applications running under 2.3 should (of course) avoid using
# the `count` argument, since 2.3 doesn't have it.
def loop(timeout=30.0, use_poll=False, map=None, count=None):
global _looping global _looping
global exit_status
map = kws.get("map", asyncore.socket_map) exit_status = None
if map is None:
map = asyncore.socket_map
# This section is taken from Python 2.3's asyncore.loop, and is more
# elaborate than the corresponding section of 2.4's: in 2.4 poll2 and
# poll3 are aliases for the same function, in 2.3 they're different
# functions.
if use_poll:
if hasattr(select, 'poll'):
poll_fun = asyncore.poll3
else:
poll_fun = asyncore.poll2
else:
poll_fun = asyncore.poll
# The loop is about to start: invoke any registered callbacks.
_loop_lock.acquire() _loop_lock.acquire()
try: try:
_looping = map _looping = map
...@@ -83,7 +108,15 @@ def loop(*args, **kws): ...@@ -83,7 +108,15 @@ def loop(*args, **kws):
finally: finally:
_loop_lock.release() _loop_lock.release()
result = _original_asyncore_loop(*args, **kws) # Run the loop. This is 2.4's logic, with the addition that we stop
# if/when this module's exit_status global is set to a non-None value.
if count is None:
while map and exit_status is None:
poll_fun(timeout, map)
else:
while map and count > 0 and exit_status is None:
poll_fun(timeout, map)
count -= 1
_loop_lock.acquire() _loop_lock.acquire()
try: try:
...@@ -91,16 +124,15 @@ def loop(*args, **kws): ...@@ -91,16 +124,15 @@ def loop(*args, **kws):
finally: finally:
_loop_lock.release() _loop_lock.release()
return result
# Evil: rebind asyncore.loop to the above loop() function. # Evil: rebind asyncore.loop to the above loop() function.
# #
# Code should explicitly call ThreadedAsync.loop() instead of asyncore.loop(). # Code should explicitly call ThreadedAsync.loop() instead of asyncore.loop().
# Most of ZODB has been fixed, but ripping this out may break 3rd party code. # Most of ZODB has been fixed, but ripping this out may break 3rd party code.
# Maybe we should issue a warning and let it continue for a while. Or # Maybe we should issue a warning and let it continue for a while (NOTE: code
# maybe we should get rid of this mechanism entirely, and have each ZEO # to raise DeprecationWarning was written but got commented out below; don't
# piece that needs one run its own asyncore loop in its own thread. # know why it got commented out). Or maybe we should get rid of this
# mechanism entirely, and have each piece that needs one run its own asyncore
# loop in its own thread.
##def deprecated_loop(*args, **kws): ##def deprecated_loop(*args, **kws):
## import warnings ## import warnings
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment