[Zodb-checkins] SVN: ZODB/trunk/ Merge rev 30894 from 3.4 branch.
Tim Peters
tim.one at comcast.net
Wed Jun 22 18:11:25 EDT 2005
Log message for revision 30895:
Merge rev 30894 from 3.4 branch.
Largely rewritten.
remove_loop_callback(): There were two definitions of this function.
Deleted one, changed the other to use enumerate().
poll(): This was trying to repair a bug in Python 2.2's asyncore.poll().
2.2 is no longer supported, so removed this poll().
_start_loop(), _stop_loop(): Removed; functionality folded into
reworked loop().
loop(): The signature of asyncore.loop() changed in 2.4, but this
still had "the old" signature. Instead of sniffing the signature
of the Python in use, this does a saner thing: the original
asyncore.loop is captured, and called from the body of this loop().
That way, (A) we don't care what asyncore.loop's signature is; and,
(B) we still call the original Python code, so debugging prints and
breakpoints (etc) stuffed into Python's asyncore no longer "vanish
by magic" when ZEO is used.
Changed:
U ZODB/trunk/NEWS.txt
U ZODB/trunk/src/ThreadedAsync/LoopCallback.py
-=-
Modified: ZODB/trunk/NEWS.txt
===================================================================
--- ZODB/trunk/NEWS.txt 2005-06-22 22:04:30 UTC (rev 30894)
+++ ZODB/trunk/NEWS.txt 2005-06-22 22:11:24 UTC (rev 30895)
@@ -1,11 +1,12 @@
-What's new in ZODB3 3.5a3?
+What's new in ZODB3 3.5a4?
==========================
-Release date: 17-Jun-2005
+Release date: DD-MMM-2005
Following is combined news from "internal releases" (to support ongoing
Zope3 development). These are the dates of the internal releases:
-- 3.5a3 DD-MMM-2005
+- 3.5a4 DD-MMM-2005
+- 3.5a3 17-Jun-2005
- 3.5a2 16-Jun-2005
- 3.5a1 10-Jun-2005
@@ -27,6 +28,18 @@
been added. See ``ZODB/cross-database-references.txt`` for an
introduction.
+ThreadedAsync.LoopCallback
+--------------------------
+
+- (3.5a4) This replaces Python's ``asyncore.loop`` function with its own, in
+ order to get notified when ``loop()`` is first called. The signature of
+ ``asyncore.loop`` changed in Python 2.4, but ``LoopCallback.loop``'s
+ signature didn't change to match. The code here was repaired to be
+ compatible with both old and new signatures, and also repaired to invoke
+ Python's ``asyncore.loop()`` instead of replacing it entirely (so, for
+ example, debugging prints added to Python's ``asyncore.loop`` won't be
+ lost anymore).
+
FileStorage.UndoSearch
----------------------
@@ -63,7 +76,19 @@
very valuable when you want to spot strange transaction sizes via Zope's
'Undo' tab".
+ThreadedAsync.LoopCallback
+--------------------------
+- This replaces Python's ``asyncore.loop`` function with its own, in order
+ to get notified when ``loop()`` is first called. The signature of
+ ``asyncore.loop`` changed in Python 2.4, but ``LoopCallback.loop``'s
+ signature didn't change to match. The code here was repaired to be
+ compatible with both old and new signatures, and also repaired to invoke
+ Python's ``asyncore.loop()`` instead of replacing it entirely (so, for
+ example, debugging prints added to Python's ``asyncore.loop`` won't be
+ lost anymore).
+
+
What's new in ZODB3 3.4?
========================
Release date: 09-Jun-2005
Modified: ZODB/trunk/src/ThreadedAsync/LoopCallback.py
===================================================================
--- ZODB/trunk/src/ThreadedAsync/LoopCallback.py 2005-06-22 22:04:30 UTC (rev 30894)
+++ ZODB/trunk/src/ThreadedAsync/LoopCallback.py 2005-06-22 22:11:24 UTC (rev 30895)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
-"""Manage the asyncore mainloop in a multi-threaded app
+"""Manage the asyncore mainloop in a multi-threaded app.
In a multi-threaded application, only a single thread runs the
asyncore mainloop. This thread (the "mainloop thread") may not start
@@ -27,27 +27,16 @@
"""
import asyncore
-import select
import thread
-import time
-from errno import EINTR
+_original_asyncore_loop = asyncore.loop
+
_loop_lock = thread.allocate_lock()
-_looping = None
+_looping = None # changes to socket map when loop() starts
_loop_callbacks = []
-def remove_loop_callback(callback):
- """Remove a callback function registered earlier.
-
- This is useful if loop() was never called.
- """
- for i in range(len(_loop_callbacks)):
- if _loop_callbacks[i][0] == callback:
- del _loop_callbacks[i]
- return
-
def register_loop_callback(callback, args=(), kw=None):
- """Register callback function to be called when mainloop starts
+ """Register callback function to be called when mainloop starts.
The callable object callback will be invokved when the mainloop
starts. If the mainloop is currently running, the callback will
@@ -72,15 +61,21 @@
This is useful if loop() was never called.
"""
- for i in range(len(_loop_callbacks)):
- if _loop_callbacks[i][0] == callback:
+ for i, value in enumerate(_loop_callbacks):
+ if value[0] == callback:
del _loop_callbacks[i]
return
-def _start_loop(map):
+# Caution: the signature of asyncore.loop changed in Python 2.4.
+# That's why we use `args` and `kws` instead of spelling out the
+# "intended" arguments. Since we _replace_ asyncore.loop with this
+# loop(), we need to be compatible with all signatures.
+def loop(*args, **kws):
+ global _looping
+
+ map = kws.get("map", asyncore.socket_map)
_loop_lock.acquire()
try:
- global _looping
_looping = map
while _loop_callbacks:
cb, args, kw = _loop_callbacks.pop()
@@ -88,96 +83,24 @@
finally:
_loop_lock.release()
-def _stop_loop():
+ result = _original_asyncore_loop(*args, **kws)
+
_loop_lock.acquire()
try:
- global _looping
_looping = None
finally:
_loop_lock.release()
-def poll(timeout=0.0, map=None):
- """A copy of asyncore.poll() with a bug fixed (see comment).
+ return result
- (asyncore.poll2() and .poll3() don't have this bug.)
- """
- if map is None:
- map = asyncore.socket_map
- if map:
- r = []; w = []; e = []
- for fd, obj in map.items():
- if obj.readable():
- r.append(fd)
- if obj.writable():
- w.append(fd)
- if [] == r == w == e:
- time.sleep(timeout)
- else:
- try:
- r, w, e = select.select(r, w, e, timeout)
- except select.error, err:
- if err[0] != EINTR:
- raise
- else:
- # This part is missing in asyncore before Python 2.3
- return
- for fd in r:
- obj = map.get(fd)
- if obj is not None:
- try:
- obj.handle_read_event()
- except asyncore.ExitNow:
- raise asyncore.ExitNow
- except:
- obj.handle_error()
-
- for fd in w:
- obj = map.get(fd)
- if obj is not None:
- try:
- obj.handle_write_event()
- except asyncore.ExitNow:
- raise asyncore.ExitNow
- except:
- obj.handle_error()
-
-def loop(timeout=30.0, use_poll=0, map=None):
- """Invoke asyncore mainloop
-
- This function functions like the regular asyncore.loop() function
- except that it also triggers ThreadedAsync callback functions
- before starting the loop.
- """
- global exit_status
- exit_status = None
-
- if use_poll:
- if hasattr(select, 'poll'):
- poll_fun = asyncore.poll3
- else:
- poll_fun = asyncore.poll2
- else:
- poll_fun = poll
-
- if map is None:
- map = asyncore.socket_map
-
- _start_loop(map)
- while map and exit_status is None:
- poll_fun(timeout, map)
- _stop_loop()
-
-
-# This module used to do something evil -- it rebound asyncore.loop to the
-# above loop() function. What was evil about this is that if you added some
-# debugging to asyncore.loop, you'd spend 6 hours debugging why your debugging
-# code wasn't called!
+# Evil: rebind asyncore.loop to the above loop() function.
#
-# Code should instead explicitly call ThreadedAsync.loop() instead of
-# asyncore.loop(). Most of ZODB has been fixed, but ripping this out may
-# break 3rd party code. So we'll issue a warning and let it continue -- for
-# now.
+# 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.
+# Maybe we should issue a warning and let it continue for a while. Or
+# maybe we should get rid of this mechanism entirely, and have each ZEO
+# piece that needs one run its own asyncore loop in its own thread.
##def deprecated_loop(*args, **kws):
## import warnings
@@ -186,7 +109,7 @@
##You should change your code to call ThreadedAsync.loop() explicitly.""",
## DeprecationWarning)
## loop(*args, **kws)
-
+##
##asyncore.loop = deprecated_loop
asyncore.loop = loop
More information about the Zodb-checkins
mailing list