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
        );
 }

Reply via email to