BIND 10 trac642, updated. 49deb2642865c1db3e65e6066949b6fa8dbcbe26 Catch any uncaught exceptions in our main loop, and exit the main loop if we get them. We use this feature to handle the new test case, which is when our stdout goes away.

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Apr 18 13:12:29 UTC 2011


The branch, trac642 has been updated
       via  49deb2642865c1db3e65e6066949b6fa8dbcbe26 (commit)
      from  6e9d04eafe8928e1e428727f0fe164ff744b3c1b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 49deb2642865c1db3e65e6066949b6fa8dbcbe26
Author: Shane Kerr <shane at isc.org>
Date:   Mon Apr 18 14:59:26 2011 +0200

    Catch any uncaught exceptions in our main loop, and exit the main loop
    if we get them.
    We use this feature to handle the new test case, which is when our
    stdout goes away.

-----------------------------------------------------------------------

Summary of changes:
 src/bin/bind10/bind10.py.in            |   79 ++++++++++++++++++--------------
 src/bin/bind10/tests/bind10_test.py.in |   38 +++++++++++++++-
 2 files changed, 81 insertions(+), 36 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index a8c63f8..f72f314 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -991,47 +991,56 @@ def report_boot_time():
             })
     boss_of_bind.cc_session.group_sendmsg(cmd, 'Stats')
 
+import traceback
+
+# In our main loop, we check for dead processes or messages 
+# on the c-channel.
 def main_loop(wakeup_pipe):
     global options
     global boss_of_bind
 
-    # In our main loop, we check for dead processes or messages 
-    # on the c-channel.
-    wakeup_fd = wakeup_pipe[0]
-    ccs_fd = boss_of_bind.ccs.get_socket().fileno()
-    while boss_of_bind.runnable:
-        # clean up any processes that exited
-        boss_of_bind.reap_children()
-        next_restart = boss_of_bind.restart_processes()
-        if next_restart is None:
-            wait_time = None
-        else:
-            wait_time = max(next_restart - time.time(), 0)
-
-        # select() can raise EINTR when a signal arrives, 
-        # even if they are resumable, so we have to catch
-        # the exception
-        try:
-            (rlist, wlist, xlist) = select.select([wakeup_fd, ccs_fd], [], [], 
-                                                  wait_time)
-        except select.error as err:
-            if err.args[0] == errno.EINTR:
-                (rlist, wlist, xlist) = ([], [], [])
+    try:
+        wakeup_fd = wakeup_pipe[0]
+        ccs_fd = boss_of_bind.ccs.get_socket().fileno()
+        while boss_of_bind.runnable:
+            # clean up any processes that exited
+            boss_of_bind.reap_children()
+            next_restart = boss_of_bind.restart_processes()
+            if next_restart is None:
+                wait_time = None
             else:
-                sys.stderr.write("[bind10] Error with select(); %s\n" % err)
-                break
-
-        for fd in rlist + xlist:
-            if fd == ccs_fd:
-                try:
-                    boss_of_bind.ccs.check_command()
-                except isc.cc.session.ProtocolError:
-                    if options.verbose:
-                        sys.stderr.write("[bind10] msgq channel disappeared.\n")
+                wait_time = max(next_restart - time.time(), 0)
+    
+            # select() can raise EINTR when a signal arrives, 
+            # even if they are resumable, so we have to catch
+            # the exception
+            try:
+                (rlist, wlist, xlist) = select.select([wakeup_fd, ccs_fd], 
+                                                      [], [], wait_time)
+            except select.error as err:
+                if err.args[0] == errno.EINTR:
+                    (rlist, wlist, xlist) = ([], [], [])
+                else:
+                    sys.stderr.write("[bind10] Error with select(); %s\n" % err)
                     break
-            elif fd == wakeup_fd:
-                os.read(wakeup_fd, 32)
-
+    
+            for fd in rlist + xlist:
+                if fd == ccs_fd:
+                    try:
+                        boss_of_bind.ccs.check_command()
+                    except isc.cc.session.ProtocolError:
+                        if options.verbose:
+                            sys.stderr.write("[bind10] msgq channel disappeared.\n")
+                        break
+                elif fd == wakeup_fd:
+                    os.read(wakeup_fd, 32)
+    except Exception as ex:
+        if hasattr(boss_of_bind, 'runnable'):
+            boss_of_bind.runnable = False
+        traceback.print_exc()
+        sys.stderr.write("[bind10] Exception in main loop: " + str(ex))
+        
+    
 def shutdown():
     global boss_of_bind
     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index fc4a863..2178724 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -128,6 +128,15 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.cfg_start_auth, True)
         self.assertEqual(bob.cfg_start_resolver, False)
 
+# Mock-up of the ccs class, as used by the bind10 main program.
+class MockCCS:
+    def __init__(self):
+        self.sock = open("/dev/null", "r+")
+    def get_socket(self):
+        return self.sock
+    def check_command(self):
+        pass
+
 # Class for testing the BoB without actually starting processes.
 # This is used for testing the start/stop components routines and
 # the BoB commands.
@@ -155,6 +164,7 @@ class MockBob(BoB):
         self.cmdctl = False
         self.c_channel_env = {}
         self.processes = { }
+        self.ccs = MockCCS()
 
     def read_bind10_config(self):
         # Configuration options are set directly
@@ -628,7 +638,6 @@ class TestSignalHandling(unittest.TestCase):
             signals.append(signal.SIGXCPU)
         if hasattr(signal, 'SIGXFSZ'):
             signals.append(signal.SIGXFSZ)
-        print(signals)
         for sig in signals:
             self.bossSetUp()
             bind10.setup(self.wakeup_pipe)
@@ -656,5 +665,32 @@ class TestSignalHandling(unittest.TestCase):
         self.assertTrue(bind10.boss_of_bind.runnable)
         self.bossTearDown()
 
+class TestTTYDisconnect(unittest.TestCase):
+    # Here we check what happens if the TTY we are outputting go goes 
+    # away. 
+    def test_tty_disconnect(self):
+        self.save_bob_class = bind10.BoB
+        self.save_stdout = sys.stdout
+        self.save_stderr = sys.stderr
+
+        bind10.BoB = MockBob
+        sys.stdout = open("/dev/null", "w")
+        self.wakeup_pipe = os.pipe()
+        bind10.setup(self.wakeup_pipe)
+
+        sys.stdout.close()
+        sys.stderr = open("/dev/null", "w")
+        bind10.main_loop(self.wakeup_pipe)
+
+        sys.stderr = self.save_stderr
+        sys.stdout = self.save_stdout
+        os.close(self.wakeup_pipe[0])
+        os.close(self.wakeup_pipe[1])
+
+        self.assertFalse(bind10.boss_of_bind.runnable)
+
+        bind10.BoB = self.save_bob_class
+        
+
 if __name__ == '__main__':
     unittest.main()




More information about the bind10-changes mailing list