1 /**
2  * Memory and GC stuff.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.sys.memory;
15 
16 import core.exception;
17 import core.memory;
18 import core.thread;
19 
20 /// Did the GC run since this function's last call on this thread?
21 /// Not 100% reliable (due to false pointers).
22 bool gcRan()
23 {
24 	static bool initialized = false;
25 	static bool destroyed = false;
26 
27 	static class Beacon
28 	{
29 		~this() @nogc
30 		{
31 			destroyed = true;
32 		}
33 	}
34 
35 	if (!initialized)
36 	{
37 		destroyed = false;
38 		new Beacon();
39 		initialized = true;
40 	}
41 
42 	bool result = destroyed;
43 	if (destroyed)
44 	{
45 		destroyed = false;
46 		new Beacon();
47 	}
48 
49 	return result;
50 }
51 
52 /// Is the given pointer located on the stack of the current thread?
53 /// Useful to assert on before taking the address of e.g. a struct member.
54 bool onStack(const(void)* p)
55 {
56 	auto p0 = thread_stackTop();
57 	auto p1 = thread_stackBottom();
58 	return p0 <= p && p <= p1;
59 }
60 
61 unittest
62 {
63 	/* .......... */ int l; auto pl = &l;
64 	static /* ... */ int s; auto ps = &s;
65 	static __gshared int g; auto pg = &g;
66 	/* ................. */ auto ph = new int;
67 	assert( pl.onStack());
68 	assert(!ps.onStack());
69 	assert(!pg.onStack());
70 	assert(!ph.onStack());
71 }
72 
73 /// Checks if we are inside a GC collection cycle.
74 /// This is currently done in a dumb and expensive way, so use sparingly.
75 bool inCollect() @nogc
76 {
77 	// Call GC.extend with dummy data.
78 	// It will normally exit silently if given a null pointer,
79 	// but not before the reentrance check.
80 	try
81 		(cast(void function(void*, size_t, size_t, const TypeInfo) @nogc)&GC.extend)(null, 0, 0, null);
82 	catch (InvalidMemoryOperationError)
83 		return true;
84 	return false;
85 }
86 
87 unittest
88 {
89 	assert(!inCollect());
90 
91 	class C
92 	{
93 		static bool tested;
94 
95 		~this() @nogc
96 		{
97 			assert(inCollect());
98 			tested = true;
99 		}
100 	}
101 
102 	foreach (n; 0..128)
103 		new C;
104 	GC.collect();
105 	assert(C.tested);
106 }