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 private void callExtend() 74 { 75 // Call GC.extend with dummy data. 76 // It will normally exit silently if given a null pointer, 77 // but not before the reentrance check. 78 GC.extend(null, 0, 0, null); 79 } 80 81 /// Asserts that we are not inside a GC collection cycle, 82 /// by performing a no-op GC operation. 83 /// If we are, an `InvalidMemoryOperationError` is raised by the runtime. 84 void assertNotInCollect() @nogc 85 { 86 (cast(void function() @nogc)&callExtend)(); 87 } 88 89 /// Checks if we are inside a GC collection cycle. 90 /// This is currently done in a dumb and expensive way, so use sparingly. 91 bool inCollect() @nogc 92 { 93 try 94 assertNotInCollect(); 95 catch (InvalidMemoryOperationError) 96 return true; 97 return false; 98 } 99 100 unittest 101 { 102 assert(!inCollect()); 103 104 class C 105 { 106 static bool tested; 107 108 ~this() @nogc 109 { 110 assert(inCollect()); 111 tested = true; 112 } 113 } 114 115 foreach (n; 0..128) 116 new C; 117 GC.collect(); 118 assert(C.tested); 119 }