D Paste by naryl
Description: Recurse Guard
|
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; } |