Add nogc typed alloc/free functions and make assert_nogc actually nogc.

This commit is contained in:
Sönke Ludwig 2018-10-21 20:15:12 +02:00
parent d437df8809
commit 90a60f7981
2 changed files with 86 additions and 14 deletions

View file

@ -8,7 +8,7 @@ targetType "library"
libs "anl" "resolv" platform="linux" libs "anl" "resolv" platform="linux"
libs "ws2_32" "user32" platform="windows-dmd" libs "ws2_32" "user32" platform="windows-dmd"
dependency "taggedalgebraic" version="~>0.10.4" dependency "taggedalgebraic" version="~>0.10.12"
configuration "epoll" { configuration "epoll" {
platforms "linux" platforms "linux"

View file

@ -1,5 +1,7 @@
module eventcore.internal.utils; module eventcore.internal.utils;
import core.memory : GC;
import std.traits : hasIndirections;
import taggedalgebraic; import taggedalgebraic;
@ -8,17 +10,81 @@ void print(ARGS...)(string str, ARGS args)
import std.format : formattedWrite; import std.format : formattedWrite;
StdoutRange r; StdoutRange r;
scope cb = () { scope cb = () {
scope (failure) assert(false); try (&r).formattedWrite(str, args);
(&r).formattedWrite(str, args); catch (Exception e) assert(false, e.msg);
}; };
(cast(void delegate() @nogc @safe nothrow)cb)(); (cast(void delegate() @nogc @safe nothrow)cb)();
r.put('\n'); r.put('\n');
} }
T mallocT(T, ARGS...)(ARGS args)
@trusted @nogc {
import core.stdc.stdlib : malloc;
import std.conv : emplace;
enum size = __traits(classInstanceSize, T);
auto ret = cast(T)malloc(size);
static if (hasIndirections!T)
GC.addRange(cast(void*)ret, __traits(classInstanceSize, T));
scope doit = { emplace!T((cast(void*)ret)[0 .. size], args); };
static if (__traits(compiles, () nothrow { typeof(doit).init(); })) // NOTE: doing the typeof thing here, because LDC 1.7.0 otherwise thinks doit gets escaped here
(cast(void delegate() @nogc nothrow)doit)();
else
(cast(void delegate() @nogc)doit)();
return ret;
}
void freeT(T)(ref T inst) @nogc
if (is(T == class))
{
import core.stdc.stdlib : free;
noGCDestroy(inst);
static if (hasIndirections!T)
GC.removeRange(cast(void*)inst);
free(cast(void*)inst);
inst = null;
}
T[] mallocNT(T)(size_t cnt)
@trusted {
import core.stdc.stdlib : malloc;
import std.conv : emplace;
auto ret = (cast(T*)malloc(T.sizeof * cnt))[0 .. cnt];
static if (hasIndirections!T)
GC.addRange(cast(void*)ret, T.sizeof * cnt);
foreach (ref v; ret)
static if (!is(T == class))
emplace!T(&v);
else v = null;
return ret;
}
void freeNT(T)(ref T[] arr)
{
import core.stdc.stdlib : free;
foreach (ref v; arr)
static if (!is(T == class))
destroy(v);
static if (hasIndirections!T)
GC.removeRange(arr.ptr);
free(arr.ptr);
arr = null;
}
private void noGCDestroy(T)(ref T t)
@trusted {
// FIXME: only do this if the destructor chain is actually nogc
scope doit = { destroy(t); };
(cast(void delegate() @nogc)doit)();
}
private extern(C) Throwable.TraceInfo _d_traceContext(void* ptr = null); private extern(C) Throwable.TraceInfo _d_traceContext(void* ptr = null);
void nogc_assert(bool cond, string message, string file = __FILE__, int line = __LINE__) void nogc_assert(bool cond, string message, string file = __FILE__, int line = __LINE__)
@trusted nothrow { @trusted nothrow @nogc {
import core.stdc.stdlib : abort; import core.stdc.stdlib : abort;
import std.stdio : stderr; import std.stdio : stderr;
@ -28,12 +94,15 @@ void nogc_assert(bool cond, string message, string file = __FILE__, int line = _
assert(false); assert(false);
} }
stderr.writefln("Assertion failure @%s(%s): %s", file, line, message); scope doit = {
stderr.writeln("------------------------"); stderr.writefln("Assertion failure @%s(%s): %s", file, line, message);
if (auto info = _d_traceContext(null)) { stderr.writeln("------------------------");
foreach (s; info) if (auto info = _d_traceContext(null)) {
stderr.writeln(s); foreach (s; info)
} else stderr.writeln("no stack trace available"); stderr.writeln(s);
} else stderr.writeln("no stack trace available");
};
(cast(void delegate() @nogc)doit)(); // write and _d_traceContext are not nogc
} }
} }
@ -53,14 +122,11 @@ struct StdoutRange {
} }
struct ChoppedVector(T, size_t CHUNK_SIZE = 16*64*1024/nextPOT(T.sizeof)) { struct ChoppedVector(T, size_t CHUNK_SIZE = 16*64*1024/nextPOT(T.sizeof)) {
import core.memory : GC;
static assert(nextPOT(CHUNK_SIZE) == CHUNK_SIZE, static assert(nextPOT(CHUNK_SIZE) == CHUNK_SIZE,
"CHUNK_SIZE must be a power of two for performance reasons."); "CHUNK_SIZE must be a power of two for performance reasons.");
@safe: nothrow: @safe: nothrow:
import core.stdc.stdlib : calloc, free, malloc, realloc; import core.stdc.stdlib : calloc, free, malloc, realloc;
import std.traits : hasIndirections;
alias chunkSize = CHUNK_SIZE; alias chunkSize = CHUNK_SIZE;
@ -183,7 +249,7 @@ struct AlgebraicChoppedVector(TCommon, TSpecific...)
import std.format : format; import std.format : format;
string ret; string ret;
foreach (i, U; TSpecific) foreach (i, U; TSpecific)
ret ~= "@property ref TSpecific[%s] %s() nothrow @safe { return this.specific.get!(TSpecific[%s]); }\n" ret ~= "@property ref TSpecific[%s] %s() nothrow @safe @nogc { return this.specific.get!(TSpecific[%s]); }\n"
.format(i, U.Handle.name, i); .format(i, U.Handle.name, i);
return ret; return ret;
} }
@ -207,10 +273,13 @@ struct SmallIntegerSet(V : size_t)
size_t m_count; size_t m_count;
} }
@disable this(this);
@property bool empty() const { return m_count == 0; } @property bool empty() const { return m_count == 0; }
void insert(V i) void insert(V i)
{ {
assert(i >= 0);
foreach (j; 0 .. m_bits.length) { foreach (j; 0 .. m_bits.length) {
uint b = 1u << (i%32); uint b = 1u << (i%32);
i /= 32; i /= 32;
@ -223,6 +292,9 @@ struct SmallIntegerSet(V : size_t)
void remove(V i) void remove(V i)
{ {
assert(i >= 0);
if (i >= m_bits[0].length * 32) return;
foreach (j; 0 .. m_bits.length) { foreach (j; 0 .. m_bits.length) {
uint b = 1u << (i%32); uint b = 1u << (i%32);
i /= 32; i /= 32;