From 14ebde52893263930cdcde1406cc91cc5c42556f Mon Sep 17 00:00:00 2001 From: Christian Theune Date: Tue, 5 Jan 2016 00:40:40 +0100 Subject: First hit at providing support for floats in the language. --- src/libmain/shared.hh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/libmain') diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 65b288e1ff3e..a350f496d19f 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -66,6 +66,30 @@ template N getIntArg(const string & opt, return n * multiplier; } +template N getFloatArg(const string & opt, + Strings::iterator & i, const Strings::iterator & end, bool allowUnit) +{ + ++i; + if (i == end) throw UsageError(format("‘%1%’ requires an argument") % opt); + string s = *i; + N multiplier = 1; + if (allowUnit && !s.empty()) { + char u = std::toupper(*s.rbegin()); + if (std::isalpha(u)) { + if (u == 'K') multiplier = 1ULL << 10; + else if (u == 'M') multiplier = 1ULL << 20; + else if (u == 'G') multiplier = 1ULL << 30; + else if (u == 'T') multiplier = 1ULL << 40; + else throw UsageError(format("invalid unit specifier ‘%1%’") % u); + s.resize(s.size() - 1); + } + } + N n; + if (!string2Float(s, n)) + throw UsageError(format("‘%1%’ requires a float argument") % opt); + return n * multiplier; +} + /* Show the manual page for the specified program. */ void showManPage(const string & name); -- cgit 1.4.1 From 934642155c036ce6880e57854f095f2863ab80f1 Mon Sep 17 00:00:00 2001 From: Christian Theune Date: Wed, 6 Jan 2016 08:25:58 +0100 Subject: @eelco's feedback: downgrade to regular float for size, remove unused function. --- src/libexpr/value.hh | 2 +- src/libmain/shared.hh | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) (limited to 'src/libmain') diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 88424106cdeb..62bdd9281f08 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -39,7 +39,7 @@ class XMLWriter; typedef long NixInt; -typedef double NixFloat; +typedef float NixFloat; /* External values must descend from ExternalValueBase, so that * type-agnostic nix functions (e.g. showType) can be implemented diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index a350f496d19f..32183d6a6cb0 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -66,29 +66,6 @@ template N getIntArg(const string & opt, return n * multiplier; } -template N getFloatArg(const string & opt, - Strings::iterator & i, const Strings::iterator & end, bool allowUnit) -{ - ++i; - if (i == end) throw UsageError(format("‘%1%’ requires an argument") % opt); - string s = *i; - N multiplier = 1; - if (allowUnit && !s.empty()) { - char u = std::toupper(*s.rbegin()); - if (std::isalpha(u)) { - if (u == 'K') multiplier = 1ULL << 10; - else if (u == 'M') multiplier = 1ULL << 20; - else if (u == 'G') multiplier = 1ULL << 30; - else if (u == 'T') multiplier = 1ULL << 40; - else throw UsageError(format("invalid unit specifier ‘%1%’") % u); - s.resize(s.size() - 1); - } - } - N n; - if (!string2Float(s, n)) - throw UsageError(format("‘%1%’ requires a float argument") % opt); - return n * multiplier; -} /* Show the manual page for the specified program. */ void showManPage(const string & name); -- cgit 1.4.1 From 840056af04561e7fed31c459948be7c0e038864a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 22 Feb 2016 14:49:15 +0100 Subject: Make OpenSSL usage thread-safe OpenSSL can randomly segfault unless we register a callback function to do locking. https://www.openssl.org/docs/manmaster/crypto/threads.html --- src/libmain/local.mk | 2 ++ src/libmain/shared.cc | 24 ++++++++++++++++++++---- src/libmain/shared.hh | 4 ++++ 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'src/libmain') diff --git a/src/libmain/local.mk b/src/libmain/local.mk index 16dbf752823d..4ff114e4b332 100644 --- a/src/libmain/local.mk +++ b/src/libmain/local.mk @@ -6,6 +6,8 @@ libmain_DIR := $(d) libmain_SOURCES := $(wildcard $(d)/*.cc) +libutil_LDFLAGS = $(OPENSSL_LIBS) + libmain_LIBS = libstore libutil libformat libmain_ALLOW_UNDEFINED = 1 diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 88ed52497fb9..8f2aa842036a 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -5,10 +5,11 @@ #include "store-api.hh" #include "util.hh" -#include +#include #include #include -#include +#include +#include #include #include @@ -16,7 +17,7 @@ #include #include -extern char * * environ; +#include namespace nix { @@ -103,7 +104,18 @@ string getArg(const string & opt, } -void detectStackOverflow(); +/* OpenSSL is not thread-safe by default - it will randomly crash + unless the user supplies a mutex locking function. So let's do + that. */ +static std::vector opensslLocks; + +static void opensslLockCallback(int mode, int type, const char * file, int line) +{ + if (mode & CRYPTO_LOCK) + opensslLocks[type].lock(); + else + opensslLocks[type].unlock(); +} void initNix() @@ -119,6 +131,10 @@ void initNix() if (getEnv("IN_SYSTEMD") == "1") logType = ltSystemd; + /* Initialise OpenSSL locking. */ + opensslLocks = std::vector(CRYPTO_num_locks()); + CRYPTO_set_locking_callback(opensslLockCallback); + settings.processEnvironment(); settings.loadConfFile(); diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 3f3f6f7232e0..0682267fa376 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -101,4 +101,8 @@ struct PrintFreed }; +/* Install a SIGSEGV handler to detect stack overflows. */ +void detectStackOverflow(); + + } -- cgit 1.4.1 From 8f71bc33d5af7bc6d4728e5e36e89bcad27d2096 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 22 Feb 2016 17:33:27 +0100 Subject: Doh --- src/libmain/local.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libmain') diff --git a/src/libmain/local.mk b/src/libmain/local.mk index 4ff114e4b332..f1fd3eb72424 100644 --- a/src/libmain/local.mk +++ b/src/libmain/local.mk @@ -6,7 +6,7 @@ libmain_DIR := $(d) libmain_SOURCES := $(wildcard $(d)/*.cc) -libutil_LDFLAGS = $(OPENSSL_LIBS) +libmain_LDFLAGS = $(OPENSSL_LIBS) libmain_LIBS = libstore libutil libformat -- cgit 1.4.1 From d5626bf4c14f725136f2c5b6ac8bf818627352f0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 23 Feb 2016 16:40:16 +0100 Subject: Pool: Allow a maximum pool size --- src/libmain/shared.cc | 1 + src/libstore/remote-store.cc | 30 +++++++++---------- src/libstore/remote-store.hh | 7 +++-- src/libutil/pool.hh | 69 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 74 insertions(+), 33 deletions(-) (limited to 'src/libmain') diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 8f2aa842036a..c27302227304 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -126,6 +126,7 @@ void initNix() std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf)); #endif + // FIXME: do we need this? It's not thread-safe. std::ios::sync_with_stdio(false); if (getEnv("IN_SYSTEMD") == "1") diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 847da107a111..f6ec3fffb614 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -14,8 +14,8 @@ #include #include #include - #include + #include namespace nix { @@ -39,8 +39,8 @@ template T readStorePaths(Source & from) template PathSet readStorePaths(Source & from); -RemoteStore::RemoteStore() - : connections(make_ref>([this]() { return openConnection(); })) +RemoteStore::RemoteStore(size_t maxConnections) + : connections(make_ref>(maxConnections, [this]() { return openConnection(); })) { } @@ -116,18 +116,6 @@ ref RemoteStore::openConnection(bool reserveSpace) } -RemoteStore::~RemoteStore() -{ - try { - //to.flush(); - //fdSocket.close(); - // FIXME: close pool - } catch (...) { - ignoreException(); - } -} - - void RemoteStore::setOptions(ref conn) { conn->to << wopSetOptions @@ -568,6 +556,18 @@ bool RemoteStore::verifyStore(bool checkContents, bool repair) return readInt(conn->from) != 0; } + +RemoteStore::Connection::~Connection() +{ + try { + to.flush(); + fd.close(); + } catch (...) { + ignoreException(); + } +} + + void RemoteStore::Connection::processStderr(Sink * sink, Source * source) { to.flush(); diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index b16a6b51db0f..af417b84ff9c 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include "store-api.hh" @@ -19,9 +20,7 @@ class RemoteStore : public Store { public: - RemoteStore(); - - ~RemoteStore(); + RemoteStore(size_t maxConnections = std::numeric_limits::max()); /* Implementations of abstract store API methods. */ @@ -100,6 +99,8 @@ private: FdSource from; unsigned int daemonVersion; + ~Connection(); + void processStderr(Sink * sink = 0, Source * source = 0); }; diff --git a/src/libutil/pool.hh b/src/libutil/pool.hh index d63912e28aa9..4b865a19389e 100644 --- a/src/libutil/pool.hh +++ b/src/libutil/pool.hh @@ -1,8 +1,10 @@ #pragma once -#include -#include #include +#include +#include +#include +#include #include "sync.hh" #include "ref.hh" @@ -39,37 +41,58 @@ private: struct State { - unsigned int count = 0; - std::list> idle; + size_t inUse = 0; + size_t max; + std::vector> idle; }; Sync state; + std::condition_variable_any wakeup; + public: - Pool(const Factory & factory = []() { return make_ref(); }) + Pool(size_t max = std::numeric_limits::max, + const Factory & factory = []() { return make_ref(); }) : factory(factory) - { } + { + auto state_(state.lock()); + state_->max = max; + } + + ~Pool() + { + auto state_(state.lock()); + assert(!state_->inUse); + state_->max = 0; + state_->idle.clear(); + } class Handle { private: Pool & pool; - ref r; + std::shared_ptr r; friend Pool; Handle(Pool & pool, std::shared_ptr r) : pool(pool), r(r) { } public: - Handle(Handle && h) : pool(h.pool), r(h.r) { abort(); } + Handle(Handle && h) : pool(h.pool), r(h.r) { h.r.reset(); } Handle(const Handle & l) = delete; ~Handle() { - auto state_(pool.state.lock()); - state_->idle.push_back(r); + if (!r) return; + { + auto state_(pool.state.lock()); + state_->idle.push_back(ref(r)); + assert(state_->inUse); + state_->inUse--; + } + pool.wakeup.notify_one(); } R * operator -> () { return &*r; } @@ -80,22 +103,38 @@ public: { { auto state_(state.lock()); + + /* If we're over the maximum number of instance, we need + to wait until a slot becomes available. */ + while (state_->idle.empty() && state_->inUse >= state_->max) + state_.wait(wakeup); + if (!state_->idle.empty()) { auto p = state_->idle.back(); state_->idle.pop_back(); + state_->inUse++; return Handle(*this, p); } - state_->count++; + + state_->inUse++; + } + + /* We need to create a new instance. Because that might take a + while, we don't hold the lock in the meantime. */ + try { + Handle h(*this, factory()); + return h; + } catch (...) { + auto state_(state.lock()); + state_->inUse--; + throw; } - /* Note: we don't hold the lock while creating a new instance, - because creation might take a long time. */ - return Handle(*this, factory()); } unsigned int count() { auto state_(state.lock()); - return state_->count; + return state_->count + state_->inUse; } }; -- cgit 1.4.1