|
| 1 | +/** |
| 2 | + * The event module provides a primitive for lightweight signaling of other threads |
| 3 | + * (emulating Windows events on Posix) |
| 4 | + * |
| 5 | + * Copyright: Copyright (c) 2019 D Language Foundation |
| 6 | + * License: Distributed under the |
| 7 | + * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). |
| 8 | + * (See accompanying file LICENSE) |
| 9 | + */ |
| 10 | +module core.sync.event2; |
| 11 | + |
| 12 | +import core.time; |
| 13 | + |
| 14 | +struct Event2 |
| 15 | +{ |
| 16 | +nothrow @nogc: |
| 17 | + /** |
| 18 | + * Creates an event object. |
| 19 | + * |
| 20 | + * Params: |
| 21 | + * manualReset = the state of the event is not reset automatically after resuming waiting clients |
| 22 | + * initialState = initial state of the signal |
| 23 | + */ |
| 24 | + this(bool manualReset, bool initialState) |
| 25 | + { |
| 26 | + osEvent = OsEvent(manualReset, initialState); |
| 27 | + } |
| 28 | + |
| 29 | + // copying not allowed, can produce resource leaks |
| 30 | + @disable this(this); |
| 31 | + @disable void opAssign(Event); |
| 32 | + |
| 33 | + /// Set the event to "signaled", so that waiting clients are resumed |
| 34 | + void set() |
| 35 | + { |
| 36 | + osEvent.set(); |
| 37 | + } |
| 38 | + |
| 39 | + /// Reset the event manually |
| 40 | + void reset() |
| 41 | + { |
| 42 | + osEvent.reset(); |
| 43 | + } |
| 44 | + |
| 45 | + /** |
| 46 | + * Wait for the event to be signaled without timeout. |
| 47 | + * |
| 48 | + * Returns: |
| 49 | + * `true` if the event is in signaled state, `false` if the event is uninitialized or another error occured |
| 50 | + */ |
| 51 | + bool wait() |
| 52 | + { |
| 53 | + return osEvent.wait(); |
| 54 | + } |
| 55 | + |
| 56 | + /** |
| 57 | + * Wait for the event to be signaled with timeout. |
| 58 | + * |
| 59 | + * Params: |
| 60 | + * tmout = the maximum time to wait |
| 61 | + * Returns: |
| 62 | + * `true` if the event is in signaled state, `false` if the event was nonsignaled for the given time or |
| 63 | + * the event is uninitialized or another error occured |
| 64 | + */ |
| 65 | + bool wait(Duration tmout) |
| 66 | + { |
| 67 | + return osEvent.wait(tmout); |
| 68 | + } |
| 69 | + |
| 70 | +private: |
| 71 | + import rt.sys.config; |
| 72 | + |
| 73 | + mixin("import " ~ osEventImport ~ ";"); |
| 74 | + OsEvent osEvent; |
| 75 | +} |
| 76 | + |
| 77 | +// Test single-thread (non-shared) use. |
| 78 | +@nogc nothrow unittest |
| 79 | +{ |
| 80 | + // auto-reset, initial state false |
| 81 | + Event ev1 = Event2(false, false); |
| 82 | + assert(!ev1.wait(1.dur!"msecs")); |
| 83 | + ev1.set(); |
| 84 | + assert(ev1.wait()); |
| 85 | + assert(!ev1.wait(1.dur!"msecs")); |
| 86 | + |
| 87 | + // manual-reset, initial state true |
| 88 | + Event ev2 = Event(true, true); |
| 89 | + assert(ev2.wait()); |
| 90 | + assert(ev2.wait()); |
| 91 | + ev2.reset(); |
| 92 | + assert(!ev2.wait(1.dur!"msecs")); |
| 93 | +} |
| 94 | + |
| 95 | +unittest |
| 96 | +{ |
| 97 | + import core.thread, core.atomic; |
| 98 | + |
| 99 | + scope event = new Event2(true, false); |
| 100 | + int numThreads = 10; |
| 101 | + shared int numRunning = 0; |
| 102 | + |
| 103 | + void testFn() |
| 104 | + { |
| 105 | + event.wait(8.dur!"seconds"); // timeout below limit for druntime test_runner |
| 106 | + numRunning.atomicOp!"+="(1); |
| 107 | + } |
| 108 | + |
| 109 | + auto group = new ThreadGroup; |
| 110 | + |
| 111 | + for (int i = 0; i < numThreads; ++i) |
| 112 | + group.create(&testFn); |
| 113 | + |
| 114 | + auto start = MonoTime.currTime; |
| 115 | + assert(numRunning == 0); |
| 116 | + |
| 117 | + event.set(); |
| 118 | + group.joinAll(); |
| 119 | + |
| 120 | + assert(numRunning == numThreads); |
| 121 | + |
| 122 | + assert(MonoTime.currTime - start < 5.dur!"seconds"); |
| 123 | +} |
0 commit comments