Show
Ignore:
Timestamp:
10/24/06 01:24:13 (2 years ago)
Author:
KirkMcDonald
Message:

Meta-programming library replaced; large re-write. StackThreads? updated to 0.3.2. Iteration updates.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/infrastructure/st/stackcontext.d

    r37 r40  
    1919 * implementations. 
    2020 * 
    21  * Version: 0.10 
    22  * Date: June 30, 2006 
     21 * Version: 0.12 
     22 * Date: October 17, 2006 
    2323 * Authors: Mikola Lysenko, mclysenk@mtu.edu 
    2424 * License: Use/copy/modify freely, just give credit. 
     
    3131 *  since overflows are now trapped. 
    3232 * 
    33  *  Implementation is not thread safe. 
    34  * 
    3533 *  DMD has a bug on linux with multiple delegates in a 
    3634 *  scope.  Be aware that the linux version may have 
     
    4846 *  removeRange I have set it as optional. 
    4947 * 
     48 *  GDC version does not support assembler optimizations, since 
     49 *  it uses a different calling convention.  
     50 * 
    5051 * History: 
     52 *  v0.12 - Workaround for DMD bug. 
     53 * 
     54 *  v0.11 - Implementation is now thread safe. 
     55 * 
    5156 *  v0.10 - Added the LEAK_FIX flag to work around the 
    5257 *          slowness of std.gc.removeRange 
     
    8186    std.stdio, 
    8287    std.string, 
    83     std.gc; 
     88    std.gc, 
     89    st.tls; 
     90 
     91//Handle versions 
     92version(D_InlineAsm_X86) 
     93
     94    version(DigitalMars) 
     95    { 
     96        version(Win32) version = SC_WIN_ASM; 
     97        version(linux) version = SC_LIN_ASM; 
     98    } 
     99     
     100    //GDC uses a different calling conventions, need to reverse engineer them later 
     101
     102 
    84103 
    85104/// The default size of a StackContext's stack 
     
    136155    } 
    137156} 
     157 
     158 
    138159 
    139160 
     
    255276 *  
    256277 ******************************************************/ 
    257 public class StackContext 
     278public final class StackContext 
    258279{ 
    259280    /** 
     
    335356    { 
    336357        assert(state != CONTEXT_STATE.RUNNING); 
    337         assert(current_context !is this); 
     358        assert(current_context.val !is this); 
    338359    } 
    339360    body 
     
    357378     *  bubbled up through this method. 
    358379     */ 
    359     public void run() 
     380    public final void run() 
    360381    { 
    361382        debug (StackContext) writefln("Running %s", this.toString); 
    362383         
    363384        //We must be ready to run 
    364         if(state != CONTEXT_STATE.READY) 
    365         { 
    366             throw new ContextException(this,  
    367                 "Context is not in a runnable state"); 
    368         } 
     385        assert(state == CONTEXT_STATE.READY,  
     386            "Context is not in a runnable state"); 
    369387         
    370388        //Save the old context 
    371         StackContext tmp = current_context
     389        StackContext tmp = current_context.val
    372390         
    373391        version(LEAK_FIX) 
     
    379397         
    380398        //Set new context 
    381         current_context = this; 
     399        current_context.val = this; 
    382400        ctx.switchIn(); 
    383         current_context = tmp; 
     401        current_context.val = tmp; 
    384402         
    385403        assert(state != CONTEXT_STATE.RUNNING); 
     
    428446     *  running context. 
    429447     */ 
    430     public static void yield() 
    431     { 
    432         if(current_context is null) 
    433         { 
    434             throw new ContextException( 
    435                 null, 
    436                 "Tried to yield without any running contexts."); 
    437         } 
    438          
    439         debug (StackContext) writefln("Yielding %s", current_context.toString); 
    440          
    441         assert(current_context.running); 
     448    public final static void yield() 
     449    { 
     450        StackContext cur_ctx = current_context.val; 
     451         
     452        //Make sure we are actually running 
     453        assert(cur_ctx !is null, 
     454            "Tried to yield without any running contexts."); 
     455         
     456        debug (StackContext) writefln("Yielding %s", cur_ctx.toString); 
     457         
     458        assert(cur_ctx.running); 
    442459         
    443460        //Leave the current context 
    444         current_context.state = CONTEXT_STATE.READY; 
    445         StackContext tmp = current_context
     461        cur_ctx.state = CONTEXT_STATE.READY; 
     462        StackContext tmp = cur_ctx
    446463         
    447464        version(LEAK_FIX) 
    448465        { 
    449466            //Save the GC range 
    450             current_context.gc_start = cast(void*)&tmp; 
     467            cur_ctx.gc_start = cast(void*)&tmp; 
    451468            debug (LogGC) writefln("Adding range: %8x-%8x", 
    452                 current_context.gc_start, current_context.ctx.stack_top); 
    453             addRange(current_context.gc_start, current_context.ctx.stack_top); 
     469                cur_ctx.gc_start, cur_ctx.ctx.stack_top); 
     470            addRange(cur_ctx.gc_start, cur_ctx.ctx.stack_top); 
    454471        } 
    455472         
    456473        //Swap 
    457         current_context.ctx.switchOut(); 
     474        cur_ctx.ctx.switchOut(); 
    458475         
    459476        version(LEAK_FIX) 
    460477        { 
     478            StackContext t_ctx = current_context.val; 
     479             
    461480            //Remove the GC range 
    462481            debug (LogGC) writefln("Removing range: %8x", 
    463                 current_context.gc_start); 
    464             assert(current_context.gc_start !is null); 
    465             removeRange(current_context.gc_start); 
    466             current_context.gc_start = null; 
     482                t_ctx.gc_start); 
     483            assert(t_ctx.gc_start !is null); 
     484            removeRange(t_ctx.gc_start); 
     485            t_ctx.gc_start = null; 
    467486        } 
    468487         
    469488        //Return 
    470         current_context = tmp; 
    471         current_context.state = CONTEXT_STATE.RUNNING; 
    472          
    473         debug (StackContext) writefln("Resuming context: %s", current_context.toString); 
     489        current_context.val = tmp; 
     490        tmp.state = CONTEXT_STATE.RUNNING; 
     491         
     492        debug (StackContext) writefln("Resuming context: %s", tmp.toString); 
    474493    } 
    475494     
     
    484503     *  t = The exception object we will propagate. 
    485504     */ 
    486     public static void throwYield(Object t) 
    487     { 
    488         last_exception = t; 
     505    public final static void throwYield(Object t) 
     506    { 
     507        current_context.val.last_exception = t; 
    489508        yield(); 
    490509    } 
     
    496515     *  A ContextException if the context is running. 
    497516     */ 
    498     public void restart() 
     517    public final void restart() 
    499518    { 
    500519        debug (StackContext) writefln("Restarting %s", this.toString); 
    501520         
    502         if(state == CONTEXT_STATE.RUNNING) 
    503         { 
    504             throw new ContextException(this,  
    505                 "Cannot reset this context while it is running!"); 
    506         } 
     521        assert(state != CONTEXT_STATE.RUNNING, 
     522            "Cannot restart a context while it is running"); 
    507523         
    508524        //Reset the context 
     525        restartStack(); 
     526    } 
     527     
     528    /** 
     529     * Recycles the context by restarting it with a new delegate. This 
     530     * can save resources by allowing a program to reuse previously 
     531     * allocated contexts. 
     532     * 
     533     * Params: 
     534     *  dg = The delegate which we will be running. 
     535     */ 
     536    public final void recycle(void delegate() dg) 
     537    { 
     538        debug (StackContext) writefln("Recycling %s", this.toString); 
     539         
     540        assert(state != CONTEXT_STATE.RUNNING, 
     541            "Cannot recycle a context while it is running"); 
     542         
     543        //Set the delegate and restart 
     544        proc = dg; 
    509545        restartStack(); 
    510546    } 
     
    519555     *  A ContextException if the context is not READY. 
    520556     */ 
    521     public void kill() 
    522     { 
    523         if(state == CONTEXT_STATE.RUNNING) 
    524         { 
    525             throw new ContextException(this, "Cannot kill a context if it is not ready"); 
    526         } 
    527         else if(state == CONTEXT_STATE.DEAD) 
    528         { 
    529             return; 
    530         } 
     557    public final void kill() 
     558    { 
     559        assert(state != CONTEXT_STATE.RUNNING, 
     560            "Cannot kill a context while it is running."); 
     561         
    531562         
    532563        version(LEAK_FIX) 
    533564        { 
     565            if(state == CONTEXT_STATE.DEAD) 
     566            { 
     567                return; 
     568            } 
     569             
    534570            //Clear the GC ranges if necessary 
    535571            if(gc_start !is null) 
     
    550586     * Returns: A string describing the context. 
    551587     */ 
    552     public char[] toString() 
     588    public final char[] toString() 
    553589    { 
    554590        static char[][] state_names =  
     
    622658    public static StackContext getRunning() 
    623659    { 
    624         return current_context
     660        return current_context.val
    625661    } 
    626662     
     
    633669                //Make sure context is running 
    634670                //assert(ctx.old_stack_pointer !is null); 
    635                 assert(current_context !is null); 
     671                assert(current_context.val !is null); 
    636672             
    637673            case CONTEXT_STATE.READY: 
     
    655691        } 
    656692    } 
    657      
    658      
     693         
    659694    version(LEAK_FIX) 
    660695    { 
     
    669704    private CONTEXT_STATE state; 
    670705     
    671 //FIXME: All static objects should be in thread local  
    672 //storage.  Not sure how to do this effectively yet. 
    673  
    674 /*BEGIN TLS {*/ 
    675      
    676706    // The last exception generated 
    677707    private static Object last_exception = null; 
    678  
     708     
     709/*BEGIN TLS {*/ 
     710         
    679711    // The currently running stack context 
    680     private static StackContext current_context = null; 
    681  
     712    private static ThreadLocal!(StackContext) current_context = null; 
     713     
    682714/*} END TLS*/ 
    683715     
     
    767799    in 
    768800    { 
    769         assert(current_context !is null); 
     801        assert(current_context.val !is null); 
    770802        version(LEAK_FIX) 
    771             assert(current_context.gc_start is null); 
     803            assert(current_context.val.gc_start is null); 
    772804    } 
    773805    body 
    774806    { 
     807        StackContext cur_ctx = current_context.val; 
     808         
    775809        try 
    776810        { 
    777811            //Set state to running, enter the context 
    778             current_context.state = CONTEXT_STATE.RUNNING; 
    779             debug (StackContext) writefln("Starting %s", current_context.toString); 
    780             current_context.proc(); 
    781             debug (StackContext) writefln("Finished %s", current_context.toString); 
     812            cur_ctx.state = CONTEXT_STATE.RUNNING; 
     813            debug (StackContext) writefln("Starting %s", cur_ctx.toString); 
     814            cur_ctx.proc(); 
     815            debug (StackContext) writefln("Finished %s", cur_ctx.toString); 
    782816        } 
    783817        catch(Object o) 
    784818        { 
    785819            //Save exceptions so we can throw them later 
    786             debug (StackContext) writefln("Got an exception: %s, in %s", o.toString, current_context.toString); 
    787             last_exception = o; 
     820            debug (StackContext) writefln("Got an exception: %s, in %s", o.toString, cur_ctx.toString); 
     821            cur_ctx.last_exception = o; 
    788822        } 
    789823        finally 
     
    791825            //Leave the object.  Don't need to worry about 
    792826            //GC, since it should already be released. 
    793             current_context.state = CONTEXT_STATE.DEAD; 
    794             debug (StackContext) writefln("Leaving %s", current_context.toString); 
    795             current_context.ctx.switchOut(); 
     827            cur_ctx.state = CONTEXT_STATE.DEAD; 
     828            debug (StackContext) writefln("Leaving %s", cur_ctx.toString); 
     829            cur_ctx.ctx.switchOut(); 
    796830        } 
    797831         
     
    807841        version(Win32) 
    808842        { 
    809             if(current_context is null) 
     843            StackContext cur = current_context.val; 
     844             
     845            if(cur is null) 
    810846                return os_query_stackBottom(); 
    811847             
    812             return current_context.ctx.stack_top; 
     848            return cur.ctx.stack_top; 
    813849        } 
    814850        else 
     
    819855    } 
    820856} 
     857 
     858static this() 
     859{ 
     860    StackContext.current_context = new ThreadLocal!(StackContext); 
     861 
     862    version(SC_WIN_ASM) 
     863    { 
     864        //Get the system's page size 
     865        SYSTEM_INFO sys_info; 
     866        GetSystemInfo(&sys_info); 
     867        page_size = sys_info.dwPageSize; 
     868    } 
     869} 
     870 
    821871 
    822872/******************************************************** 
     
    828878 ********************************************************/ 
    829879 
    830 private version (Win32
     880private version (SC_WIN_ASM
    831881{ 
    832882 
     
    904954size_t page_size; 
    905955 
    906 static this() 
    907 { 
    908     //Get the system's page size 
    909     SYSTEM_INFO sys_info; 
    910     GetSystemInfo(&sys_info); 
    911     page_size = sys_info.dwPageSize; 
    912 } 
    913956 
    914957private struct SysContext 
     
    10351078    void killStack() 
    10361079    { 
     1080        //Work around for bug in DMD 0.170 
     1081        if(stack_bottom is null) 
     1082        { 
     1083            debug(StackContext) 
     1084                writefln("WARNING!!!! Accidentally deleted a context twice"); 
     1085            return; 
     1086        } 
     1087         
    10371088        debug (LogStack) 
    10381089        { 
     
    11411192} 
    11421193} 
    1143 else private version(linux
     1194else private version(SC_LIN_ASM
    11441195{ 
    11451196 
     
    12251276        //Initialize stack pointer 
    12261277        stack_pointer = stack_top; 
    1227  
    1228          //Initialize stack state 
    1229         void push(uint val) 
    1230         { 
    1231             stack_pointer -= 4; 
    1232             *cast(uint*)stack_pointer = val; 
    1233         } 
    1234          
    1235         push(cast(uint)&StackContext.startContext); //Start point 
    1236         push(0);        //EBP 
    1237         push(0);        //EBX 
    1238         push(0);        //ESI 
    1239         push(0);        //EDI 
     1278         
     1279        //Initialize stack state 
     1280        *cast(uint*)(stack_pointer-4) = cast(uint)&StackContext.startContext; 
     1281        stack_pointer -= 20; 
    12401282    } 
    12411283     
     
    12451287    void killStack() 
    12461288    { 
     1289        //Make sure the GC didn't accidentally double collect us... 
     1290        if(stack_bottom is null) 
     1291        { 
     1292            debug(StackContext) writefln("WARNING!!! Accidentally killed stack twice"); 
     1293            return; 
     1294        } 
     1295         
    12471296        //Deallocate the stack 
    12481297        if(munmap(stack_bottom, (stack_top - stack_bottom))) 
     
    13431392else 
    13441393{ 
    1345     //Unsupported system 
    1346     static assert(false, "Stack Context: System Unsupported"); 
     1394    static assert(false, "System currently unsupported"); 
    13471395} 
    13481396 
     
    13931441    assert(s1 == 0); 
    13941442    assert(a.getState == CONTEXT_STATE.DEAD); 
    1395     assert(b.getState == CONTEXT_STATE.READY); 
    1396      
    1397     try 
    1398     { 
    1399         a.run(); 
    1400         assert(false); 
    1401     } 
    1402     catch(ContextException ce) 
    1403     { 
    1404         debug writefln("Generated exception correctly"); 
    1405     } 
    1406      
     1443    assert(b.getState == CONTEXT_STATE.READY);     
    14071444     
    14081445    assert(b.getState == CONTEXT_STATE.READY); 
     
    16811718    } 
    16821719     
     1720    writefln("blah2"); 
     1721     
    16831722    assert(a); 
    16841723    assert(b); 
     
    19001939    delete a; 
    19011940     
    1902     StackContext b; 
    1903      
    1904     b = new StackContext( 
    1905     delegate void() 
    1906     { 
    1907         b.restart(); 
    1908         assert(false); 
    1909     }); 
    1910      
    1911     try 
    1912     { 
    1913         b.run(); 
    1914         assert(false); 
    1915     } 
    1916     catch(ContextException e) 
    1917     { 
    1918         e.print; 
    1919     } 
    1920      
    1921     try 
    1922     { 
    1923         StackContext.yield(); 
    1924         assert(false); 
    1925     } 
    1926     catch(ContextException e) 
    1927     { 
    1928         e.print; 
    1929     } 
    19301941     
    19311942    writefln("Standard exceptions passed"); 
     
    22152226} 
    22162227 
     2228unittest 
     2229{ 
     2230    writefln("Testing thread safety"); 
     2231     
     2232    int x = 0, y = 0; 
     2233     
     2234    StackContext sc0 = new StackContext( 
     2235    { 
     2236        while(true) 
     2237        { 
     2238            x++; 
     2239            StackContext.yield; 
     2240        } 
     2241    }); 
     2242     
     2243    StackContext sc1 = new StackContext( 
     2244    { 
     2245        while(true) 
     2246        { 
     2247            y++; 
     2248            StackContext.yield; 
     2249        } 
     2250    }); 
     2251     
     2252    Thread t0 = new Thread( 
     2253    { 
     2254        for(int i=0; i<10000; i++) 
     2255            sc0.run(); 
     2256         
     2257        return 0; 
     2258    }); 
     2259     
     2260    Thread t1 = new Thread( 
     2261    { 
     2262        for(int i=0; i<10000; i++) 
     2263            sc1.run(); 
     2264         
     2265        return 0; 
     2266    }); 
     2267     
     2268    assert(sc0); 
     2269    assert(sc1); 
     2270    assert(t0); 
     2271    assert(t1); 
     2272     
     2273    t0.start; 
     2274    t1.start; 
     2275    t0.wait; 
     2276    t1.wait; 
     2277     
     2278    assert(x == 10000); 
     2279    assert(y == 10000); 
     2280     
     2281    writefln("Thread safety passed!"); 
     2282} 
     2283 
  • trunk/infrastructure/st/stackthread.d

    r37 r40  
    2121 * 
    2222 * Bugs: 
    23  *  None known yet. 
     23 *  Not thread safe.  May be changed in future versions, 
     24 *  however this will require a radical refactoring. 
    2425 * 
    2526 * History: