diff --git a/src/spawn/Client.cxx b/src/spawn/Client.cxx index 8d1aa3175..6b72eb239 100644 --- a/src/spawn/Client.cxx +++ b/src/spawn/Client.cxx @@ -429,9 +429,11 @@ Serialize(SpawnSerializer &s, const PreparedChildProcess &p) std::unique_ptr SpawnServerClient::SpawnChildProcess(const char *name, PreparedChildProcess &&p) -{ +try { assert(!shutting_down); + ++stats.spawned; + /* this check is performed again on the server (which is obviously necessary, and the only way to have it secure); this one is only here for the developer to see the error earlier in the @@ -467,6 +469,9 @@ SpawnServerClient::SpawnChildProcess(const char *name, auto handle = std::make_unique(*this, pid); processes.insert(*handle); return handle; +} catch (...) { + ++stats.errors; + throw; } void @@ -526,10 +531,12 @@ SpawnServerClient::HandleExecCompleteMessage(SpawnPayload payload) if (const auto i = processes.find(pid); i != processes.end()) { // TODO forward errors if (i->completion_handler) { - if (*error == 0) + if (*error == 0) { i->completion_handler->OnSpawnSuccess(); - else + } else { + ++stats.errors; i->completion_handler->OnSpawnError(std::make_exception_ptr(std::runtime_error{error})); + } /* if there is a completion handler, don't log error message to diff --git a/src/spawn/Client.hxx b/src/spawn/Client.hxx index 6b09db23d..fd2987278 100644 --- a/src/spawn/Client.hxx +++ b/src/spawn/Client.hxx @@ -6,6 +6,7 @@ #include "Interface.hxx" #include "Config.hxx" +#include "Stats.hxx" #include "event/DeferEvent.hxx" #include "event/SocketEvent.hxx" #include "net/MultiReceiveMessage.hxx" @@ -47,7 +48,9 @@ class SpawnServerClient final : public SpawnService { IntrusiveHashSetOperators, - std::equal_to>>; + std::equal_to>, + IntrusiveHashSetBaseHookTraits, + IntrusiveHashSetOptions{.constant_time_size=true}>; ChildProcessSet processes; @@ -63,6 +66,8 @@ class SpawnServerClient final : public SpawnService { MultiReceiveMessage receive{16, 1024, CMSG_SPACE(sizeof(int)), 1}; + mutable SpawnStats stats{}; + unsigned last_pid = 0; /** @@ -107,6 +112,11 @@ public: return cgroups; } + const SpawnStats &GetStats() const noexcept { + stats.alive = processes.size(); + return stats; + } + void Shutdown() noexcept; UniqueSocketDescriptor Connect(); diff --git a/src/spawn/Stats.hxx b/src/spawn/Stats.hxx new file mode 100644 index 000000000..fb212a22d --- /dev/null +++ b/src/spawn/Stats.hxx @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright CM4all GmbH +// author: Max Kellermann + +#pragma once + +#include + +struct SpawnStats { + /** + * The total number of SpawnChildProcess() calls (include + * failed ones). + */ + uint_least64_t spawned; + + /** + * The number of failed SpawnChildProcess() calls. + */ + uint_least64_t errors; + + /** + * How many child processse are alive right now? + */ + std::size_t alive; +};