Showing with 238 additions and 84 deletions.
  1. +1 −0 mak/COPY
  2. +1 −0 mak/SRCS
  3. +16 −2 src/core/exception.d
  4. +103 −0 src/core/internal/spinlock.d
  5. +2 −0 src/core/memory.d
  6. +5 −0 src/core/runtime.d
  7. +3 −3 src/core/thread.d
  8. +79 −79 src/gc/gc.d
  9. +11 −0 src/gc/proxy.d
  10. +11 −0 src/gcstub/gc.d
  11. +3 −0 win32.mak
  12. +3 −0 win64.mak
1 change: 1 addition & 0 deletions mak/COPY
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ COPY=\
$(IMPDIR)\core\internal\abort.d \
$(IMPDIR)\core\internal\convert.d \
$(IMPDIR)\core\internal\hash.d \
$(IMPDIR)\core\internal\spinlock.d \
$(IMPDIR)\core\internal\string.d \
$(IMPDIR)\core\internal\traits.d \
\
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ SRCS=\
src\core\internal\abort.d \
src\core\internal\convert.d \
src\core\internal\hash.d \
src\core\internal\spinlock.d \
src\core\internal\string.d \
src\core\internal\traits.d \
\
Expand Down
18 changes: 16 additions & 2 deletions src/core/exception.d
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,13 @@ class OutOfMemoryError : Error

override string toString() const @trusted
{
return msg.length ? (cast()super).toString() : "Memory allocation failed";
return msg.length ? (cast()this).superToString() : "Memory allocation failed";
}

// kludge to call non-const super.toString
private string superToString() @trusted
{
return super.toString();
}
}

Expand All @@ -239,6 +245,7 @@ unittest
assert(oome.line == __LINE__ - 2);
assert(oome.next is null);
assert(oome.msg == "Memory allocation failed");
assert(oome.toString.length);
}

{
Expand Down Expand Up @@ -269,7 +276,13 @@ class InvalidMemoryOperationError : Error

override string toString() const @trusted
{
return msg.length ? (cast()super).toString() : "Invalid memory operation";
return msg.length ? (cast()this).superToString() : "Invalid memory operation";
}

// kludge to call non-const super.toString
private string superToString() @trusted
{
return super.toString();
}
}

Expand All @@ -281,6 +294,7 @@ unittest
assert(oome.line == __LINE__ - 2);
assert(oome.next is null);
assert(oome.msg == "Invalid memory operation");
assert(oome.toString.length);
}

{
Expand Down
103 changes: 103 additions & 0 deletions src/core/internal/spinlock.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* SpinLock for runtime internal usage.
*
* Copyright: Copyright Digital Mars 2015 -.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Martin Nowak
* Source: $(DRUNTIMESRC core/internal/_spinlock.d)
*/
module core.internal.spinlock;

import core.atomic, core.thread;

shared struct SpinLock
{
/// for how long is the lock usually contended
enum Contention : ubyte
{
brief,
medium,
lengthy,
}

@trusted @nogc nothrow:
this(Contention contention)
{
this.contention = contention;
}

void lock()
{
if (cas(&val, size_t(0), size_t(1)))
return;
// Try to reduce the chance of another cas failure
// TTAS lock (https://en.wikipedia.org/wiki/Test_and_test-and-set)
immutable step = 1 << contention;
while (true)
{
for (size_t n; atomicLoad!(MemoryOrder.raw)(val); n += step)
yield(n);
if (cas(&val, size_t(0), size_t(1)))
return;
}
}

void unlock()
{
atomicStore!(MemoryOrder.rel)(val, size_t(0));
}

/// yield with backoff
void yield(size_t k)
{
if (k < pauseThresh)
return pause();
else if (k < 32)
return Thread.yield();
Thread.sleep(1.msecs);
}

private:
version (D_InlineAsm_X86)
enum X86 = true;
else version (D_InlineAsm_X86_64)
enum X86 = true;
else
enum X86 = false;

static if (X86)
{
enum pauseThresh = 16;
void pause()
{
asm @trusted @nogc nothrow
{
// pause instruction
rep;
nop;
}
}
}
else
{
enum pauseThresh = 4;
void pause()
{
}
}

size_t val;
Contention contention;
}

// aligned to cacheline to avoid false sharing
shared align(64) struct AlignedSpinLock
{
this(SpinLock.Contention contention)
{
impl = shared(SpinLock)(contention);
}

SpinLock impl;
alias impl this;
}
2 changes: 2 additions & 0 deletions src/core/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ private
extern (C) void gc_removeRoot( in void* p ) nothrow;
extern (C) void gc_removeRange( in void* p ) nothrow @nogc;
extern (C) void gc_runFinalizers( in void[] segment );

package extern (C) bool gc_inFinalizer();
}


Expand Down
5 changes: 5 additions & 0 deletions src/core/runtime.d
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,11 @@ Throwable.TraceInfo defaultTraceHandler( void* ptr = null )
else version( Solaris )
import core.sys.solaris.execinfo;

// avoid recursive GC calls in finalizer, trace handlers should be made @nogc instead
import core.memory : gc_inFinalizer;
if (gc_inFinalizer)
return null;

//printf("runtime.defaultTraceHandler()\n");
static if( __traits( compiles, backtrace ) )
{
Expand Down
6 changes: 3 additions & 3 deletions src/core/thread.d
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ class Thread
*
* ------------------------------------------------------------------------
*/
static void sleep( Duration val ) nothrow
static void sleep( Duration val ) @nogc nothrow
in
{
assert( !val.isNegative );
Expand Down Expand Up @@ -1134,7 +1134,7 @@ class Thread
if( !nanosleep( &tin, &tout ) )
return;
if( errno != EINTR )
throw new ThreadError( "Unable to sleep for the specified duration" );
assert(0, "Unable to sleep for the specified duration");
tin = tout;
}
}
Expand All @@ -1144,7 +1144,7 @@ class Thread
/**
* Forces a context switch to occur away from the calling thread.
*/
static void yield() nothrow
static void yield() @nogc nothrow
{
version( Windows )
SwitchToThread();
Expand Down
Loading