commit:     0b45ff4fc55967211791186e9c6ad5d7839ec772
Author:     Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Tue Dec  9 12:02:29 2025 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Tue Dec  9 12:02:29 2025 +0000
URL:        https://gitweb.gentoo.org/proj/steve.git/commit/?id=0b45ff4f

Support per-process job limit

Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>

 steve.cxx | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/steve.cxx b/steve.cxx
index 2181dbe..1e41fd7 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -91,6 +91,7 @@ struct steve_state {
        bool verbose;
        uint64_t jobs;
        uint64_t min_jobs;
+       int64_t per_process_limit;
        double max_load_avg{-1};  /* < 0 implies no load average */
        double load_avg;
        int64_t tokens;
@@ -112,6 +113,7 @@ enum class steve_token_availability {
        available,
        no_tokens,
        load_exceeded,
+       per_process_limit_exceeded,
 };
 
 static void steve_get_load(steve_state *state)
@@ -178,6 +180,8 @@ static steve_token_availability 
steve_can_give_token(steve_state *state, uint64_
 
        if (state->tokens <= 0)
                return steve_token_availability::no_tokens;
+       if (state->per_process_limit > 0 && state->processes[pid].tokens_held 
>= state->per_process_limit)
+               return steve_token_availability::per_process_limit_exceeded;
        if (state->max_load_avg > 0) {
                if (state->jobs < state->min_jobs + state->tokens)
                        return steve_token_availability::available;
@@ -244,8 +248,16 @@ static void steve_reserve_token(steve_state *state, 
uint64_t pid)
 static void steve_wake_waiters(steve_state *state)
 {
        for (auto it = state->waiters.begin(); it != state->waiters.end();) {
-               if (steve_can_give_token(state, it->pid) != 
steve_token_availability::available)
-                       break;
+               steve_token_availability token_available = 
steve_can_give_token(state, it->pid);
+               switch (token_available) {
+                       case steve_token_availability::available:
+                               break;
+                       case 
steve_token_availability::per_process_limit_exceeded:
+                               ++it;
+                               continue;
+                       default:
+                               return;
+               }
 
                if (fuse_req_t *read_req = 
std::get_if<fuse_req_t>(&it->handle)) {
                        /* read request */
@@ -330,6 +342,8 @@ static void steve_init(void *userdata, struct 
fuse_conn_info *)
        }
        if (state->min_jobs > 0)
                std::print(stderr, "  at least {} jobs will be always 
available\n", state->min_jobs);
+       if (state->per_process_limit > 0)
+               std::print(stderr, "  per-process limit set to {}\n", 
state->per_process_limit);
 }
 
 static void steve_destroy(void *userdata)
@@ -742,6 +756,8 @@ static constexpr char steve_usage[] =
 "                           (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"
+"    --per-process-limit=LIMIT, -p LIMIT\n"
+"                           max. jobs to serve to a single process\n"
 "    --user=USER, -u USER   drop superuser privileges and switch to USER\n"
 "                           (and its primary group)\n"
 "    --verbose, -v          enable verbose logging\n"
@@ -754,13 +770,14 @@ static const struct option steve_long_opts[] = {
        { "load-average", required_argument, 0, 'l' },
        { "load-recheck-timeout", required_argument, 0, 'r' },
        { "min-jobs", required_argument, 0, 'm' },
+       { "per-process-limit", required_argument, 0, 'p' },
        { "user", required_argument, 0, 'u' },
        { "verbose", no_argument, 0, 'v' },
        { "debug", no_argument, 0, 'd' },
        {},
 };
 
-static const char *steve_short_opts = "hVj:l:r:m:u:vd";
+static const char *steve_short_opts = "hVj:l:r:m:p:u:vd";
 
 int main(int argc, char **argv)
 {
@@ -779,6 +796,7 @@ int main(int argc, char **argv)
                                return 0;
                        case 'j':
                        case 'm':
+                       case 'p':
                                {
                                        long jobs_arg;
                                        if (!arg_to_long(optarg, &jobs_arg)) {
@@ -789,6 +807,8 @@ int main(int argc, char **argv)
                                                state.jobs = jobs_arg;
                                        else if (opt == 'm')
                                                state.min_jobs = jobs_arg;
+                                       else if (opt == 'p')
+                                               state.per_process_limit = 
jobs_arg;
                                        else
                                                assert(0 && "not reached");
                                }

Reply via email to