changeset 88:01f4f5f1acc9

Changes to init and to allow compiling with gdc. Tweaked init code to allow using circular iterators (disabled until my patch makes it into tango). Changes to allow compiling with gdc. Building is successful and unittests complete, but in my experience a SIGSEGV occurs within SDL.
author Diggory Hardy <diggory.hardy@gmail.com>
date Mon, 29 Sep 2008 12:09:44 +0100
parents 2212285f714c
children 97e6dce08037
files codeDoc/jobs.txt mde/file/mergetag/DataSet.d mde/file/mergetag/DefaultData.d mde/file/serialize.d mde/setup/Init.d
diffstat 5 files changed, 97 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/jobs.txt	Tue Sep 23 12:31:48 2008 +0100
+++ b/codeDoc/jobs.txt	Mon Sep 29 12:09:44 2008 +0100
@@ -3,9 +3,11 @@
 
 
 In progress:
+
+
+
+Bugs:
 Sometimes nothing is drawn until a resize, and fonts are blocks? External bug?
-CircularIterator
-unittest again!
 
 
 
--- a/mde/file/mergetag/DataSet.d	Tue Sep 23 12:31:48 2008 +0100
+++ b/mde/file/mergetag/DataSet.d	Mon Sep 29 12:09:44 2008 +0100
@@ -63,7 +63,7 @@
         ds.sec[cast(ID)"test"] = new DefaultData;
         assert (ds.getSections!(DefaultData)().length == 1);
         ds.sec[cast(ID)"test"].addTag ("char[]",cast(ID)"T"," \"ut tag 1 \" ");
-        assert (ds.getSections!(DefaultData)()[cast(ID)"test"].Arg!(char[])[cast(ID)"T"] == "ut tag 1 ");
+        assert (ds.getSections!(DefaultData)()[cast(ID)"test"]._charA[cast(ID)"T"] == "ut tag 1 ");
     
         logger.info ("Unittest complete.");
     }
--- a/mde/file/mergetag/DefaultData.d	Tue Sep 23 12:31:48 2008 +0100
+++ b/mde/file/mergetag/DefaultData.d	Mon Sep 29 12:09:44 2008 +0100
@@ -126,17 +126,6 @@
     * int[ID] _int;		// name is type prefixed by _
     * char[][ID] _charA;	// [] is replaced by A
     * ------------------
-    *
-    * An alternative access method is to use the provided templates:
-    * --------------------
-    * template Arg(T) {
-    *     alias Name Arg;
-    * }
-    *
-    * type y = Arg!(type).Arg;	// example of use
-    * --------------------
-    * Note: trying to use Arg!(type) to implicitly refer to Arg!(type).Arg causes compiler errors
-    * due to the "alias Name Arg;" statement actually being a mixin.
     */
     /+ All types previously supported. Most of these weren't used.
     const char[][] dataTypes = ["bool","bool[]",
@@ -164,18 +153,4 @@
     void writeAll (ItemDelg itemdlg) {	/// Supports all types listed in dataTypes.
         mixin (writeVars ());
     }
-    
-    /* These make no attempt to check Arg is valid.
-    * But if the symbol doesn't exist the complier will throw an error anyway, e.g.:
-    * Error: identifier '_boolAA' is not defined
-    */
-    template ArgName (T : T[]) {
-        const char[] ArgName = ArgName!(T)~`A`;
-    }
-    template ArgName (T) {
-        const char[] ArgName = `_`~T.stringof;
-    }
-    template Arg(T) {
-        mixin(`alias `~ArgName!(T)~` Arg;`);
-    }
 }
--- a/mde/file/serialize.d	Tue Sep 23 12:31:48 2008 +0100
+++ b/mde/file/serialize.d	Mon Sep 29 12:09:44 2008 +0100
@@ -346,11 +346,11 @@
     // Structs
     struct Foo {    int a = 9;  char b = '\v'; float c;    }
     struct Bar {    Foo a,b;    }
-    static Foo foo1 = { a:150, b:'8', c:17.2f}, foo2;
+    static Foo foo1 = { a:150, b:'8'}, foo2;
     Bar bar;
     bar.a = foo1;
     bar.b = foo2;
-    assert (serialize(bar) == "{0:{0:150,1:'8',2:1.72000007e+01},1:{0:9,1:'\\v',2:nan}}");
+    assert (serialize(bar) == "{0:{0:150,1:'8',2:nan},1:{0:9,1:'\\v',2:nan}}");
     
     
     // Basic Types
@@ -386,10 +386,11 @@
     }));
     
     // Floats
-    // These numbers are not particularly meaningful:
-    assert (serialize!(float) (0.0f) == "0.00000000");
-    assert (serialize!(double) (-1e25) == "-1.00000000000000000e+25");
-    assert (serialize!(real) (cast(real) 4.918e300) == "4.91800000000000000000e+300");
+    // We can't do a proper float-test because we can't rely on numbers being printed to the same
+    // number of figures on all platforms. Do nan tests to check type is supported.
+    assert (serialize!(float) (float.init) == "nan");
+    assert (serialize!(double) (double.init) == "nan");
+    assert (serialize!(real) (real.init) == "nan");
     
     // Escape sequences (test conversion functions)
     assert (serialize ("\a\b\t\n\v\f\r\"\'\\") == `"\a\b\t\n\v\f\r\"\'\\"`);
--- a/mde/setup/Init.d	Tue Sep 23 12:31:48 2008 +0100
+++ b/mde/setup/Init.d	Mon Sep 29 12:09:44 2008 +0100
@@ -51,7 +51,7 @@
 import tango.core.Thread;
 import tango.core.sync.Condition;
 import tango.core.Exception;
-import tango.util.container.LinkedList;
+import tango.util.container.CircularList;
 
 //import tango.stdc.stringz : fromStringz;
 import tango.io.Console;	// for printing command-line usage
@@ -235,7 +235,7 @@
     
     // run init stages or cleanup if startup is false
     private static void runStages(bool startup) () {
-        LinkedList!(InitStage*) toRun = new LinkedList!(InitStage*);
+        CircularList!(InitStage*) toRun = new CircularList!(InitStage*);
         foreach (v; stages) {
             // Filter only stages with the relevant delegate. It is not checked later that the
             // delegate exists!
@@ -257,8 +257,10 @@
                 }
             }
         }
+        auto toRunIt = toRun.iterator;
         int numWorking = miscOpts.numThreads;
-        bool abortInit = false;
+        enum STATE {    WORKING = 0,    DONE = 1,       ABORT = 2 }
+        STATE doneInit = STATE.WORKING;
         Mutex toRunM = new Mutex;       // synchronization on toRun, numWorking
         Condition toRunC = new Condition(toRunM);       // used by threads waiting for remaining stages' dependencies to be met
         
@@ -275,74 +277,84 @@
          * When notified, threads start at 1. */
         void initThreadFct () {
             try {       // created as a thread - must not throw exceptions
-            InitStage* stage;
-            
-            threadLoop: while (true) {      // thread loops until a problem occurs or nothing else can be done
-            // Look for a job:
-            synchronized (toRunM) {
-                --numWorking;           // stopped working: looking/waiting for a job
-                if (abortInit) break threadLoop;  // something went wrong in another thread
-                static if (startup)
-                    int num_rdepends = (stage is null) ? 0 : stage.rdepends.length;
-                else
-                    int num_rdepends = (stage is null) ? 0 : stage.depends.length;
+                InitStage* stage;
                 
-                getStage: while (true) {
-                    auto it = toRun.iterator;   // asserts if toRun is empty
-                    itStages: while (it.next (stage)) {   // get next element of toRun
-                        static if (startup) {
-                            foreach (d; stage.depends)
-                                if (stages[d].state != StageState.ACTIVE)
-                                    continue itStages;  // dependency isn't met (yet)
-                        } else {
-                            foreach (d; stage.rdepends)
-                                if (stages[d].state != StageState.INACTIVE)
-                                    continue itStages;  // reverse dependency isn't unmet (yet)
+                threadLoop:
+                while (true) {      // thread loops until a problem occurs or nothing else can be done
+                    // Look for a job:
+                    synchronized (toRunM) {
+                    --numWorking;           // stopped working: looking/waiting for a job
+                    if (doneInit) break threadLoop;  // something went wrong in another thread
+                    
+                    static if (startup)
+                        int num_rdepends = (stage is null) ? 0 : stage.rdepends.length;
+                    else
+                        int num_rdepends = (stage is null) ? 0 : stage.depends.length;
+                    
+                    getStage:
+                    while (true) {
+                        static if (false)       // An addition to CircularList to allow continuous circular iteration; not yet in tango.
+                            toRunIt.start;                  // start circling from here
+                        else
+                            toRunIt = toRun.iterator;       // new iterator
+                        itStages:
+                        while (toRunIt.next (stage)) {   // get next element of toRun
+                            debug logger.trace ("Iterating: {}", stage);
+                            static if (startup) {
+                                foreach (d; stage.depends)
+                                    if (stages[d].state != StageState.ACTIVE)
+                                        continue itStages;  // dependency isn't met (yet)
+                            } else {
+                                foreach (d; stage.rdepends)
+                                    if (stages[d].state != StageState.INACTIVE)
+                                        continue itStages;  // reverse dependency isn't unmet (yet)
+                            }
+                            
+                            // All dependencies met
+                            debug assert (toRun.size, "toRun is empty (error with iterator)");
+                            toRunIt.remove;
+                            break getStage;
                         }
                         
-                        // All dependencies met
-                        it.remove;
-                        break getStage;
+                        // No stage remaining with all dependencies met
+                        if (toRun.size && numWorking)       // still some working so more dependencies may be met later
+                            toRunC.wait;    // wait until another thread finishes
+                            else                // no thread is working, so none of what's left is doable, or nothing's left
+                                break threadLoop;
+                    }
+                    ++numWorking;           // got a job!
+                    if (num_rdepends > 2)   // how many stages depended on the last one run?
+                        toRunC.notifyAll(); // tell all waiting threads there may be work now
+                    else if (num_rdepends == 2)
+                        toRunC.notify();    // there's potentially work for this thread and one other
+                        // else there won't be additional work so don't notify
                     }
                     
-                    // No stage remaining with all dependencies met
-                    if (!toRun.isEmpty && numWorking)     // still some working so more dependencies may be met later
-                        toRunC.wait;    // wait until another thread finishes
-                    else                // no thread is working, so none of what's left is doable, or nothing's left
+                    // Do a job:
+                    try {
+                        // FIXME - old stage start&finish trace messages - we don't have a name!
+                        debug logger.trace ("InitStage {}: starting", stage);
+                        static if (startup)
+                        stage.state = (*stage).init();  // init is a property of a pointer (oh no!)
+                        else
+                            stage.state = stage.cleanup();
+                        debug logger.trace ("InitStage {}: completed; state: {}", stage, stage.state);
+                    } catch (InitStageException e) {
+                        debug logger.trace ("InitStage {}: failed", stage);
+                        stage.state = e.state;
+                        doneInit = STATE.ABORT;
                         break threadLoop;
+                    } catch (Exception e) {
+                        debug logger.trace ("InitStage {}: failed", stage);
+                        doneInit = STATE.ABORT;
+                        break threadLoop;
+                    }
                 }
-                ++numWorking;           // got a job!
-                if (num_rdepends > 2)   // how many stages depended on the last one run?
-                    toRunC.notifyAll(); // tell all waiting threads there may be work now
-                else if (num_rdepends == 2)
-                    toRunC.notify();    // there's potentially work for this thread and one other
-                // else there won't be additional work so don't notify
-            }
-            
-            // Do a job:
-            try {
-                // FIXME - old stage start&finish trace messages - we don't have a name!
-                debug logger.trace ("InitStage {}: starting", stage);
-                static if (startup)
-                    stage.state = (*stage).init();  // init is a property of a pointer (oh no!)
-                else
-                    stage.state = stage.cleanup();
-                debug logger.trace ("InitStage {}: completed; state: {}", stage, stage.state);
-            } catch (InitStageException e) {
-                debug logger.trace ("InitStage {}: failed", stage);
-                stage.state = e.state;
-                abortInit = true;
-                break threadLoop;
-            } catch (Exception e) {
-                debug logger.trace ("InitStage {}: failed", stage);
-                abortInit = true;
-                break threadLoop;
-            }
-            }
             } catch (Exception e) {
                 logger.fatal ("Exception in initThreadFct: "~e.msg);
-                abortInit = true;
+                doneInit = STATE.ABORT;
             }
+            doneInit |= STATE.DONE;     // allow other threads a faster exit
             toRunC.notifyAll(); // Most likely if we're exiting, we should make sure others aren't waiting.
             return;
         }
@@ -361,11 +373,12 @@
             initThreadFct();                            // try with just this thread
         }       // any other exception will be caught in main() and abort program
         
-        if (abortInit)
+        if (doneInit & STATE.ABORT)
             throw new InitException ("An init/cleanup function failed (see above message(s))");
         
-        foreach (stage; toRun)
-            logger.warn ("InitStage {}: was not run due to unmet dependencies", stage);
+        if (toRun.size)
+            foreach (stage; toRun)
+                logger.warn ("InitStage {}: was not run due to unmet dependencies", stage);
     }
     
     private static {
@@ -397,7 +410,6 @@
         stages = new typeof(stages);    // an empty test-bed
         
         bool init1, init2, init3 = true;
-        bool failed = false;    // set if anything goes wrong
         StageState s1InitReturns = StageState.ACTIVE;
         addInitStage ("stg1", delegate StageState() {
             init1 = true;
@@ -407,11 +419,11 @@
             return StageState.INACTIVE;
         });
         addInitStage ("stg2", delegate StageState() {
-            if (!init1) failed = true;
+            assert (init1);
             init2 = true;
             return StageState.ACTIVE;
         }, delegate StageState() {
-            if (!init1) failed = true;
+            assert (init1);
             init2 = false;
             return StageState.INACTIVE;
         }, ["stg1"]);
@@ -421,7 +433,7 @@
             return StageState.ERROR;
         };
         s3.cleanup = delegate StageState() {
-            if (!init1) failed = true;
+            assert (init1);
             init3 = false;
             return StageState.INACTIVE;
         };
@@ -442,7 +454,6 @@
         runStages!(true);
         assert (init1);
         assert (init2);
-        assert (!failed);
         foreach (s; stages)
             assert (s.state == StageState.ACTIVE);
         
@@ -450,7 +461,6 @@
         assert (!init1);
         assert (!init2);
         assert (!init3);
-        assert (!failed);
         foreach (s; stages)
             assert (s.state == StageState.INACTIVE);
         
@@ -460,18 +470,19 @@
         assert (init1);
         assert (!init2);
         assert (!init3);
-        assert (!failed);
         runStages!(false);
         assert (init1); // S1 cleanup won't run
         
         stages[toStageName("stg1")].state = StageState.INACTIVE;     // hack it back so we can still test
         s1InitReturns = StageState.ACTIVE;
         init1 = false;
+        bool a1 = false;
         try {
             runStages!(true);
-            assert (false);             // runStages should throw because s3.init runs now
-        } catch (Exception) {}
-        assert (init1); // s1.init should run first
+            a1 = true;
+        } catch (Exception e) {}
+        assert (!a1, "runStages didn't throw");
+        assert (init1); // s1.init should run first; s2.init may or may not get run
         assert (stages[toStageName("stg3")].state == cast(StageState)7);        // set by the exception
         
         stages = realInit;      // restore the real init stages