conf: route service conditions through one owner primitive

A service's condition was computed with mkcond() at each of the six
sites that assert or clear it, and svc_find_by_cond() reimplemented
the reverse lookup a seventh time.  maybe_clear_cond() had its own
scan for another service supplying the same condition.

svc_cond_owner() answers who owns a condition, svc_cond_nth() walks
the conditions a service owns, and svc_cond_set()/svc_cond_clear()
apply to all of them.  svc_find_by_cond() becomes a wrapper, and
maybe_clear_cond() keeps its rule per condition rather than for the
one it used to compute.

The provides[] storage lands here unused, since svc_cond_nth() reads
num_provides.  Nothing sets it yet, so a service still owns exactly
its own pid/<ident> and there is no functional change.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-08-05 17:57:57 +02:00
parent 4299ce8839
commit 22fbb408eb
7 changed files with 129 additions and 36 deletions
+2 -2
View File
@@ -148,12 +148,12 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
}
if (svc->notify == SVC_NOTIFY_PID)
cond_set(cond);
svc_cond_set(svc);
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
service_ready(svc, 1);
} else if (mask & IN_DELETE) {
sneaky_zebra:
cond_clear(cond);
svc_cond_clear(svc);
if (svc->notify == SVC_NOTIFY_PID)
service_ready(svc, 0);
}
+1 -3
View File
@@ -112,8 +112,6 @@ static int restart(svc_t *svc, void *user_data)
static int reload(svc_t *svc, void *user_data)
{
char cond[MAX_COND_LEN];
(void)user_data;
if (!svc)
@@ -138,7 +136,7 @@ static int reload(svc_t *svc, void *user_data)
* mechanism which may not re-trigger on SIGHUP.
*/
if (svc_is_noreload(svc)) {
cond_clear(mkcond(svc, cond, sizeof(cond)));
svc_cond_clear(svc);
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
service_ready(svc, 0);
}
+25
View File
@@ -145,6 +145,31 @@ char *mkcond(svc_t *svc, char *buf, size_t len)
return buf;
}
/*
* Assert or clear every condition a service owns: its own pid/<ident>
* and anything it declares with provides. Each site that owns a
* service's conditions goes through these, so the two cannot drift.
*/
void svc_cond_set(svc_t *svc)
{
char buf[MAX_COND_LEN];
const char *cond;
int i = 0;
while ((cond = svc_cond_nth(svc, i++, buf, sizeof(buf))))
cond_set(cond);
}
void svc_cond_clear(svc_t *svc)
{
char buf[MAX_COND_LEN];
const char *cond;
int i = 0;
while ((cond = svc_cond_nth(svc, i++, buf, sizeof(buf))))
cond_clear(cond);
}
static int cond_set_gen(const char *file, unsigned int gen)
{
char *ptr, path[256];
+2
View File
@@ -25,6 +25,8 @@ typedef enum cond_state {
} cond_state_t;
char *mkcond (svc_t *svc, char *buf, size_t len);
void svc_cond_set (svc_t *svc);
void svc_cond_clear(svc_t *svc);
const char *condstr (enum cond_state s);
const char *cond_path (const char *name);
unsigned int cond_get_gen (const char *path);
+2 -6
View File
@@ -1271,8 +1271,6 @@ static void service_clean_pidfile(svc_t *svc, pid_t reaped)
*/
static void service_cleanup(svc_t *svc)
{
char cond[MAX_COND_LEN];
/* PID collected, cancel any pending SIGKILL */
service_timeout_cancel(svc);
@@ -1297,7 +1295,7 @@ static void service_cleanup(svc_t *svc)
* RUNNING to HALTED (skipping STOPPING where cond_clear()
* is normally called).
*/
cond_clear(mkcond(svc, cond, sizeof(cond)));
svc_cond_clear(svc);
service_notify_stop(svc);
@@ -3191,13 +3189,11 @@ restart:
case SVC_STOPPING_STATE:
if (!svc->pid) {
char condstr[MAX_COND_LEN];
dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
service_notify_stop(svc);
service_timeout_cancel(svc);
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
svc_cond_clear(svc);
switch (svc->type) {
case SVC_TYPE_SERVICE:
+89 -25
View File
@@ -57,27 +57,24 @@ static TAILQ_HEAD(, svc) gc_list = TAILQ_HEAD_INITIALIZER(gc_list);
static void maybe_clear_cond(svc_t *svc)
{
char ident[MAX_IDENT_LEN];
char cond[MAX_COND_LEN];
svc_t *iter = NULL;
svc_t *s;
char buf[MAX_COND_LEN];
const char *cond;
int i = 0;
mkcond(svc, cond, sizeof(cond));
svc_ident(svc, ident, sizeof(ident));
for (s = svc_iterator(&iter, 1); s; s = svc_iterator(&iter, 0)) {
char c[MAX_COND_LEN];
while ((cond = svc_cond_nth(svc, i++, buf, sizeof(buf)))) {
svc_t *owner = svc_cond_owner(cond, svc);
mkcond(s, c, sizeof(c));
if (!string_compare(cond, c))
if (owner) {
dbg("Not clearing cond %s from gc svc %s, provided by new active service %s",
cond, ident, svc_ident(owner, NULL, 0));
continue;
}
dbg("Not clearing cond %s from gc svc %s, provided by new active service %s",
cond, ident, svc_ident(s, NULL, 0));
return;
dbg("Cleaning out %s, clearing cond %s ...", ident, cond);
cond_clear(cond);
}
dbg("Cleaning out %s, clearing any conditions ...", svc->name);
cond_clear(mkcond(svc, cond, sizeof(cond)));
}
static void svc_gc(void *arg)
@@ -459,25 +456,92 @@ svc_t *svc_find_by_pid(pid_t pid)
}
/**
* svc_find_by_cond - Find a service object by its pid/foo condition
* @cond: Full "pid/foo" condition
* svc_cond_nth - Walk the conditions a service owns
* @svc: Service object
* @i: 0 for the service's own pid/<ident>, 1.. for provided ones
* @buf: Scratch for the own condition, unused for the rest
* @len: Size of @buf
*
* Returns:
* The @i'th condition, or %NULL when @i is past the last one.
*/
const char *svc_cond_nth(svc_t *svc, int i, char *buf, size_t len)
{
if (!svc || i < 0)
return NULL;
if (i == 0)
return mkcond(svc, buf, len);
if (i > svc->num_provides)
return NULL;
return svc->provides[i - 1];
}
/**
* svc_cond_owner - Find the service that owns a condition
* @cond: Full condition, e.g. "pid/syslogd"
* @skip: Service to leave out of the search, or %NULL
*
* A service's own pid/<ident> outranks one it merely provides, that is
* how Finit tracks the service itself, so every identity is checked
* before any provides.
*
* Returns:
* A pointer to an &svc_t object, or %NULL if nobody owns @cond.
*/
svc_t *svc_cond_owner(const char *cond, svc_t *skip)
{
svc_t *svc, *iter = NULL;
int i;
if (!cond || !cond[0])
return NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
char buf[MAX_COND_LEN];
if (svc == skip)
continue;
if (string_compare(mkcond(svc, buf, sizeof(buf)), cond))
return svc;
}
iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (svc == skip)
continue;
for (i = 0; i < svc->num_provides; i++) {
if (string_compare(svc->provides[i], cond))
return svc;
}
}
return NULL;
}
/**
* svc_find_by_cond - Find a service object by a condition it owns
* @cond: Full condition, e.g. "pid/syslogd"
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find_by_cond(const char *cond)
{
return svc_cond_owner(cond, NULL);
}
/*
* Provides are re-read from the .conf files on every reload, and a
* service re-registering must not lose to a claim another service has
* not dropped yet, so they all go at once before parsing starts.
*/
void svc_provides_reset(void)
{
svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
char buf[MAX_COND_LEN];
mkcond(svc, buf, sizeof(buf));
if (string_compare(buf, cond))
return svc;
}
return NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0))
svc->num_provides = 0;
}
/**
+8
View File
@@ -102,6 +102,7 @@ typedef enum {
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
#define MAX_USER_LEN 16
#define MAX_NUM_SUPGROUPS 4
#define MAX_NUM_PROVIDES 4
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
#define MAX_NUM_SVC_ARGS 64
@@ -151,6 +152,10 @@ typedef struct svc {
svc_block_t block; /* Reason that this service is currently stopped */
char cond[MAX_COND_LEN];
/* Conditions this service asserts on top of its own pid/<ident> */
char provides[MAX_NUM_PROVIDES][MAX_COND_LEN];
int num_provides;
/* Instance specifics */
int job; /* For internal use only, canonical ref is NAME:ID */
char name[MAX_ARG_LEN];
@@ -266,6 +271,9 @@ svc_t *svc_find (char *name, char *id);
svc_t *svc_find_by_str (const char *str);
svc_t *svc_find_by_pid (pid_t pid);
svc_t *svc_find_by_cond (const char *cond);
svc_t *svc_cond_owner (const char *cond, svc_t *skip);
const char *svc_cond_nth (svc_t *svc, int i, char *buf, size_t len);
void svc_provides_reset (void);
svc_t *svc_find_by_jobid (int job, char *id);
svc_t *svc_find_by_tty (char *dev);
svc_t *svc_find_by_pidfile (char *fn);