]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Add AsyncEngine and TimeEngine support to the EventLoop, allowing it to
authorrobertc <>
Sat, 12 Aug 2006 07:43:10 +0000 (07:43 +0000)
committerrobertc <>
Sat, 12 Aug 2006 07:43:10 +0000 (07:43 +0000)
completely replace the old one embedded in main.cc - convert loop using
tests to use an event loop instance.

25 files changed:
src/AsyncEngine.cc [new file with mode: 0644]
src/AsyncEngine.h [new file with mode: 0644]
src/CompletionDispatcher.h
src/EventLoop.cc
src/EventLoop.h
src/Makefile.am
src/SquidTime.h
src/comm.cc
src/comm.h
src/comm_poll.cc
src/event.cc
src/event.h
src/main.cc
src/tests/testCoss.cc
src/tests/testEvent.cc
src/tests/testEventLoop.cc
src/tests/testEventLoop.h
src/tests/testHeader_AsyncEngine.cc [new file with mode: 0644]
src/tests/testHeader_SquidTime.cc [new file with mode: 0644]
src/tests/testNull.cc
src/tests/testStoreSupport.cc [new file with mode: 0644]
src/tests/testStoreSupport.h [new file with mode: 0644]
src/tests/testUfs.cc
src/time.cc
test-suite/test_tools.cc

diff --git a/src/AsyncEngine.cc b/src/AsyncEngine.cc
new file mode 100644 (file)
index 0000000..9887fd3
--- /dev/null
@@ -0,0 +1,34 @@
+
+/*
+ * $Id: AsyncEngine.cc,v 1.1 2006/08/12 01:43:10 robertc Exp $
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "AsyncEngine.h"
diff --git a/src/AsyncEngine.h b/src/AsyncEngine.h
new file mode 100644 (file)
index 0000000..c41fd9a
--- /dev/null
@@ -0,0 +1,86 @@
+
+/*
+ * $Id: AsyncEngine.h,v 1.1 2006/08/12 01:43:10 robertc Exp $
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_ASYNCENGINE_H
+#define SQUID_ASYNCENGINE_H
+
+#include "squid.h"
+
+
+/* Abstract interface for async engines which an event loop can utilise.
+ *
+ * Some implementations will be truely async, others like the event engine
+ * will be pseudo async.
+ */
+
+class AsyncEngine
+{
+
+public:
+    /* error codes returned from checkEvents. If the return value is not
+     * negative, then it is the requested delay until the next call. If it is
+     * negative, it is one of the following codes:
+     */
+    enum CheckError {
+        /* this engine is completely idle: it has no pending events, and nothing
+         * registered with it that can create events
+         */
+        EVENT_IDLE = -1,
+        /* some error has occured in this engine */
+        EVENT_ERROR = -2,
+    };
+
+    virtual ~AsyncEngine() {}
+
+    /* Check the engine for events. If there are events that have completed,
+     * the engine should at this point hand them off to their dispatcher.
+     * Engines that operate asynchronously - i.e. the DiskThreads engine - 
+     * should hand events off to their dispatcher as they arrive rather than
+     * waiting for checkEvents to be called. Engines like poll and select should
+     * use this call as the time to perform their checks with the OS for new
+     * events.
+     *
+     * The return value is the status code of the event checking. If its a
+     * non-negative value then it is used as hint for the minimum requested
+     * time before checkEvents is called again. I.e. the event engine knows
+     * how long it is until the next event will be scheduled - so it will 
+     * return that time (in milliseconds).
+     *
+     * The timeout value is a requested timeout for this engine - the engine
+     * should not block for more than this period. (If it takes longer than the
+     * timeout to do actual checks thats fine though undesirable).
+     */
+    virtual int checkEvents(int timeout) = 0;
+};
+
+#endif /* SQUID_ASYNCENGINE_H */
index 3d49451bce17a0913226e3c62d22edeead78c617..afbff9f5d43586692cf27050421d31a52701c6e4 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: CompletionDispatcher.h,v 1.1 2006/08/07 02:28:22 robertc Exp $
+ * $Id: CompletionDispatcher.h,v 1.2 2006/08/12 01:43:10 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -49,7 +49,10 @@ public:
 
     virtual ~CompletionDispatcher() {}
 
-    virtual void dispatch() = 0;
+    /* dispatch events. This should return true if there were events dispatched
+     * between the last call to dispatch() returning and this call returning.
+     */
+    virtual bool dispatch() = 0;
 };
 
 #endif /* SQUID_COMPLETIONDISPATCHER_H */
index 23e85d5483ed985df78a9df93879759969586a3f..ddf74bda2b754684780c700bd08364d19f90d6a0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: EventLoop.cc,v 1.1 2006/08/07 02:28:22 robertc Exp $
+ * $Id: EventLoop.cc,v 1.2 2006/08/12 01:43:10 robertc Exp $
  *
  * DEBUG: section 1     Main Loop
  * AUTHOR: Harvest Derived
  *
  */
 
-#include "squid.h"
-#include "event.h"
 #include "EventLoop.h"
-#include "comm.h"
 
-EventLoop::EventLoop() : errcount(0), last_loop(false)
+EventLoop::EventLoop() : errcount(0), last_loop(false), timeService(NULL)
 {}
 
 void
@@ -54,68 +51,87 @@ EventLoop::registerDispatcher(CompletionDispatcher *dispatcher)
     dispatchers.push_back(dispatcher);
 }
 
+void
+EventLoop::registerEngine(AsyncEngine *engine)
+{
+    engines.push_back(engine);
+}
+
 void
 EventLoop::run()
 {
     prepareToRun();
 
-    while (!last_loop)
-        runOnce();
+    while (!runOnce())
+
+        ;
 }
 
-void
+bool
 EventLoop::runOnce()
 {
-    int loop_delay = EventScheduler::GetInstance()->checkEvents();
+    bool result = true;
+    bool error = false;
+    int loop_delay = 10; /* 10 ms default delay */
+
+    for (engine_vector::iterator i = engines.begin();
+            i != engines.end(); ++i) {
+        int requested_delay;
+        /* special case the last engine */
+
+        if (i - engines.end() != -1)
+            requested_delay = (*i)->checkEvents(0);
+        else /* last engine gets the delay */
+            requested_delay = (*i)->checkEvents(loop_delay);
+
+        if (requested_delay < 0)
+            switch (requested_delay) {
+
+            case AsyncEngine::EVENT_IDLE:
+                debugs(1, 9, "Engine " << *i << " is idle.");
+                break;
+
+            case AsyncEngine::EVENT_ERROR:
+                result = false;
+                error = true;
+                break;
+
+            default:
+                fatal_dump("unknown AsyncEngine result");
+            }
+        else if (requested_delay < loop_delay) {
+            loop_delay = requested_delay;
+            result = false;
+        }
+    }
+
+    if (timeService != NULL)
+        timeService->tick();
 
     for (dispatcher_vector::iterator i = dispatchers.begin();
             i != dispatchers.end(); ++i)
-        (*i)->dispatch();
-
-    if (loop_delay < 0)
-        loop_delay = 0;
-
-    switch (comm_select(loop_delay)) {
-
-    case COMM_OK:
-        errcount = 0;  /* reset if successful */
-        break;
-
-    case COMM_IDLE:
-        /* TODO: rather than busy loop, if everything has returned IDLE we should
-         * wait for a reasonable timeout period, - if everything returned IDLE
-         * then not only is there no work to do, there is no work coming in -
-         * all the comm loops have no fds registered, and  all the other 
-         * async engines have no work active or pending.
-         * ... perhaps we can have a query method to say 'when could there be 
-         * work' - i.e. the event dispatcher can return the next event in its
-         * queue, and everything else can return -1.
-         */
-        errcount = 0;
-        break;
+        if ((*i)->dispatch())
+            result = false;
 
-    case COMM_ERROR:
-        errcount++;
+    if (error) {
+        ++errcount;
         debugs(1, 0, "Select loop Error. Retry " << errcount);
+    } else
+        errcount = 0;
 
-        if (errcount == 10)
-            fatal_dump("Select Loop failed 10 times.!");
-
-        break;
-
-    case COMM_TIMEOUT:
-        break;
-
-    case COMM_SHUTDOWN:
-        stop();
+    if (errcount == 10)
+        return true;
 
-        break;
+    if (last_loop)
+        return true;
 
-    default:
-        fatal_dump("MAIN: Internal error -- this should never happen.");
+    return result;
+}
 
-        break;
-    }
+void
+EventLoop::setTimeService(TimeEngine *engine)
+{
+    timeService = engine;
 }
 
 void
index c1cbd96bc55f402e59ce12e9044c7e6ab653f580..e7500c62e90f056d043732aae997f99dbf2d3e00 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: EventLoop.h,v 1.1 2006/08/07 02:28:22 robertc Exp $
+ * $Id: EventLoop.h,v 1.2 2006/08/12 01:43:10 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -36,7 +36,9 @@
 
 #include "squid.h"
 #include "Array.h"
+#include "AsyncEngine.h"
 #include "CompletionDispatcher.h"
+#include "SquidTime.h"
 
 /* An event loop. An event loop is the core inner loop of squid.
  * The event loop can be run until exit, or once. After it finishes control
@@ -52,26 +54,41 @@ public:
     EventLoop();
     /* register an event dispatcher to be invoked on each event loop. */
     void registerDispatcher(CompletionDispatcher *dispatcher);
-    /* start the event loop running */
+    /* register an async engine which will be given the opportunity to perform
+     * in-main-thread tasks each event loop.
+     */
+    void registerEngine(AsyncEngine *engine);
+    /* start the event loop running. The loop will run until it is stopped by
+     * calling stop(), or when the loop is completely idle - nothing 
+     * dispatched in a loop, and all engines idle.
+     */
     void run();
     /* run the loop once. This may not complete all events! It should therefor
      * be used with care.
      * TODO: signal in runOnce whether or not the loop is over - IDLE vs OK vs
      * TIMEOUT?
      */
-    void runOnce();
+    bool runOnce();
+    /* set the time service. There can be only one time service set at any
+     * time. The time service is invoked on each loop 
+     */
+    void setTimeService(TimeEngine *engine);
     /* stop the event loop - it will finish the current loop and then return to the
      * caller of run().
      */
     void stop();
 
+    int errcount;
+
 private:
     /* setup state variables prior to running */
     void prepareToRun();
-    int errcount;
     bool last_loop;
     typedef Vector<CompletionDispatcher *> dispatcher_vector;
     dispatcher_vector dispatchers;
+    typedef Vector<AsyncEngine *> engine_vector;
+    engine_vector engines;
+    TimeEngine * timeService;
 };
 
 
index 03bc25dbee52d2e1023bf7b97f749c83f02031cf..f561157cd98de7700fcde45cb40e34d95f220160 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.159 2006/08/07 02:28:22 robertc Exp $
+#  $Id: Makefile.am,v 1.160 2006/08/12 01:43:10 robertc Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -381,6 +381,8 @@ squid_SOURCES = \
        ACLChecklist.h \
        $(squid_ACLSOURCES) \
        asn.cc \
+       AsyncEngine.cc \
+       AsyncEngine.h \
        authenticate.cc \
        authenticate.h \
        cache_cf.cc \
@@ -1643,6 +1645,7 @@ tests_testEventLoop_DEPENDENCIES =  $(top_builddir)/lib/libmiscutil.a \
 ## RBC 20060422.
 HEADERS_TO_TEST = \
        tests/testHeader_ACL.cc \
+       tests/testHeader_AsyncEngine.cc \
        tests/testHeader_CompletionDispatcher.cc \
        tests/testHeader_ConfigParser.cc \
        tests/testHeader_client_side_request.cc \
@@ -1654,6 +1657,7 @@ HEADERS_TO_TEST = \
        tests/testHeader_HttpHeaderRange.cc \
        tests/testHeader_HttpReply.cc \
        tests/testHeader_HttpRequestMethod.cc \
+       tests/testHeader_SquidTime.cc \
        tests/testHeader_Store.cc \
        tests/testHeader_StoreEntryStream.cc \
        tests/testHeader_URL.cc \
@@ -1964,6 +1968,8 @@ STORE_TEST_SOURCES=\
        $(DELAY_POOL_SOURCE) \
        CacheDigest.cc \
        ConfigParser.cc \
+       EventLoop.cc \
+       event.cc \
        HttpMsg.cc \
        store_dir.cc \
        store.cc \
@@ -1982,7 +1988,7 @@ STORE_TEST_SOURCES=\
        mem_node.cc \
        stmem.cc \
        tests/stub_mime.cc \
-       HttpHeaderTools.cc HttpHeader.cc acl.cc event.cc mem.cc \
+       HttpHeaderTools.cc HttpHeader.cc acl.cc mem.cc \
        acl_noncore.cc \
        MemBuf.cc HttpHdrContRange.cc Packer.cc ACLChecklist.cc HttpHdrCc.cc HttpHdrSc.cc \
        HttpHdrScTarget.cc url.cc ACLProxyAuth.cc ACLRegexData.cc ACLUserData.cc \
@@ -1991,6 +1997,8 @@ STORE_TEST_SOURCES=\
        refresh.cc \
        tests/stub_store_client.cc \
        tests/stub_tools.cc \
+       tests/testStoreSupport.cc \
+       tests/testStoreSupport.h \
        time.cc \
        URLScheme.cc \
        wordlist.cc
index 45954e633c268451e04f740dd875a1dbb42bc2b4..23cb493952a643e1600ff225e5db9640894f58f5 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: SquidTime.h,v 1.1 2006/05/08 23:38:33 robertc Exp $
+ * $Id: SquidTime.h,v 1.2 2006/08/12 01:43:11 robertc Exp $
  *
  * DEBUG: section 21    Time Functions
  * AUTHOR: Harvest Derived
@@ -42,4 +42,16 @@ extern time_t squid_curtime; /* 0 */
 
 time_t getCurrentTime(void);
 
+/* event class for doing synthetic time etc */
+
+class TimeEngine
+{
+
+public:
+    virtual ~TimeEngine();
+    /* tick the clock - update from the OS or other time source, */
+    virtual void tick();
+};
+
+
 #endif /* SQUID_TIME_H */
index 8df6963b29a64a6900cf43abb15bdc7946a3da8b..d5e4b84cf07335160c5f995698f3062b23076bf6 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: comm.cc,v 1.420 2006/08/07 02:28:22 robertc Exp $
+ * $Id: comm.cc,v 1.421 2006/08/12 01:43:11 robertc Exp $
  *
  * DEBUG: section 5     Socket Functions
  * AUTHOR: Harvest Derived
@@ -2640,3 +2640,38 @@ ConnectionDetail::ConnectionDetail() {
     memset(&me, 0, sizeof(me));
     memset(&peer, 0, sizeof(peer));
 }
+
+bool
+CommDispatcher::dispatch() {
+    bool result = comm_iocallbackpending();
+    comm_calliocallback();
+    /* and again to deal with indirectly queued events
+     * resulting from the first call. These are usually
+     * callbacks and should be dealt with immediately.
+     */
+    comm_calliocallback();
+    return result;
+}
+
+int
+CommSelectEngine::checkEvents(int timeout) {
+    switch (comm_select(timeout)) {
+
+    case COMM_OK:
+
+    case COMM_TIMEOUT:
+        return 0;
+
+    case COMM_IDLE:
+
+    case COMM_SHUTDOWN:
+        return EVENT_IDLE;
+
+    case COMM_ERROR:
+        return EVENT_ERROR;
+
+    default:
+        fatal_dump("comm.cc: Internal error -- this should never happen.");
+        return EVENT_ERROR;
+    };
+}
index dd91d402beb9f0948218124da7ed6ae946f37077..402084e0f8f906697240f1ce8f81819ed4bdbb85 100644 (file)
@@ -2,6 +2,8 @@
 #define __COMM_H__
 
 #include "squid.h"
+#include "AsyncEngine.h"
+#include "CompletionDispatcher.h"
 #include "StoreIOBuffer.h"
 #include "Array.h"
 
@@ -179,4 +181,22 @@ private:
     void removeCheck (int const);
 };
 
+/* a dispatcher for comms events */
+
+class CommDispatcher : public CompletionDispatcher
+{
+
+public:
+    virtual bool dispatch();
+};
+
+/* A comm engine that calls comm_select */
+
+class CommSelectEngine : public AsyncEngine
+{
+
+public:
+    virtual int checkEvents(int timeout);
+};
+
 #endif
index eca9f8a6369f95e93147514385ef32979004f863..5e7d4b3c011decd121b32798626c3f64b424dcf8 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: comm_poll.cc,v 1.17 2006/08/07 02:28:22 robertc Exp $
+ * $Id: comm_poll.cc,v 1.18 2006/08/12 01:43:11 robertc Exp $
  *
  * DEBUG: section 5     Socket Functions
  *
@@ -433,7 +433,11 @@ comm_select(int msec)
         if (msec > MAX_POLL_TIME)
             msec = MAX_POLL_TIME;
 
-        /* nothing to do */
+        /* nothing to do
+         *
+         * Note that this will only ever trigger when there are no log files
+         * and stdout/err/in are all closed too.
+         */
         if (nfds == 0 && !npending) {
             if (shutting_down)
                 return COMM_SHUTDOWN;
index 3deb6937943c61853680f840f0d4fe0fd211018f..74ee38322f631e6289839c9e7b3319790ecedd36 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: event.cc,v 1.41 2006/08/07 02:28:22 robertc Exp $
+ * $Id: event.cc,v 1.42 2006/08/12 01:43:11 robertc Exp $
  *
  * DEBUG: section 41    Event Processing
  * AUTHOR: Henrik Nordstrom
@@ -111,9 +111,11 @@ EventDispatcher::add
     queue.push_back(event);
 }
 
-void
+bool
 EventDispatcher::dispatch()
 {
+    bool result = queue.size() != 0;
+
     for (Vector<ev_entry *>::iterator i = queue.begin(); i != queue.end(); ++i) {
         ev_entry * event = *i;
         EVH *callback;
@@ -132,6 +134,7 @@ EventDispatcher::dispatch()
     }
 
     queue.clean();
+    return result;
 }
 
 EventDispatcher *
@@ -182,11 +185,16 @@ EventScheduler::checkDelay()
     if (!tasks)
         return (int) 10;
 
-    return (int) ((tasks->when - current_dtime) * 1000);
+    int result = (int) ((tasks->when - current_dtime) * 1000);
+
+    if (result < 0)
+        return 0;
+
+    return result;
 }
 
 int
-EventScheduler::checkEvents()
+EventScheduler::checkEvents(int timeout)
 {
 
     struct ev_entry *event = NULL;
index 2831feb89c62adb399ef752c3f087a6e53cac4c0..66cd16ae01f8a052c29644c0317fe966343c22e3 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: event.h,v 1.1 2006/08/07 02:28:22 robertc Exp $
+ * $Id: event.h,v 1.2 2006/08/12 01:43:11 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -36,6 +36,7 @@
 
 #include "squid.h"
 #include "Array.h"
+#include "AsyncEngine.h"
 #include "CompletionDispatcher.h"
 
 /* forward decls */
@@ -86,7 +87,7 @@ public:
     void add
         (const char *name, EVH * func, void *arg, double when, int, bool cbdata=true);
 
-    void dispatch();
+    bool dispatch();
 
     static EventDispatcher *GetInstance();
 
@@ -96,12 +97,16 @@ private:
     static EventDispatcher _instance;
 };
 
-class EventScheduler
+class EventScheduler : public AsyncEngine
 {
 
 public:
     /* Create an event scheduler that will hand its ready to run callbacks to
-     * an EventDispatcher */
+     * an EventDispatcher 
+     *
+     * TODO: add should include a dispatcher to use perhaps? then it would be
+     * more decoupled..
+     */
     EventScheduler(EventDispatcher *);
     ~EventScheduler();
     /* cancel a scheduled but not dispatched event */
@@ -116,7 +121,7 @@ public:
     bool find(EVH * func, void * arg);
     /* schedule a callback function to run in when seconds */
     void schedule(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata=true);
-    int checkEvents();
+    int checkEvents(int timeout);
     static EventScheduler *GetInstance();
 
 private:
index c829130bb34edd27c31b4e735c0c08dbf03c0e84..493ce0265591239f17f0e1d96b7b79ec75f7121d 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.cc,v 1.428 2006/08/07 02:28:22 robertc Exp $
+ * $Id: main.cc,v 1.429 2006/08/12 01:43:11 robertc Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -114,7 +114,7 @@ static void setEffectiveUser(void);
 extern void log_trace_done();
 extern void log_trace_init(char *);
 #endif
-static EVH SquidShutdown;
+static void SquidShutdown(void);
 static void mainSetCwd(void);
 static int checkRunningPid(void);
 
@@ -128,14 +128,27 @@ static const char *squid_start_script = "squid_start";
 #include "test_access.c"
 #endif
 
+/* temporary thunk across to the unrefactored store interface */
+
+class StoreRootEngine : public AsyncEngine
+{
+
+public:
+    int checkEvents(int timeout)
+    {
+        Store::Root().callback();
+        return EVENT_IDLE;
+    };
+};
+
 class SignalDispatcher : public CompletionDispatcher
 {
 
 public:
-    SignalDispatcher(EventLoop &loop) : loop(loop) {}
+    SignalDispatcher(EventLoop &loop) : loop(loop), events_dispatched(false) {}
 
     void addEventLoop(EventLoop * loop);
-    virtual void dispatch();
+    virtual bool dispatch();
 
 private:
     static void StopEventLoop(void * data)
@@ -144,9 +157,10 @@ private:
     }
 
     EventLoop &loop;
+    bool events_dispatched;
 };
 
-void
+bool
 SignalDispatcher::dispatch()
 {
     if (do_reconfigure) {
@@ -176,9 +190,12 @@ SignalDispatcher::dispatch()
 #endif
 
         serverConnectionsClose();
-        //eventAdd("SquidShutdown", StopEventLoop, this, (double) (wait + 1), 1, false);
-        eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1, false);
+        eventAdd("SquidShutdown", StopEventLoop, this, (double) (wait + 1), 1, false);
     }
+
+    bool result = events_dispatched;
+    events_dispatched = false;
+    return result;
 }
 
 static void
@@ -1301,25 +1318,36 @@ main(int argc, char **argv)
     /* TODO: stop requiring the singleton here */
     mainLoop.registerDispatcher(EventDispatcher::GetInstance());
 
-    for (;;)
-    {
-        /* Attempt any pending storedir IO
-        * Note: the storedir is roughly a reactor of its own.
-        */
-        Store::Root().callback();
+    /* TODO: stop requiring the singleton here */
+    mainLoop.registerEngine(EventScheduler::GetInstance());
 
-        comm_calliocallback();
+    StoreRootEngine store_engine;
 
-        /* and again to deal with indirectly queued events
-         * resulting from the first call. These are usually
-         * callbacks and should be dealt with immediately.
-         */
+    mainLoop.registerEngine(&store_engine);
 
-        if (comm_iocallbackpending())
-            comm_calliocallback();
+    CommDispatcher comm_dispatcher;
 
-        mainLoop.runOnce();
-    }
+    mainLoop.registerDispatcher(&comm_dispatcher);
+
+    CommSelectEngine comm_engine;
+
+    /* must be last - its the only engine that implements timeouts properly
+     * at the moment.
+     */
+    mainLoop.registerEngine(&comm_engine);
+
+    /* use the standard time service */
+    TimeEngine time_engine;
+
+    mainLoop.setTimeService(&time_engine);
+
+    mainLoop.run();
+
+    if (mainLoop.errcount == 10)
+        fatal_dump("Event loop exited with failure.");
+
+    /* shutdown squid now */
+    SquidShutdown();
 
     /* NOTREACHED */
     return 0;
@@ -1587,7 +1615,7 @@ watch_child(char *argv[])
 }
 
 static void
-SquidShutdown(void *unused)
+SquidShutdown()
 {
 #if USE_WIN32_SERVICE
     WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
index 501422ff2ef078f6eacd576f2751e8584eefc494..ad1a898f1f5e28dbf1498b233eb648dc0dd78c4c 100644 (file)
@@ -11,7 +11,7 @@
 #include "HttpHeader.h"
 #include "HttpReply.h"
 #include "StoreFileSystem.h"
-#include "SquidTime.h"
+#include "testStoreSupport.h"
 
 #define TESTDIR "testCoss__testCossSearch"
 
@@ -172,12 +172,10 @@ testCoss::testCossSearch()
     /* ok, ready to use */
     Store::Root().init();
 
-    /* ensure rebuilding finishes - run a mini event loop */
-    while (store_dirs_rebuilding > 1) {
-        getCurrentTime();
-        EventScheduler::GetInstance()->checkEvents();
-        EventDispatcher::GetInstance()->dispatch();
-    }
+    /* rebuild is a scheduled event */
+    StockEventLoop loop;
+
+    loop.run();
 
     /* nothing to rebuild */
     CPPUNIT_ASSERT(store_dirs_rebuilding == 1);
index b00be3301be63295ed6fb38187599698398731a7..9b30c2376d17b341412568b38b6130d5b5617c55 100644 (file)
@@ -62,8 +62,10 @@ testEvent::testDispatch()
     EventDispatcher dispatcher;
     CalledEvent event;
     dispatcher.add(new ev_entry("test event", CalledEvent::Handler, &event, 0, 0, false));
-    dispatcher.dispatch();
-    dispatcher.dispatch();
+    /* return true when an event is dispatched */
+    CPPUNIT_ASSERT_EQUAL(true, dispatcher.dispatch());
+    /* return false when none were dispatched */
+    CPPUNIT_ASSERT_EQUAL(false, dispatcher.dispatch());
     CPPUNIT_ASSERT_EQUAL(1, event.calls);
 }
 
@@ -79,7 +81,7 @@ testEvent::testCancel()
     scheduler.schedule("test event", CalledEvent::Handler, &event, 0, 0, false);
     scheduler.schedule("test event2", CalledEvent::Handler, &event_to_cancel, 0, 0, false);
     scheduler.cancel(CalledEvent::Handler, &event_to_cancel);
-    scheduler.checkEvents();
+    scheduler.checkEvents(0);
     dispatcher.dispatch();
     CPPUNIT_ASSERT_EQUAL(1, event.calls);
     CPPUNIT_ASSERT_EQUAL(0, event_to_cancel.calls);
@@ -97,7 +99,7 @@ testEvent::testDump()
     CapturingStoreEntry * anEntry = new CapturingStoreEntry();
     scheduler.schedule("last event", CalledEvent::Handler, &event, 0, 0, false);
     /* schedule and dispatch to set the last run event */
-    scheduler.checkEvents();
+    scheduler.checkEvents(0);
     dispatcher.dispatch();
     scheduler.schedule("test event", CalledEvent::Handler, &event, 0, 0, false);
     scheduler.schedule("test event2", CalledEvent::Handler, &event2, 0, 0, false);
@@ -133,14 +135,14 @@ testEvent::testCheckEvents()
     EventDispatcher dispatcher;
     EventScheduler scheduler(&dispatcher);
     CalledEvent event;
-    CPPUNIT_ASSERT_EQUAL(10, scheduler.checkEvents());
+    CPPUNIT_ASSERT_EQUAL(10, scheduler.checkEvents(0));
     /* event running now gets sent to the dispatcher and the delay is set to 10ms */
     scheduler.schedule("test event", CalledEvent::Handler, &event, 0, 0, false);
-    CPPUNIT_ASSERT_EQUAL(10, scheduler.checkEvents());
+    CPPUNIT_ASSERT_EQUAL(10, scheduler.checkEvents(0));
     dispatcher.dispatch();
     /* event running later results in  a delay of the time till it runs */
     scheduler.schedule("test event", CalledEvent::Handler, &event, 2, 0, false);
-    CPPUNIT_ASSERT_EQUAL(2000, scheduler.checkEvents());
+    CPPUNIT_ASSERT_EQUAL(2000, scheduler.checkEvents(0));
     dispatcher.dispatch();
     CPPUNIT_ASSERT_EQUAL(1, event.calls);
 }
index 2a28bfbf2b6cc33ebe42c22698084c8cf5d40ca7..753b5bdd3a7c0e05f7f4d3404a6c75e4fee77efa 100644 (file)
@@ -1,10 +1,12 @@
 #include "squid.h"
 #include <cppunit/TestAssert.h>
 
+#include "AsyncEngine.h"
 #include "CompletionDispatcher.h"
 #include "Mem.h"
 #include "testEventLoop.h"
 #include "EventLoop.h"
+#include "event.h"
 
 
 CPPUNIT_TEST_SUITE_REGISTRATION( testEventLoop );
@@ -43,8 +45,8 @@ testEventLoop::testCreate()
  * Running the loop once is useful for integration with other loops, such as 
  * migrating to it in incrementally.
  *
- * This test works by having a customer dispatcher which records how many times its
- * called.
+ * This test works by having a custom dispatcher and engine which record how
+ * many times they are called.
  */
 
 class RecordDispatcher : public CompletionDispatcher
@@ -59,27 +61,57 @@ public:
     {
         ++calls;
     }
+
+    bool dispatch()
+    {
+        ++calls;
+        /* claim we dispatched calls to be useful for the testStopOnIdle test.
+         */
+        return true;
+    }
 };
 
+class RecordingEngine : public AsyncEngine
+{
+
+public:
+    int calls;
+    int lasttimeout;
+    int return_timeout;
+    RecordingEngine(int return_timeout=0): calls(0), lasttimeout(0),
+            return_timeout(return_timeout)
+          {}
+
+          virtual int checkEvents(int timeout)
+          {
+              ++calls;
+              lasttimeout = timeout;
+              return return_timeout;
+          }
+      };
+
 void
 testEventLoop::testRunOnce()
 {
     EventLoop theLoop;
     RecordDispatcher dispatcher;
     theLoop.registerDispatcher(&dispatcher);
+    RecordingEngine engine;
+    theLoop.registerEngine(&engine);
     theLoop.runOnce();
     CPPUNIT_ASSERT_EQUAL(1, dispatcher.calls);
+    CPPUNIT_ASSERT_EQUAL(1, engine.calls);
 }
 
 /*
- * completion dispatchers registered with the event loop are invoked by the event 
- * loop.
+ * completion dispatchers registered with the event loop are invoked by the
+ * event loop.
  *
- * This test works by having a customer dispatcher which shuts the loop down once its
- * been invoked twice.
+ * This test works by having a customer dispatcher which shuts the loop down
+ * once its been invoked twice.
  *
- * It also tests that loop.run() and loop.stop() work, because if they dont work,
- * this test will either hang, or fail.
+ * It also tests that loop.run() and loop.stop() work, because if they dont
+ * work, this test will either hang, or fail.
  */
 
 class ShutdownDispatcher : public CompletionDispatcher
@@ -96,6 +128,14 @@ public:
         if (++calls == 2)
             theLoop.stop();
     }
+
+    bool dispatch()
+    {
+        if (++calls == 2)
+            theLoop.stop();
+
+        return true;
+    }
 };
 
 void
@@ -105,5 +145,118 @@ testEventLoop::testRegisterDispatcher()
     ShutdownDispatcher testDispatcher(theLoop);
     theLoop.registerDispatcher(&testDispatcher);
     theLoop.run();
+    /* we should get two calls because the test dispatched returns true from
+     * dispatch(), and calls stop on the second call.
+     */
     CPPUNIT_ASSERT_EQUAL(2, testDispatcher.calls);
 }
+
+/* test that a registered async engine is invoked on each loop run
+ * we do this with an intstrumented async engine.
+ */
+void
+testEventLoop::testRegisterEngine()
+{
+    EventLoop theLoop;
+    ShutdownDispatcher testDispatcher(theLoop);
+    theLoop.registerDispatcher(&testDispatcher);
+    RecordingEngine testEngine;
+    theLoop.registerEngine(&testEngine);
+    theLoop.run();
+    CPPUNIT_ASSERT_EQUAL(2, testEngine.calls);
+}
+
+/* each AsyncEngine needs to be given a timeout. We want one engine in each
+ * loop to be given the timeout value - and the rest to have a timeout of 0.
+ * The last registered engine should be given this timeout, which will mean
+ * that we dont block in the loop until the last engine. This will allow for
+ * dynamic introduction and removal of engines, as long as the last engine
+ * is one which can do a os call rather than busy waiting.
+ *
+ * So - we want the timeout hints returned from the earlier engines to be
+ * tracked, and the lowest non-negative value given to the last engine.
+ */
+void
+testEventLoop::testEngineTimeout()
+{
+    EventLoop theLoop;
+    RecordingEngine engineOne(5);
+    RecordingEngine engineTwo;
+    theLoop.registerEngine(&engineOne);
+    theLoop.registerEngine(&engineTwo);
+    theLoop.runOnce();
+    CPPUNIT_ASSERT_EQUAL(0, engineOne.lasttimeout);
+    CPPUNIT_ASSERT_EQUAL(5, engineTwo.lasttimeout);
+}
+
+/* An event loop with all idle engines, and nothing dispatched in a run should
+ * automatically quit. The runOnce call should return True when the loop is
+ * entirely idle to make it easy for people running the loop by hand.
+ */
+void
+testEventLoop::testStopOnIdle()
+{
+    EventLoop theLoop;
+    /* trivial case - no dispatchers or engines, should quit immediately */
+    CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
+    theLoop.run();
+    /* add a dispatcher with nothing to dispatch - use an EventDispatcher as its
+     * sufficient and handy
+     */
+    EventDispatcher dispatcher;
+    theLoop.registerDispatcher(&dispatcher);
+    CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
+    theLoop.run();
+    /* add an engine which is idle.
+     */
+    RecordingEngine engine(AsyncEngine::EVENT_IDLE);
+    theLoop.registerEngine(&engine);
+    CPPUNIT_ASSERT_EQUAL(true, theLoop.runOnce());
+    CPPUNIT_ASSERT_EQUAL(1, engine.calls);
+    theLoop.run();
+    CPPUNIT_ASSERT_EQUAL(2, engine.calls);
+    /* add an engine which is suffering errors. This should result in 10
+     * loops until the loop stops - because thats the error retry amount
+     */
+    RecordingEngine failing_engine(AsyncEngine::EVENT_ERROR);
+    theLoop.registerEngine(&failing_engine);
+    CPPUNIT_ASSERT_EQUAL(false, theLoop.runOnce());
+    CPPUNIT_ASSERT_EQUAL(1, failing_engine.calls);
+    theLoop.run();
+    /* run resets the error count ... */
+    CPPUNIT_ASSERT_EQUAL(11, failing_engine.calls);
+}
+
+/* An event loop has a time service which is like an async engine but never
+ * generates events and there can only be one such service.
+ */
+
+class StubTime : public TimeEngine
+{
+
+public:
+    StubTime::StubTime() : calls(0) {}
+
+    int calls;
+    void tick()
+    {
+        ++calls;
+    }
+};
+
+void
+testEventLoop::testSetTimeService()
+{
+    EventLoop theLoop;
+    StubTime myTime;
+    /* the loop will not error without a time service */
+    theLoop.runOnce();
+    /* we can set the time service */
+    theLoop.setTimeService(&myTime);
+    /* it invokes our tick() call */
+    theLoop.runOnce();
+    CPPUNIT_ASSERT_EQUAL(1, myTime.calls);
+    /* it invokes our tick() call again */
+    theLoop.runOnce();
+    CPPUNIT_ASSERT_EQUAL(2, myTime.calls);
+}
index 6aa0f1d193e15c158d96035f9f9b9ca679288b30..f3df5058ee9c30ff133c011546a55480f4211a15 100644 (file)
@@ -14,14 +14,26 @@ class testEventLoop : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST( testCreate );
     CPPUNIT_TEST( testRunOnce );
     CPPUNIT_TEST( testRegisterDispatcher );
+    CPPUNIT_TEST( testRegisterEngine );
+    CPPUNIT_TEST( testEngineTimeout );
+    CPPUNIT_TEST( testSetTimeService );
+    CPPUNIT_TEST( testStopOnIdle );
     CPPUNIT_TEST_SUITE_END();
 
 public:
 
 protected:
     void testCreate();
+    void testEngineTimeout();
     void testRunOnce();
     void testRegisterDispatcher();
+    void testRegisterEngine();
+    void testSetTimeService();
+    void testStopOnIdle();
+    /* TODO:
+     * test that engine which errors a couple of times, then returns 0, then
+     * errors 10 times in a row triggers a fail on the 10th time around
+     */
 };
 
 #endif
diff --git a/src/tests/testHeader_AsyncEngine.cc b/src/tests/testHeader_AsyncEngine.cc
new file mode 100644 (file)
index 0000000..39b7820
--- /dev/null
@@ -0,0 +1,4 @@
+/* This test tests that the header below can be processed on its own with
+ * no other #includes. Dont add any!
+ */
+#include "AsyncEngine.h"
diff --git a/src/tests/testHeader_SquidTime.cc b/src/tests/testHeader_SquidTime.cc
new file mode 100644 (file)
index 0000000..d16c38f
--- /dev/null
@@ -0,0 +1,4 @@
+/* This test tests that the header below can be processed on its own with
+ * no other #includes. Dont add any!
+ */
+#include "SquidTime.h"
index cbd932e5de5e574b96ae9b6d8a1035580f241c1d..2441824f0f94d209fa044705a2a40948412a9169 100644 (file)
@@ -11,7 +11,7 @@
 #include "HttpHeader.h"
 #include "HttpReply.h"
 #include "StoreFileSystem.h"
-#include "SquidTime.h"
+#include "testStoreSupport.h"
 
 #define TESTDIR "testNull__testNullSearch"
 
@@ -140,13 +140,9 @@ testNull::testNullSearch()
     /* ok, ready to use */
     Store::Root().init();
 
-    /* ensure rebuilding finishes - run a mini event loop */
-
-    while (store_dirs_rebuilding > 1) {
-        getCurrentTime();
-        EventScheduler::GetInstance()->checkEvents();
-        EventDispatcher::GetInstance()->dispatch();
-    }
+    /* rebuild is a scheduled event */
+    StockEventLoop loop;
+    loop.run();
 
     /* nothing to rebuild */
     CPPUNIT_ASSERT(store_dirs_rebuilding == 1);
diff --git a/src/tests/testStoreSupport.cc b/src/tests/testStoreSupport.cc
new file mode 100644 (file)
index 0000000..a51350c
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ * DEBUG: 
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "testStoreSupport.h"
+#include "event.h"
+#include "EventLoop.h"
+#include "SquidTime.h"
+
+/* construct a stock loop with event dispatching, a time service that advances
+ * 1 second a tick
+ */
+StockEventLoop::StockEventLoop() : default_time_engine(TimeEngine())
+{
+    registerDispatcher(EventDispatcher::GetInstance());
+    registerEngine(EventScheduler::GetInstance());
+    setTimeService(&default_time_engine);
+}
diff --git a/src/tests/testStoreSupport.h b/src/tests/testStoreSupport.h
new file mode 100644 (file)
index 0000000..13c0c37
--- /dev/null
@@ -0,0 +1,51 @@
+
+/*
+ * DEBUG: 
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef   SQUID_TESTSTORESUPPORT_H
+#define   SQUID_TESTSTORESUPPORT_H
+
+#include "EventLoop.h"
+
+/* construct a stock loop with event dispatching, a time service that advances
+ * 1 second a tick
+ */
+
+class StockEventLoop : public EventLoop
+{
+
+public:
+    StockEventLoop();
+    TimeEngine default_time_engine;
+};
+
+#endif /* SQUID_TESTSTORESUPPORT_H */
index 3fd15da110e2fd990f8ef68f0cebee991df0d0e0..08f5a2c678cf544bca5cdb925669ae883035987a 100644 (file)
@@ -9,7 +9,7 @@
 #include "Mem.h"
 #include "HttpHeader.h"
 #include "HttpReply.h"
-#include "SquidTime.h"
+#include "testStoreSupport.h"
 
 #define TESTDIR "testUfs__testUfsSearch"
 
@@ -103,15 +103,13 @@ testUfs::testUfsSearch()
     /* ok, ready to create */
     aStore->create();
 
-    /* ok, ready to use - init store & hash too */
+    /* ok, ready to use - inits store & hash too */
     Store::Root().init();
 
-    /* ensure rebuilding finishes - run a mini event loop */
-    while (store_dirs_rebuilding > 1) {
-        getCurrentTime();
-        EventScheduler::GetInstance()->checkEvents();
-        EventDispatcher::GetInstance()->dispatch();
-    }
+    /* rebuild is a scheduled event */
+    StockEventLoop loop;
+
+    loop.run();
 
     /* nothing to rebuild */
     CPPUNIT_ASSERT(store_dirs_rebuilding == 1);
index 31985176551caef4e8277645bf0f20251a19e2fe..75101b5de0c3fab4f472bd15449632ff812e68de 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: time.cc,v 1.2 2006/05/08 23:38:33 robertc Exp $
+ * $Id: time.cc,v 1.3 2006/08/12 01:43:11 robertc Exp $
  *
  * DEBUG: section 21    Time Functions
  * AUTHOR: Harvest Derived
@@ -51,3 +51,12 @@ getCurrentTime(void)
                     (double) current_time.tv_usec / 1000000.0;
     return squid_curtime = current_time.tv_sec;
 }
+
+TimeEngine::~TimeEngine()
+{}
+
+void
+TimeEngine::tick()
+{
+    getCurrentTime();
+}
index 815452e4f52cba51623c603b2ee47082644307d0..1e26f60f7ca902cae872860d4055ccfb7a77eb3f 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: test_tools.cc,v 1.7 2005/01/03 16:08:27 robertc Exp $
+ * $Id: test_tools.cc,v 1.8 2006/08/12 01:43:12 robertc Exp $
  *
  * AUTHOR: Robert Collins
  *
@@ -107,13 +107,20 @@ va_dcl
 static void
 _db_print_stderr(const char *format, va_list args) {
     /* FIXME? */
-   // if (opt_debug_stderr < Debug::level)
-   if (1 < Debug::level)
+    // if (opt_debug_stderr < Debug::level)
+
+    if (1 < Debug::level)
         return;
 
     vfprintf(stderr, format, args);
 }
 
+void
+fatal_dump(const char *message) {
+    debug (0,0) ("Fatal: %s",message);
+    exit (1);
+}
+
 void
 fatal(const char *message) {
     debug (0,0) ("Fatal: %s",message);
@@ -131,8 +138,7 @@ fatalvf(const char *fmt, va_list args) {
 /* printf-style interface for fatal */
 #if STDC_HEADERS
 void
-fatalf(const char *fmt,...)
-{
+fatalf(const char *fmt,...) {
     va_list args;
     va_start(args, fmt);
 #else
@@ -156,16 +162,14 @@ debug_trap(const char *message) {
 }
 
 std::ostream &
-Debug::getDebugOut()
-{
+Debug::getDebugOut() {
     assert (CurrentDebug == NULL);
     CurrentDebug = new std::ostringstream();
     return *CurrentDebug;
 }
 
 void
-Debug::finishDebug()
-{
+Debug::finishDebug() {
     _db_print("%s\n", CurrentDebug->str().c_str());
     delete CurrentDebug;
     CurrentDebug = NULL;
@@ -176,8 +180,7 @@ std::ostringstream *Debug::CurrentDebug (NULL);
 MemImplementingAllocator *dlink_node_pool = NULL;
 
 dlink_node *
-dlinkNodeNew()
-{
+dlinkNodeNew() {
     if (dlink_node_pool == NULL)
         dlink_node_pool = MemPools::GetInstance().create("Dlink list nodes", sizeof(dlink_node));
 
@@ -187,8 +190,7 @@ dlinkNodeNew()
 
 /* the node needs to be unlinked FIRST */
 void
-dlinkNodeDelete(dlink_node * m)
-{
+dlinkNodeDelete(dlink_node * m) {
     if (m == NULL)
         return;
 
@@ -196,8 +198,7 @@ dlinkNodeDelete(dlink_node * m)
 }
 
 void
-dlinkAdd(void *data, dlink_node * m, dlink_list * list)
-{
+dlinkAdd(void *data, dlink_node * m, dlink_list * list) {
     m->data = data;
     m->prev = NULL;
     m->next = list->head;
@@ -212,8 +213,7 @@ dlinkAdd(void *data, dlink_node * m, dlink_list * list)
 }
 
 void
-dlinkAddAfter(void *data, dlink_node * m, dlink_node * n, dlink_list * list)
-{
+dlinkAddAfter(void *data, dlink_node * m, dlink_node * n, dlink_list * list) {
     m->data = data;
     m->prev = n;
     m->next = n->next;
@@ -229,8 +229,7 @@ dlinkAddAfter(void *data, dlink_node * m, dlink_node * n, dlink_list * list)
 }
 
 void
-dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
-{
+dlinkAddTail(void *data, dlink_node * m, dlink_list * list) {
     m->data = data;
     m->next = NULL;
     m->prev = list->tail;
@@ -245,8 +244,7 @@ dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
 }
 
 void
-dlinkDelete(dlink_node * m, dlink_list * list)
-{
+dlinkDelete(dlink_node * m, dlink_list * list) {
     if (m->next)
         m->next->prev = m->prev;
 
@@ -268,5 +266,4 @@ ctx_enter(const char *descr) {
 }
 
 void
-ctx_exit(Ctx ctx) {
-}
+ctx_exit(Ctx ctx) {}