mirror of
https://github.com/NixOS/nix
synced 2024-09-19 10:50:24 -04:00
118 lines
3 KiB
C++
118 lines
3 KiB
C++
#include "error.hh"
|
|
#include "environment-variables.hh"
|
|
#include "eval-settings.hh"
|
|
#include "config-global.hh"
|
|
#include "serialise.hh"
|
|
#include "eval-gc.hh"
|
|
|
|
#if HAVE_BOEHMGC
|
|
|
|
# include <pthread.h>
|
|
# if __FreeBSD__
|
|
# include <pthread_np.h>
|
|
# endif
|
|
|
|
# include <gc/gc.h>
|
|
# include <gc/gc_cpp.h>
|
|
# include <gc/gc_allocator.h>
|
|
|
|
# include <boost/coroutine2/coroutine.hpp>
|
|
# include <boost/coroutine2/protected_fixedsize_stack.hpp>
|
|
# include <boost/context/stack_context.hpp>
|
|
|
|
#endif
|
|
|
|
namespace nix {
|
|
|
|
#if HAVE_BOEHMGC
|
|
/* Called when the Boehm GC runs out of memory. */
|
|
static void * oomHandler(size_t requested)
|
|
{
|
|
/* Convert this to a proper C++ exception. */
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
static inline void initGCReal()
|
|
{
|
|
/* Initialise the Boehm garbage collector. */
|
|
|
|
/* Don't look for interior pointers. This reduces the odds of
|
|
misdetection a bit. */
|
|
GC_set_all_interior_pointers(0);
|
|
|
|
/* We don't have any roots in data segments, so don't scan from
|
|
there. */
|
|
GC_set_no_dls(1);
|
|
|
|
/* Enable perf measurements. This is just a setting; not much of a
|
|
start of something. */
|
|
GC_start_performance_measurement();
|
|
|
|
GC_INIT();
|
|
|
|
GC_set_oom_fn(oomHandler);
|
|
|
|
/* Set the initial heap size to something fairly big (25% of
|
|
physical RAM, up to a maximum of 384 MiB) so that in most cases
|
|
we don't need to garbage collect at all. (Collection has a
|
|
fairly significant overhead.) The heap size can be overridden
|
|
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
|
|
should probably also provide a nix.conf setting for this. Note
|
|
that GC_expand_hp() causes a lot of virtual, but not physical
|
|
(resident) memory to be allocated. This might be a problem on
|
|
systems that don't overcommit. */
|
|
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
|
|
size_t size = 32 * 1024 * 1024;
|
|
# if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
|
|
size_t maxSize = 384 * 1024 * 1024;
|
|
long pageSize = sysconf(_SC_PAGESIZE);
|
|
long pages = sysconf(_SC_PHYS_PAGES);
|
|
if (pageSize != -1)
|
|
size = (pageSize * pages) / 4; // 25% of RAM
|
|
if (size > maxSize)
|
|
size = maxSize;
|
|
# endif
|
|
debug("setting initial heap size to %1% bytes", size);
|
|
GC_expand_hp(size);
|
|
}
|
|
}
|
|
|
|
static size_t gcCyclesAfterInit = 0;
|
|
|
|
size_t getGCCycles()
|
|
{
|
|
assertGCInitialized();
|
|
return static_cast<size_t>(GC_get_gc_no()) - gcCyclesAfterInit;
|
|
}
|
|
|
|
#endif
|
|
|
|
static bool gcInitialised = false;
|
|
|
|
void initGC()
|
|
{
|
|
if (gcInitialised)
|
|
return;
|
|
|
|
#if HAVE_BOEHMGC
|
|
initGCReal();
|
|
|
|
gcCyclesAfterInit = GC_get_gc_no();
|
|
#endif
|
|
|
|
// NIX_PATH must override the regular setting
|
|
// See the comment in applyConfig
|
|
if (auto nixPathEnv = getEnv("NIX_PATH")) {
|
|
globalConfig.set("nix-path", concatStringsSep(" ", EvalSettings::parseNixPath(nixPathEnv.value())));
|
|
}
|
|
|
|
gcInitialised = true;
|
|
}
|
|
|
|
void assertGCInitialized()
|
|
{
|
|
assert(gcInitialised);
|
|
}
|
|
|
|
} // namespace nix
|