]>
Commit | Line | Data |
---|---|---|
5fee5ec3 IB |
1 | import core.memory; |
2 | import core.sync.condition; | |
3 | import core.sync.mutex; | |
4 | import core.thread; | |
5 | ||
6 | __gshared Condition g_cond; | |
7 | __gshared Mutex g_mutex; | |
8 | __gshared int g_step = 0; | |
9 | ||
10 | class C | |
9125dc32 | 11 | { |
9125dc32 IB |
12 | ~this() |
13 | { | |
14 | import core.stdc.stdlib; | |
5fee5ec3 | 15 | abort(); // this gets triggered although the instance always stays referenced |
9125dc32 IB |
16 | } |
17 | } | |
18 | ||
5fee5ec3 | 19 | C c; |
9125dc32 IB |
20 | |
21 | static this() | |
22 | { | |
5fee5ec3 | 23 | c = new C; |
9125dc32 IB |
24 | } |
25 | ||
26 | static ~this() | |
27 | { | |
9125dc32 | 28 | import core.memory; |
5fee5ec3 | 29 | GC.free(cast(void*)c); // free without destruction to avoid triggering abort() |
9125dc32 IB |
30 | } |
31 | ||
5fee5ec3 | 32 | void test() |
9125dc32 | 33 | { |
5fee5ec3 IB |
34 | assert(c !is null); |
35 | ||
36 | // notify the main thread of the finished initialization | |
37 | synchronized (g_mutex) g_step = 1; | |
38 | g_cond.notifyAll(); | |
39 | ||
40 | // wait until the GC collection is done | |
41 | synchronized (g_mutex) { | |
42 | while (g_step != 2) | |
43 | g_cond.wait(); | |
44 | } | |
9125dc32 IB |
45 | } |
46 | ||
5fee5ec3 | 47 | |
9125dc32 IB |
48 | void main() |
49 | { | |
5fee5ec3 IB |
50 | g_mutex = new Mutex; |
51 | g_cond = new Condition(g_mutex); | |
52 | ||
53 | auto th = new Thread(&test); | |
54 | th.start(); | |
55 | ||
56 | // wait for thread to be fully initialized | |
57 | synchronized (g_mutex) { | |
58 | while (g_step != 1) | |
59 | g_cond.wait(); | |
60 | } | |
61 | ||
62 | // this causes the other thread's C instance to be reaped with the bug present | |
63 | GC.collect(); | |
64 | ||
65 | // allow the thread to shut down | |
66 | synchronized (g_mutex) g_step = 2; | |
67 | g_cond.notifyAll(); | |
9125dc32 | 68 | |
5fee5ec3 | 69 | th.join(); |
9125dc32 | 70 | } |