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