diff --git a/Milter/__init__.py b/Milter/__init__.py
index 26eecf57ece7a5354be0722938d596a3f3e0dd6d..0e80797669fdc9fbf8af8e8f7fb53e67b09c1d43 100755
--- a/Milter/__init__.py
+++ b/Milter/__init__.py
@@ -28,6 +28,7 @@ def uniqueID():
   _seq_lock.release()
   return seqno
 
+## @private
 OPTIONAL_CALLBACKS = {
   'connect':(P_NR_CONN,P_NOCONNECT),
   'hello':(P_NR_HELO,P_NOHELO),
@@ -40,6 +41,7 @@ OPTIONAL_CALLBACKS = {
   'header':(P_NR_HDR,P_NOHDRS)
 }
 
+## @private
 def decode_mask(bits,names):
   t = [ (s,getattr(milter,s)) for s in names]
   nms = [s for s,m in t if bits & m]
@@ -47,6 +49,13 @@ def decode_mask(bits,names):
   if bits: nms += hex(bits)
   return nms
 
+## @fn set_flags(flags)
+# @brief Enable optional %milter actions.
+# Certain %milter actions need to be enabled before calling milter.runmilter()
+# or they throw an exception. 
+# @param flags Bit ored mask of optional actions to enable
+
+
 ## Class decorator to enable optional protocol steps.
 # P_SKIP is enabled by default when supported, but
 # applications may wish to enable P_HDR_LEADSPC
@@ -538,12 +547,6 @@ class Milter(Base):
 # change in configuration.
 factory = Milter
 
-## @fn set_flags(flags)
-# @brief Enable optional %milter actions.
-# Certain %milter actions need to be enabled before calling milter.runmilter()
-# or they throw an exception. 
-# @param flags Bit ored mask of optional actions to enable
-
 ## @private
 # @brief Connect context to connection instance and return enabled callbacks.
 def negotiate_callback(ctx,opts):
diff --git a/README b/README
index 45dd4ec2c168b8e7f66c9aa8d8a6e8fbd90ec394..c4fc66356fc48f3add8bd2dd2f76ca751d952f87 100644
--- a/README
+++ b/README
@@ -69,8 +69,7 @@ Not-so-quick Installation
 First install Sendmail.  Make sure you read libmilter/README in the Sendmail
 source directory, and make sure you enable libmilter before you build.  The
 8.11 series had libmilter marked as FFR (For Future Release); 8.12
-officially
-supports libmilter, but it's still not built by default.
+officially supports libmilter, but it's still not built by default.
 
 Install Python, and enable threading in Modules/Setup.
 
diff --git a/doc/mainpage.py b/doc/mainpage.py
index e63f2b28db8874554c1d1fb12708e490e729a0d2..f8d31b833e0b595e0393507013f12c51b2eeb185 100644
--- a/doc/mainpage.py
+++ b/doc/mainpage.py
@@ -1,6 +1,5 @@
 ## @mainpage Writing Milters in Python
 #
-# 
 # At the lowest level, the <code>milter</code> module provides a thin wrapper
 # around the <a href="https://www.milter.org/developers/api/index"> sendmail
 # libmilter API</a>.  This API lets you register callbacks for a number of
@@ -34,3 +33,21 @@
 # The <code>mime</code> module provides a wrapper for the Python email package
 # that fixes some bugs, and simplifies modifying selected parts of a MIME
 # message.
+#
+# @section threading
+#
+# The libmilter library which pymilter wraps 
+# <a href="https://www.milter.org/developers/overview#SignalHandling">handles
+# all signals</a> itself, and expects to be called from a single main thread.
+# It handles SIGTERM, SIGHUP, and SIGINT, mapping the first two to 
+# <a href="https://www.milter.org/developers/api/smfi_stop">smfi_stop</a>
+# and the last to an internal ABORT.
+#
+# If you use python threads or threading modules, then signal handling gets
+# confused.  Threads may still be useful, but you may need to provide an
+# alternate means of causing graceful shutdown.
+#
+# You may find the
+# <a href="http://docs.python.org/release/2.6.6/library/multiprocessing.html">
+# multiprocessing</a> module useful.  It can be a drop-in
+# replacement for threading as illustrated in @ref milter-template.py.
diff --git a/milter-template.py b/milter-template.py
index d995c173c876591c0cf91564b67f0e6d35f47e3c..ee72380b4cb26bd54fe4bb343a6133796a59ee87 100644
--- a/milter-template.py
+++ b/milter-template.py
@@ -14,7 +14,13 @@ import email
 import sys
 from socket import AF_INET, AF_INET6
 from Milter.utils import parse_addr
+if True:
+  from multiprocessing import Process as Thread, Queue
+else:
+  from threading import Thread
+  from Queue import Queue
 
+logq = Queue(maxsize=4)
 
 class myMilter(Milter.Base):
 
@@ -117,16 +123,24 @@ class myMilter(Milter.Base):
   ## === Support Functions ===
 
   def log(self,*msg):
-    print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S'),self.id),
+    logq.put((msg,self.id,time.time()))
+
+def background():
+  while True:
+    t = logq.get()
+    if not t: break
+    msg,id,ts = t
+    print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S',time.localtime(ts)),id),
     # 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
     for i in msg: print i,
     print
 
-
 ## ===
     
 def main():
-  socketname = "/tmp/pythonsock"
+  bt = Thread(target=background)
+  bt.start()
+  socketname = "/home/stuart/pythonsock"
   timeout = 600
   # Register to have the Milter factory create instances of your class:
   Milter.factory = myMilter
@@ -136,7 +150,9 @@ def main():
   Milter.set_flags(flags)       # tell Sendmail which features we use
   print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
   sys.stdout.flush()
-  Milter.runmilter("test",socketname,timeout)
+  Milter.runmilter("pythonfilter",socketname,timeout)
+  logq.put(None)
+  bt.join()
   print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
 
 if __name__ == "__main__":
diff --git a/pymilter.spec b/pymilter.spec
index 09f3a85f5ffdd122457579cb18e74aa04dcf9703..8a7b70b4946866d4b59accfd5cc50d94f77eb83b 100644
--- a/pymilter.spec
+++ b/pymilter.spec
@@ -13,8 +13,9 @@ License: GPLv2+
 Group: Development/Libraries
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
 Url: http://www.bmsi.com/python/milter.html
-Requires: %{pythonbase}, sendmail >= 8.13
-# Need python2.4 specific pydns, not the version for system python
+# python-2.6.4 gets RuntimeError: not holding the import lock
+Requires: %{pythonbase} >= 2.6.5, sendmail >= 8.13
+# Need python2.6 specific pydns, not the version for system python
 Requires: %{pythonbase}-pydns
 # Needed for callbacks, not a core function but highly useful for milters
 BuildRequires: ed, %{pythonbase}-devel, sendmail-devel >= 8.13
@@ -77,6 +78,7 @@ rm -rf $RPM_BUILD_ROOT
 * Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.5-1
 - Print milter.error for invalid callback return type.
   (Since stacktrace is empty, the TypeError exception is confusing.)
+- Fix milter-template.py
 
 * Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.4-1
 - Handle IP6 in Milter.utils.iniplist()