D Paste by naryl
Description: Recurse Guard
Hide line numbers

Create new paste
Post a reply
View replies

Paste:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  

import tango.io.Console;
import tango.core.Thread;

/***************************************************
  Implementation
 ***************************************************/
struct RecurseGuard {
    Thread[] threads;

    static Object monitor;

    void addThread() {
        auto ct = Thread.getThis;
        synchronized(monitor) {
            foreach (thread; threads) {
                assert(thread != ct, "Recursive call!");
            }
            threads ~= ct;
        }
    }

    void removeThread() {
        auto ct = Thread.getThis;
        synchronized(monitor) {
            foreach(i, thread; threads) {
                if (thread == ct) {
                    threads[i] = threads[$-1];
                    threads = threads[0 .. $-1];
                    return;
                }
            }
        }
        assert(false, "Current thread didn't enter this function (wtf?)");
    }

    alias addThread opCall;
    alias removeThread done;
}

static this() {
    RecurseGuard.monitor = new Object;
}

class TestException : Exception {
    this() {
        super("test");
    }
}

/***************************************************
  Usage
 ***************************************************/
void testFunction(bool recurse) {
    static RecurseGuard guard;

    guard();
    scope(exit) guard.done;

    Thread.sleep(1); // Pretend to be working
    if (recurse) {
        testFunction(false);
    }
}

void testBadFunction() {
    static RecurseGuard guard;

    guard();
    scope(exit) guard.done;

    Thread.sleep(1);
    throw new TestException;
}

/***************************************************
  Tests
 ***************************************************/
void testPositive() {
    try {
        Cout("Positive test... ").flush;
        testFunction(false);
        Cout("Passed").newline;
    } catch (Exception e) {
        Cout("Failed").newline;
    }
}

void testNegative() {
    try {
        Cout("Negative test... ").flush;
        testFunction(true);
        Cout("Failed").newline;
    } catch (Exception e) {
        Cout("Passed").newline;
    }
}

void testException() {
    try {
        Cout("Positive test with exception... ").flush;
        testBadFunction;
        Cout("Failed").newline;
    } catch (TestException e) {
        Cout("Passed").newline;
    } catch (Exception e) {
        Cout("Failed").newline;
    }
}

void testThreads() {
    try {
        Cout("Positive threaded test... ").flush;
        Thread[] threads;
        for (int i = 0; i < 100; i++){
            threads ~= new Thread({testFunction(false);});
            threads[$-1].start;
        }

        foreach (thread; threads)
            thread.join;

        Cout("Passed").newline;
    } catch (Exception e) {
        Cout("Failed").newline;
    }
}

void main() {
    testPositive;
    testNegative;
    testException;
    testThreads;
}

Replies:
No replies posted yet