commit: 0acfa9b48c03eaddc29216a67eb751a202a4736e
Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Tue Dec 9 09:57:18 2025 +0000
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Tue Dec 9 09:57:18 2025 +0000
URL: https://gitweb.gentoo.org/proj/steve.git/commit/?id=0acfa9b4
Support changing the recheck delay
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>
steve.cxx | 31 +++++++++++++++++++++++++------
stevie.cxx | 2 +-
util.hxx | 6 +++---
3 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/steve.cxx b/steve.cxx
index 0a0d6dd..32b0a94 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -17,6 +17,7 @@
#include <cstring>
#include <cerrno>
#include <climits>
+#include <cmath>
#include <csignal>
#include <deque>
#include <functional>
@@ -97,6 +98,7 @@ struct steve_state {
std::unordered_map<uint64_t, steve_process> processes;
struct event_base *evb;
int loadavg_fd{-2};
+ struct timeval recheck_timeout{0, 500000};
bool recheck_triggered{false};
std::unique_ptr<struct event, std::function<void(struct event*)>>
recheck_event{nullptr, event_free};
@@ -183,9 +185,7 @@ static steve_token_availability
steve_can_give_token(steve_state *state, uint64_
if (state->load_avg > state->max_load_avg) {
/* trigger a recheck if we don't have one now */
assert(!state->recheck_triggered);
- /* TODO: make this configurable? */
- struct timeval tv = { 0, 500000 };
- if (evtimer_add(state->recheck_event.get(), &tv) == -1)
+ if (evtimer_add(state->recheck_event.get(),
&state->recheck_timeout) == -1)
std::print(stderr, "failed to enable recheck
timer\n");
else
state->recheck_triggered = true;
@@ -323,8 +323,11 @@ static void steve_init(void *userdata, struct
fuse_conn_info *)
state->tokens = state->jobs;
std::print(stderr, "steve running on /dev/steve for {} jobs\n",
state->jobs);
- if (state->max_load_avg > 0)
+ if (state->max_load_avg > 0) {
std::print(stderr, " tokens will be served with load average <
{:.3}\n", state->max_load_avg);
+ std::print(stderr, " with a recheck timeout of {} s {} us\n",
+ state->recheck_timeout.tv_sec,
state->recheck_timeout.tv_usec);
+ }
if (state->min_jobs > 0)
std::print(stderr, " at least {} jobs will be always
available\n", state->min_jobs);
}
@@ -708,6 +711,9 @@ static constexpr char steve_usage[] =
" --jobs=JOBS, -j JOBS jobs to use (default: nproc)\n"
" --load-average=LOAD_AVG, -l LOAD_AVG\n"
" do not serve tokens unless load is below
LOAD_AVG\n"
+" --load-recheck-timeout=TIMEOUT, -r TIMEOUT\n"
+" timeout for throttling due to exceeded load, in
sec\n"
+" (fractional down to usec, default: 0.5)\n"
" --min-jobs=MIN_JOBS, -m MIN_JOBS\n"
" min. jobs to serve even if load average is
exceeded\n"
" --user=USER, -u USER drop superuser privileges and switch to USER\n"
@@ -720,6 +726,7 @@ static const struct option steve_long_opts[] = {
{ "version", no_argument, 0, 'V' },
{ "jobs", required_argument, 0, 'j' },
{ "load-average", required_argument, 0, 'l' },
+ { "load-recheck-timeout", required_argument, 0, 'r' },
{ "min-jobs", required_argument, 0, 'm' },
{ "user", required_argument, 0, 'u' },
{ "verbose", no_argument, 0, 'v' },
@@ -727,7 +734,7 @@ static const struct option steve_long_opts[] = {
{},
};
-static const char *steve_short_opts = "hVj:l:m:u:vd";
+static const char *steve_short_opts = "hVj:l:r:m:u:vd";
int main(int argc, char **argv)
{
@@ -761,11 +768,23 @@ int main(int argc, char **argv)
}
break;
case 'l':
- if (!arg_to_load_avg(optarg,
&state.max_load_avg)) {
+ if (!arg_to_double(optarg, &state.max_load_avg)
|| state.max_load_avg < 1) {
std::print(stderr, "invalid load
average value (must be >=1): {}\n", optarg);
return 1;
}
break;
+ case 'r': {
+ double timeout;
+ if (!arg_to_double(optarg, &timeout) || timeout
< 0.000001 || timeout > INT_MAX) {
+ std::print(stderr, "invalid timeout
value (must be >=1 us): {}\n", optarg);
+ return 1;
+ }
+ state.recheck_timeout.tv_sec = trunc(timeout);
+ state.recheck_timeout.tv_usec = (
+ (timeout -
state.recheck_timeout.tv_sec) * 1000000
+ );
+ break;
+ }
case 'u':
user = optarg;
break;
diff --git a/stevie.cxx b/stevie.cxx
index 3fdb95a..46769a6 100644
--- a/stevie.cxx
+++ b/stevie.cxx
@@ -215,7 +215,7 @@ int main(int argc, char **argv)
actions.emplace_back(ioctl_num, ioctl_val);
} else if (STEVE_IOC_IS_SET(ioctl_num)) {
if (double *dval =
std::get_if<double>(&ioctl_val)) {
- if (!arg_to_load_avg(optarg, dval)) {
+ if (!arg_to_double(optarg, dval) ||
*dval < 1) {
std::print(stderr, "invalid
load average value (must be >=1): {}\n", optarg);
return 1;
}
diff --git a/util.hxx b/util.hxx
index fab35c7..87ab29a 100644
--- a/util.hxx
+++ b/util.hxx
@@ -10,7 +10,7 @@ struct fd_guard {
~fd_guard() { close(fd); }
};
-bool arg_to_long(const char *optarg, long *out) {
+static bool arg_to_long(const char *optarg, long *out) {
char *endptr;
errno = 0;
*out = strtol(optarg, &endptr, 10);
@@ -19,11 +19,11 @@ bool arg_to_long(const char *optarg, long *out) {
);
}
-bool arg_to_load_avg(const char *optarg, double *out) {
+static bool arg_to_double(const char *optarg, double *out) {
char *endptr;
errno = 0;
*out = strtod(optarg, &endptr);
return (
- !*endptr && errno == 0 && *out >= 1
+ !*endptr && errno == 0
);
}