1 module lwdr.tracking; 2 3 import rtoslink; 4 5 version(LWDR_TrackMem) 6 { 7 struct AllocationList(T, size_t MaxElements) 8 { 9 static assert(MaxElements > 0, "MaxElements should be at least 1!"); 10 11 private T[MaxElements] payload; 12 private size_t length_ = 0; 13 14 @property bool empty() const { return length_ == 0; } 15 @property size_t length() const { return length_; } 16 17 bool add(T t) nothrow @nogc 18 { 19 if(length_ + 1 >= MaxElements) 20 return false; 21 22 payload[length_++] = t; 23 return true; 24 } 25 26 auto getLast() nothrow @nogc 27 { 28 return payload[length_ - 1]; 29 } 30 31 void removeLast() nothrow @nogc 32 { 33 if(empty) return; 34 35 payload[length_ - 1] = T.init; 36 length_--; 37 } 38 39 bool removeLastOccurenceOf(T t) nothrow @nogc 40 { 41 if(empty) return false; 42 43 size_t index; 44 bool found = false; 45 46 for(size_t i = length_ - 1; i > 0; i--) 47 { 48 if(payload[i] == t) 49 { 50 index = i; 51 found = true; 52 } 53 } 54 55 if(!found) 56 return false; 57 58 for(size_t i = index; i < length_ - 1; i++) 59 { 60 payload[i] = payload[i+1]; 61 } 62 payload[length_ - 1] = T.init; 63 length_--; 64 return true; 65 } 66 } 67 68 version(LWDR_TLS) 69 private AllocationList!(void*, 16) trackedAllocations; 70 else 71 private __gshared AllocationList!(void*, 16) trackedAllocations; 72 73 struct MemAlloc 74 { 75 size_t allocsAtScope; 76 77 void free() nothrow @nogc 78 { 79 assert(allocsAtScope >= trackedAllocations.length); 80 81 auto difference = trackedAllocations.length - allocsAtScope; 82 foreach(d; 0 .. difference) 83 { 84 auto ptr = trackedAllocations.getLast; 85 trackedAllocations.removeLast; 86 rtosbackend_heapfreealloc(ptr); 87 } 88 } 89 } 90 91 MemAlloc enterMemoryTracking() nothrow @nogc 92 { 93 return MemAlloc(trackedAllocations.length); 94 } 95 96 version(LWDR_TLS) 97 private bool currentlyTracking = false; 98 else 99 private __gshared bool currentlyTracking = false; 100 void enableMemoryTracking() nothrow @nogc { currentlyTracking = true; } 101 void disableMemoryTracking() nothrow @nogc { currentlyTracking = false; } 102 103 void* lwdrInternal_alloc(size_t sz) nothrow @nogc 104 { 105 auto ptr = rtosbackend_heapalloc(sz); 106 if(currentlyTracking) 107 { 108 trackedAllocations.add(ptr); 109 } 110 return ptr; 111 } 112 113 void lwdrInternal_free(void* ptr) nothrow @nogc 114 { 115 trackedAllocations.removeLastOccurenceOf(ptr); 116 rtosbackend_heapfreealloc(ptr); 117 } 118 119 ubyte[] lwdrInternal_allocBytes(size_t sz) nothrow @nogc 120 { 121 return cast(ubyte[])lwdrInternal_alloc(sz)[0..sz]; 122 } 123 } 124 else 125 { 126 void* lwdrInternal_alloc(size_t sz) nothrow @nogc pure 127 { 128 return rtosbackend_heapalloc(sz); 129 } 130 131 void lwdrInternal_free(void* ptr) nothrow @nogc pure 132 { 133 return rtosbackend_heapfreealloc(ptr); 134 } 135 136 ubyte[] lwdrInternal_allocBytes(size_t sz) nothrow pure @nogc 137 { 138 return cast(ubyte[])lwdrInternal_alloc(sz)[0..sz]; 139 } 140 }