view tango/example/concurrency/fiber_test.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
line wrap: on
line source

import tango.core.Thread;

extern (C) int printf(char * str, ...);

void main()
{
	printf("Compile with -unittest");
}


unittest
{
    printf("Testing context creation/deletion\n");
    int s0 = 0;
    static int s1 = 0;
    
    Fiber a = new Fiber(
    delegate void()
    {
        s0++;
    });
    
    static void fb() { s1++; }
    
    Fiber b = new Fiber(&fb);
    
    Fiber c = new Fiber(
        delegate void() { assert(false); });
    
    assert(a);
    assert(b);
    assert(c);
    
    assert(s0 == 0);
    assert(s1 == 0);
    assert(a.state == Fiber.State.HOLD);
    assert(b.state == Fiber.State.HOLD);
    assert(c.state == Fiber.State.HOLD);
    
    delete c;
    
    assert(s0 == 0);
    assert(s1 == 0);
    assert(a.state == Fiber.State.HOLD);
    assert(b.state == Fiber.State.HOLD);
    
    printf("running a\n");
    a.call();
    printf("done a\n");
    
    assert(a);
    
    assert(s0 == 1);
    assert(s1 == 0);
    assert(a.state == Fiber.State.TERM);
    assert(b.state == Fiber.State.HOLD);    
    
    assert(b.state == Fiber.State.HOLD);
    
    printf("Running b\n");
    b.call();
    printf("Done b\n");
    
    assert(s0 == 1);
    assert(s1 == 1);
    assert(b.state == Fiber.State.TERM);
    
    delete a;
    delete b;
    
    printf("Context creation passed\n");
}
    
unittest
{
    printf("Testing context switching\n");
    int s0 = 0;
    int s1 = 0;
    int s2 = 0;
    
    Fiber a = new Fiber(
    delegate void()
    {
        while(true)
        {
            debug printf(" ---A---\n");
            s0++;
            Fiber.yield();
        }
    });
    
    
    Fiber b = new Fiber(
    delegate void()
    {
        while(true)
        {
            debug printf(" ---B---\n");
            s1++;
            Fiber.yield();
        }
    });
    
    
    Fiber c = new Fiber(
    delegate void()
    {
        while(true)
        {
            debug printf(" ---C---\n");
            s2++;
            Fiber.yield();
        }
    });
    
    assert(a);
    assert(b);
    assert(c);
    assert(s0 == 0);
    assert(s1 == 0);
    assert(s2 == 0);
    
    a.call();
    b.call();
    
    assert(a);
    assert(b);
    assert(c);
    assert(s0 == 1);
    assert(s1 == 1);
    assert(s2 == 0);
    
    for(int i=0; i<20; i++)
    {
        c.call();
        a.call();
    }
    
    assert(a);
    assert(b);
    assert(c);
    assert(s0 == 21);
    assert(s1 == 1);
    assert(s2 == 20);
    
    delete a;
    delete b;
    delete c;
    
    printf("Context switching passed\n");
}
    
unittest
{
    printf("Testing nested contexts\n");
    Fiber a, b, c;
    
    int t0 = 0;
    int t1 = 0;
    int t2 = 0;
    
    a = new Fiber(
    delegate void()
    {
        
        t0++;
        b.call();
        
    });
    
    b = new Fiber(
    delegate void()
    {
        assert(t0 == 1);
        assert(t1 == 0);
        assert(t2 == 0);
        
        t1++;
        c.call();
        
    });
    
    c = new Fiber(
    delegate void()
    {
        assert(t0 == 1);
        assert(t1 == 1);
        assert(t2 == 0);
        
        t2++;
    });
    
    assert(a);
    assert(b);
    assert(c);
    assert(t0 == 0);
    assert(t1 == 0);
    assert(t2 == 0);
    
    a.call();
    
    assert(t0 == 1);
    assert(t1 == 1);
    assert(t2 == 1);
    
    assert(a);
    assert(b);
    assert(c);
    
    delete a;
    delete b;
    delete c;
    
    printf("Nesting contexts passed\n");
}

unittest
{
	printf("Testing basic exceptions\n");


	int t0 = 0;
	int t1 = 0;
	int t2 = 0;

	assert(t0 == 0);
	assert(t1 == 0);
	assert(t2 == 0);

	try
	{

		try
		{
			throw new Exception("Testing\n");
			t2++;
		}
		catch(Exception fx)
		{
			t1++;
			throw fx;
		}
	
		t2++;
	}
	catch(Exception ex)
	{
		t0++;
		printf("%.*s\n", ex.toString);
	}

	assert(t0 == 1);
	assert(t1 == 1);
	assert(t2 == 0);

	printf("Basic exceptions are supported\n");
}


unittest
{
    printf("Testing exceptions\n");
    Fiber a, b, c;
    
    int t0 = 0;
    int t1 = 0;
    int t2 = 0;
    
    printf("t0 = %d\nt1 = %d\nt2 = %d\n", t0, t1, t2);
    
    a = new Fiber(
    delegate void()
    {
        t0++;
        throw new Exception("A exception\n");
        t0++;
    });
    
    b = new Fiber(
    delegate void()
    {
        t1++;
        c.call();
        t1++;
    });
    
    c = new Fiber(
    delegate void()
    {
        t2++;
        throw new Exception("C exception\n");
        t2++;
    });
    
    assert(a);
    assert(b);
    assert(c);
    assert(t0 == 0);
    assert(t1 == 0);
    assert(t2 == 0);
    
    try
    {
        a.call();
        assert(false);
    }
    catch(Exception e)
    {
        printf("%.*s\n", e.toString);
    }
    
    assert(a);
    assert(a.state == Fiber.State.TERM);
    assert(b);
    assert(c);
    assert(t0 == 1);
    assert(t1 == 0);
    assert(t2 == 0);
    
    try
    {
        b.call();
        assert(false);
    }
    catch(Exception e)
    {
        printf("%.*s\n", e.toString);
    }
    
    printf("blah2\n");
    
    assert(a);
    assert(b);
    assert(b.state == Fiber.State.TERM);
    assert(c);
    assert(c.state == Fiber.State.TERM);
    assert(t0 == 1);
    assert(t1 == 1);
    assert(t2 == 1);

	delete a;
	delete b;
	delete c;
    

	Fiber t;
	int q0 = 0;
	int q1 = 0;

	t = new Fiber(
	delegate void()
	{
		try
		{
			q0++;
			throw new Exception("T exception\n");
			q0++;
		}
		catch(Exception ex)
		{
			q1++;
			printf("!!!!!!!!GOT EXCEPTION!!!!!!!!\n");
			printf("%.*s\n", ex.toString);
		}
	});


	assert(t);
	assert(q0 == 0);
	assert(q1 == 0);
	t.call();
	assert(t);
	assert(t.state == Fiber.State.TERM);
	assert(q0 == 1);
	assert(q1 == 1);

	delete t;
   
    Fiber d, e;
    int s0 = 0;
    int s1 = 0;
    
    d = new Fiber(
    delegate void()
    {
        try
        {
            s0++;
            e.call();
            Fiber.yield();
            s0++;
            e.call();
            s0++;
        }
        catch(Exception ex)
        {
            printf("%.*s\n", ex.toString);
        }
    });
    
    e = new Fiber(
    delegate void()
    {
        s1++;
        Fiber.yield();
        throw new Exception("E exception\n");
        s1++;
    });
    
    assert(d);
    assert(e);
    assert(s0 == 0);
    assert(s1 == 0);
    
    d.call();
    
    assert(d);
    assert(e);
    assert(s0 == 1);
    assert(s1 == 1);
    
    d.call();
    
    assert(d);
    assert(e);
    assert(s0 == 2);
    assert(s1 == 1);
    
    assert(d.state == Fiber.State.TERM);
    assert(e.state == Fiber.State.TERM);
    
    delete d;
    delete e;
    
    printf("Exceptions passed\n");
}

unittest
{
    printf("Testing standard exceptions\n");
    int t = 0;
    
    Fiber a = new Fiber(
    delegate void()
    {
        throw new Exception("BLAHAHA");
    });
    
    assert(a);
    assert(t == 0);
    
    try
    {
        a.call();
        assert(false);
    }
    catch(Exception e)
    {
        printf("%.*s\n", e.toString);
    }
    
    assert(a);
    assert(a.state == Fiber.State.TERM);
    assert(t == 0);
    
    delete a;
    
    
    printf("Standard exceptions passed\n");
}

unittest
{
    printf("Memory stress test\n");
    
    const uint STRESS_SIZE = 5000;
    
    Fiber ctx[];
    ctx.length = STRESS_SIZE;
    
    int cnt0 = 0;
    int cnt1 = 0;
    
    void threadFunc()
    {
        cnt0++;
        Fiber.yield;
        cnt1++;
    }
    
    foreach(inout Fiber c; ctx)
    {
        c = new Fiber(&threadFunc, 1024);
    }
    
    assert(cnt0 == 0);
    assert(cnt1 == 0);
    
    foreach(inout Fiber c; ctx)
    {
        c.call;
    }
    
    assert(cnt0 == STRESS_SIZE);
    assert(cnt1 == 0);
    
    foreach(inout Fiber c; ctx)
    {
        c.call;
    }
    
    assert(cnt0 == STRESS_SIZE);
    assert(cnt1 == STRESS_SIZE);
    
    foreach(inout Fiber c; ctx)
    {
        delete c;
    }
    
    assert(cnt0 == STRESS_SIZE);
    assert(cnt1 == STRESS_SIZE);
    
    printf("Memory stress test passed\n");
}

unittest
{
    printf("Testing floating point\n");
    
    float f0 = 1.0;
    float f1 = 0.0;
    
    double d0 = 2.0;
    double d1 = 0.0;
    
    real r0 = 3.0;
    real r1 = 0.0;
    
    assert(f0 == 1.0);
    assert(f1 == 0.0);
    assert(d0 == 2.0);
    assert(d1 == 0.0);
    assert(r0 == 3.0);
    assert(r1 == 0.0);
    
    Fiber a, b, c;
    
    a = new Fiber(
    delegate void()
    {
        while(true)
        {
            f0 ++;
            d0 ++;
            r0 ++;
            
            Fiber.yield();
        }
    });
    
    b = new Fiber(
    delegate void()
    {
        while(true)
        {
            f1 = d0 + r0;
            d1 = f0 + r0;
            r1 = f0 + d0;
            
            Fiber.yield();
        }
    });
    
    c = new Fiber(
    delegate void()
    {
        while(true)
        {
            f0 *= d1;
            d0 *= r1;
            r0 *= f1;
            
            Fiber.yield();
        }
    });
    
    a.call();
    assert(f0 == 2.0);
    assert(f1 == 0.0);
    assert(d0 == 3.0);
    assert(d1 == 0.0);
    assert(r0 == 4.0);
    assert(r1 == 0.0);
    
    b.call();
    assert(f0 == 2.0);
    assert(f1 == 7.0);
    assert(d0 == 3.0);
    assert(d1 == 6.0);
    assert(r0 == 4.0);
    assert(r1 == 5.0);
    
    c.call();
    assert(f0 == 12.0);
    assert(f1 == 7.0);
    assert(d0 == 15.0);
    assert(d1 == 6.0);
    assert(r0 == 28.0);
    assert(r1 == 5.0);
    
    a.call();
    assert(f0 == 13.0);
    assert(f1 == 7.0);
    assert(d0 == 16.0);
    assert(d1 == 6.0);
    assert(r0 == 29.0);
    assert(r1 == 5.0);
    
    printf("Floating point passed\n");
}


version(x86) unittest
{
    printf("Testing registers\n");
    
    struct registers
    {
        int eax, ebx, ecx, edx;
        int esi, edi;
        int ebp, esp;
        
        //TODO: Add fpu stuff
    }
    
    static registers old;
    static registers next;
    static registers g_old;
    static registers g_next;
    
    //I believe that D calling convention requires that
    //EBX, ESI and EDI be saved.  In order to validate
    //this, we write to those registers and call the
    //stack thread.
    static StackThread reg_test = new StackThread(
    delegate void() 
    {
        asm
        {
            naked;
            
            pushad;
            
            mov EBX, 1;
            mov ESI, 2;
            mov EDI, 3;
            
            mov [old.ebx], EBX;
            mov [old.esi], ESI;
            mov [old.edi], EDI;
            mov [old.ebp], EBP;
            mov [old.esp], ESP;
            
            call StackThread.yield;
            
            mov [next.ebx], EBX;
            mov [next.esi], ESI;
            mov [next.edi], EDI;
            mov [next.ebp], EBP;
            mov [next.esp], ESP;
            
            popad;
        }
    });
    
    //Run the stack context
    asm
    {
        naked;
        
        pushad;
        
        mov EBX, 10;
        mov ESI, 11;
        mov EDI, 12;
        
        mov [g_old.ebx], EBX;
        mov [g_old.esi], ESI;
        mov [g_old.edi], EDI;
        mov [g_old.ebp], EBP;
        mov [g_old.esp], ESP;
        
        mov EAX, [reg_test];
        call StackThread.call;
        
        mov [g_next.ebx], EBX;
        mov [g_next.esi], ESI;
        mov [g_next.edi], EDI;
        mov [g_next.ebp], EBP;
        mov [g_next.esp], ESP;
        
        popad;
    }
    
    
    //Make sure the registers are byte for byte equal.
    assert(old.ebx = 1);
    assert(old.esi = 2);
    assert(old.edi = 3);
    assert(old == next);
    
    assert(g_old.ebx = 10);
    assert(g_old.esi = 11);
    assert(g_old.edi = 12);
    assert(g_old == g_next);
    
    printf("Registers passed!\n");
}


unittest
{
    printf("Testing throwYield\n");
    
    int q0 = 0;
    
    Fiber st0 = new Fiber(
    delegate void()
    {
        q0++;
        Fiber.yieldAndThrow(new Exception("testing throw yield\n"));
        q0++;
    });
    
    try
    {
        st0.call();
        assert(false);
    }
    catch(Exception e)
    {
        printf("%.*s\n", e.toString);
    }
    
    assert(q0 == 1);
    assert(st0.state == Fiber.State.HOLD);
    
    st0.call();
    assert(q0 == 2);
    assert(st0.state == Fiber.State.TERM);
    
    printf("throwYield passed!\n");
}

unittest
{
    printf("Testing thread safety\n");
    
    int x = 0, y = 0;
    
    Fiber sc0 = new Fiber(
    {
        while(true)
        {
            x++;
            Fiber.yield;
        }
    });
    
    Fiber sc1 = new Fiber(
    {
        while(true)
        {
            y++;
            Fiber.yield;
        }
    });
    
    Thread t0 = new Thread(
    {
        for(int i=0; i<10000; i++)
            sc0.call();
    });
    
    Thread t1 = new Thread(
    {
        for(int i=0; i<10000; i++)
            sc1.call();
    });
    
    assert(sc0);
    assert(sc1);
    assert(t0);
    assert(t1);
    
    t0.start;
    t1.start;
    t0.join;
    t1.join;
    
    assert(x == 10000);
    assert(y == 10000);
    
    printf("Thread safety passed!\n");
}