Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #986 from rainers/gc_config_cleanup
Browse files Browse the repository at this point in the history
Allow link-time and run-time GC configuration
  • Loading branch information
MartinNowak committed Nov 22, 2014
2 parents 6648dac + 6e1d47c commit 4e8bb2c
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 45 deletions.
1 change: 1 addition & 0 deletions mak/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ MANIFEST=\
src\rt\bss_section.c \
src\rt\cast_.d \
src\rt\cmath2.d \
src\rt\config.d \
src\rt\cover.d \
src\rt\critical_.d \
src\rt\deh.d \
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ SRCS=\
src\rt\arrayshort.d \
src\rt\cast_.d \
src\rt\cmath2.d \
src\rt\config.d \
src\rt\cover.d \
src\rt\critical_.d \
src\rt\deh.d \
Expand Down
29 changes: 29 additions & 0 deletions src/core/demangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,35 @@ unittest
static assert(!__traits(compiles, mangleFunc!(typeof(&fooCPP))("")));
}

/**
* Mangles a C function or variable.
*
* Params:
* dst = An optional destination buffer.
*
* Returns:
* The mangled name for a C function or variable, i.e.
* an underscore is prepended or not, depending on the
* compiler/linker tool chain
*/
char[] mangleC(const(char)[] sym, char[] dst = null)
{
version(Win32)
enum string prefix = "_";
else version(OSX)
enum string prefix = "_";
else
enum string prefix = "";

auto len = sym.length + prefix.length;
if( dst.length < len )
dst.length = len;

dst[0 .. prefix.length] = prefix[];
dst[prefix.length .. len] = sym[];
return dst[0 .. len];
}


version(unittest)
{
Expand Down
84 changes: 39 additions & 45 deletions src/gc/config.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,6 @@

module gc.config;

// to add the possiblity to configure the GC from the outside, add gc.config
// with one of these versions to the executable build command line, e.g.
// dmd -version=initGCFromEnvironment main.c /path/to/druntime/src/gc/config.d

//version = initGCFromEnvironment; // read settings from environment variable D_GC
version = initGCFromCommandLine; // read settings from command line argument "--DRT-gcopt=options"

version(initGCFromEnvironment)
version = configurable;
version(initGCFromCommandLine)
version = configurable;

import core.stdc.stdlib;
import core.stdc.stdio;
import core.stdc.ctype;
Expand All @@ -27,6 +15,10 @@ import core.vararg;

extern extern(C) string[] rt_args();

extern extern(C) __gshared bool rt_envvars_enabled;
extern extern(C) __gshared bool rt_cmdline_enabled;
extern extern(C) __gshared string[] rt_options;

struct Config
{
bool disable; // start disabled
Expand All @@ -36,48 +28,46 @@ struct Config

size_t initReserve; // initial reserve (MB)
size_t minPoolSize = 1; // initial and minimum pool size (MB)
size_t maxPoolSize = 32; // maximum pool size (MB)
size_t maxPoolSize = 64; // maximum pool size (MB)
size_t incPoolSize = 3; // pool size increment (MB)

bool initialize(...) // avoid inlining
bool initialize() @nogc
{
version(initGCFromEnvironment)
{
auto p = getenv("D_GC");
if (p)
if (!parseOptions(p[0 .. strlen(p)]))
return false;
}
version(initGCFromCommandLine)
import core.internal.traits : externDFunc;

alias rt_configCallBack = string delegate(string) @nogc nothrow;
alias fn_configOption = string function(string opt, scope rt_configCallBack dg, bool reverse) @nogc nothrow;

alias rt_configOption = externDFunc!("rt.config.rt_configOption", fn_configOption);

string parse(string opt) @nogc nothrow
{
foreach (a; rt_args)
{
if(a.length >= 12 && a[0..12] == "--DRT-gcopt=")
if (!parseOptions(a[12 .. $]))
return false;
}
if (!parseOptions(opt))
return "err";
return null; // continue processing
}
return true;
string s = rt_configOption("gcopt", &parse, true);
return s is null;
}

version (configurable):

string help() @nogc
void help() @nogc nothrow
{
return "GC options are specified as white space separated assignments:
disable=0|1 - start disabled
profile=0|1 - enable profiling with summary when terminating program
precise=0|1 - enable precise scanning (not implemented yet)
concurrent=0|1 - enable concurrent collection (not implemented yet)
string s = "GC options are specified as white space separated assignments:
disable:0|1 - start disabled (%d)
profile:0|1 - enable profiling with summary when terminating program (%d)
precise:0|1 - enable precise scanning (not implemented yet)
concurrent:0|1 - enable concurrent collection (not implemented yet)
initReserve=N - initial memory to reserve (MB), default 0
minPoolSize=N - initial and minimum pool size (MB), default 1
maxPoolSize=N - maximum pool size (MB), default 32
incPoolSize=N - pool size increment (MB), defaut 3
initReserve:N - initial memory to reserve in MB (%lld)
minPoolSize:N - initial and minimum pool size in MB (%lld)
maxPoolSize:N - maximum pool size in MB (%lld)
incPoolSize:N - pool size increment MB (%lld)
";
printf(s.ptr, disable, profile, cast(long)initReserve,
cast(long)minPoolSize, cast(long)maxPoolSize, cast(long)incPoolSize);
}

bool parseOptions(const(char)[] opt) @nogc
bool parseOptions(const(char)[] opt) @nogc nothrow
{
size_t p = 0;
while(p < opt.length)
Expand All @@ -87,13 +77,13 @@ struct Config
if (p >= opt.length)
break;
auto q = p;
while (q < opt.length && opt[q] != '=' && !isspace(opt[q]))
while (q < opt.length && opt[q] != ':' && opt[q] != '=' && !isspace(opt[q]))
q++;

auto s = opt[p .. q];
if(s == "help")
{
printf("%s", help().ptr);
help();
p = q;
}
else if (q < opt.length)
Expand All @@ -102,7 +92,11 @@ struct Config
size_t v = 0;
for ( ; r < opt.length && isdigit(opt[r]); r++)
v = v * 10 + opt[r] - '0';

if(r == q + 1)
{
printf("numeric argument expected for GC option \"%.*s\"\n", cast(int) s.length, s.ptr);
return false;
}
if(s == "disable")
disable = v != 0;
else if(s == "profile")
Expand Down
137 changes: 137 additions & 0 deletions src/rt/config.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Configuration options for druntime
*
* Copyright: Copyright Digital Mars 2014.
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Rainer Schuetze
* Source: $(DRUNTIMESRC src/rt/_config.d)
*/

module rt.config;

// The default way to configure the runtime is by passing command line arguments
// starting with "--DRT-" and followed by the option name, e.g. "--DRT-gcopt" to
// configure the GC.
// Command line options starting with "--DRT-" are filtered out before calling main,
// so the program will not see them. They are still available via rt_args().
//
// Configuration via the command line can be disabled by declaring a variable for the
// linker to pick up before using it's default from the runtime:
//
// extern(C) __gshared bool rt_cmdline_enabled = false;
//
// Likewise, declare a boolean rt_envvars_enabled to enable configuration via the
// environment variable "DRT_" followed by the option name, e.g. "DRT_GCOPT":
//
// extern(C) __gshared bool rt_envvars_enabled = true;
//
// Setting default configuration properties in the executable can be done by specifying an
// array of options named rt_options:
//
// extern(C) __gshared string[] rt_options = [ "gcopt=precise:1 profile:1"];
//
// Evaluation order of options is rt_options, then environment variables, then command
// line arguments, i.e. if command line arguments are not disabled, they can override
// options specified through the environment or embedded in the executable.

import core.demangle : mangleC;

// put each variable in its own COMDAT by making them template instances
template rt_envvars_enabled()
{
pragma(mangle,mangleC("rt_envvars_enabled")) __gshared bool rt_envvars_enabled = false;
}
template rt_cmdline_enabled()
{
pragma(mangle,mangleC("rt_cmdline_enabled")) __gshared bool rt_cmdline_enabled = true;
}
template rt_options()
{
pragma(mangle,mangleC("rt_options")) __gshared string[] rt_options = [];
}

import core.stdc.ctype : toupper;
import core.stdc.stdlib : getenv;
import core.stdc.string : strlen;

extern extern(C) string[] rt_args() @nogc nothrow;

alias rt_configCallBack = string delegate(string) @nogc nothrow;

/**
* get a druntime config option using standard configuration options
* opt name of the option to retreive
* dg if non-null, passes the option through this
* delegate and only returns its return value if non-null
* reverse reverse the default processing order cmdline/envvar/rt_options
* to allow overwriting settings in the delegate with values
* from higher priority
*
* returns the options' value if
* - set on the command line as "--DRT-<opt>=value" (rt_cmdline_enabled enabled)
* - the environment variable "DRT_<OPT>" is set (rt_envvars_enabled enabled)
* - rt_options[] contains an entry "<opt>=value"
* - null otherwise
*/
string rt_configOption(string opt, scope rt_configCallBack dg = null, bool reverse = false) @nogc nothrow
{
if (!dg)
dg = (string s) => s;

if (string s = (reverse ? rt_linkOption(opt, dg) : rt_cmdlineOption(opt, dg)))
return s;
if (string s = rt_envvarsOption(opt, dg))
return s;
if (string s = (reverse ? rt_cmdlineOption(opt, dg) : rt_linkOption(opt, dg)))
return s;
return null;
}

string rt_cmdlineOption(string opt, scope rt_configCallBack dg) @nogc nothrow
{
if(rt_cmdline_enabled!())
{
foreach (a; rt_args)
{
if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" &&
a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=')
if (string s = dg(a[7 + opt.length .. $]))
return s;
}
}
return null;
}

string rt_envvarsOption(string opt, scope rt_configCallBack dg) @nogc nothrow
{
if(rt_envvars_enabled!())
{
if (opt.length >= 32)
assert(0);

char[40] var;
var[0 .. 4] = "DRT_";
foreach (i, c; opt)
var[4 + i] = cast(char) toupper(c);
var[4 + opt.length] = 0;

auto p = getenv(var.ptr);
if (p)
if (string s = dg(cast(string) p[0 .. strlen(p)]))
return s;
}
return null;
}

string rt_linkOption(string opt, scope rt_configCallBack dg) @nogc nothrow
{
foreach (a; rt_options!())
{
if(a.length > opt.length && a[0..opt.length] == opt && a[opt.length] == '=')
if (string s = dg(a[opt.length + 1 .. $]))
return s;
}
return null;
}

0 comments on commit 4e8bb2c

Please sign in to comment.