Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions changelog/forkgc.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
A concurrent GC for Posix systems

For Posix systems that support the fork() function (or the clone() on linux systems),
the conservative/precise GC can be made concurrent by enabling the 'fork' GC options in the usual ways, e.g.
by adding `--DRT-gcopt=fork:1` to the command line or by embedding
----
extern(C) __gshared string[] rt_options = [ "gcopt=fork:1" ];
----
into your linked binary (see $(LINK $(ROOT_DIR)spec/garbage.html#gc_config)).

The application continues execution and new memory is allocated from the system while the forked
process is marking heap objects. Parallel marking is disabled for the forked process so it only
uses a single thread for minimal impact on the concurrent execution of the application.

This reduces "stop the world" time at the cost of needing more memory and page-protection overhead when
writing to memory currently being scanned.
28 changes: 28 additions & 0 deletions src/core/exception.d
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,18 @@ unittest
}


/**
* Thrown on a configuration error.
*/
class ForkError : Error
{
this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
{
super( "fork() failed", file, line, next );
}
}


/**
* Thrown on a switch error.
*/
Expand Down Expand Up @@ -716,6 +728,22 @@ extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @t
throw staticError!InvalidMemoryOperationError();
}


/**
* A callback for errors in the case of a failed fork in D. A $(LREF ForkError) will be thrown.
*
* Params:
* file = The name of the file that signaled this error.
* line = The line number on which this error occurred.
*
* Throws:
* $(LREF ConfigurationError).
*/
extern (C) void onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
{
throw staticError!ForkError( file, line, null );
}

/**
* A callback for unicode errors in D. A $(LREF UnicodeException) will be thrown.
*
Expand Down
4 changes: 3 additions & 1 deletion src/core/gc/config.d
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ __gshared Config config;
struct Config
{
bool disable; // start disabled
bool fork = false; // optional concurrent behaviour
ubyte profile; // enable profiling with summary when terminating program
string gc = "conservative"; // select gc implementation conservative|precise|manual

Expand All @@ -39,8 +40,9 @@ struct Config

printf("GC options are specified as white space separated assignments:
disable:0|1 - start disabled (%d)
fork:0|1 - set fork behaviour (%d)
profile:0|1|2 - enable profiling with summary when terminating program (%d)
gc:".ptr, disable, profile);
gc:".ptr, disable, fork, profile);
foreach (i, entry; registeredGCFactories)
{
if (i) printf("|");
Expand Down
24 changes: 20 additions & 4 deletions src/core/internal/gc/bits.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
module core.internal.gc.bits;

import core.internal.gc.os : os_mem_map, os_mem_unmap, HaveFork;

import core.bitop;
import core.stdc.string;
Expand All @@ -32,19 +33,29 @@ struct GCBits
wordtype* data;
size_t nbits;

void Dtor() nothrow
void Dtor(bool share = false) nothrow
{
if (data)
{
free(data);
static if (!HaveFork)
free(data);
else if (share)
os_mem_unmap(data, nwords * data[0].sizeof);
else
free(data);
data = null;
}
}

void alloc(size_t nbits) nothrow
void alloc(size_t nbits, bool share = false) nothrow
{
this.nbits = nbits;
data = cast(typeof(data[0])*)calloc(nwords, data[0].sizeof);
static if (!HaveFork)
data = cast(typeof(data[0])*)calloc(nwords, data[0].sizeof);
else if (share)
data = cast(typeof(data[0])*)os_mem_map(nwords * data[0].sizeof, true); // Allocate as MAP_SHARED
else
data = cast(typeof(data[0])*)calloc(nwords, data[0].sizeof);
if (!data)
onOutOfMemoryError();
}
Expand Down Expand Up @@ -431,6 +442,11 @@ struct GCBits
memset(data, 0, nwords * wordtype.sizeof);
}

void setAll() nothrow
{
memset(data, 0xFF, nwords * wordtype.sizeof);
}

void copy(GCBits *f) nothrow
in
{
Expand Down
Loading