mirror of
https://github.com/troglobit/finit.git
synced 2026-10-14 10:19:36 +00:00
libink/dbus: give parked and outstanding calls a deadline
A call is parked until the resolver says who sent it, and an outbound call sits in a pending slot until its reply lands. Neither had a way to give up. A broker that answers GetConnectionUnixUser slowly, or not at all, leaves the caller waiting forever and keeps the slot; four of those and every later privileged call is refused with LimitsExceeded until Finit restarts. libink cannot time itself out, it has no event loop, so the deadline is the embedder's to keep. One sweep per connection covers both, and the ordering between them stays in the library rather than in each embedder: calls first, because one timing out usually resolves the park it was made for, and AccessDenied tells that caller more than a bare timeout. The sweep is armed when a resolve is deferred and stops rearming as soon as nothing is outstanding, so a system that never meets a broker never wakes up for it. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
a1969efac1
commit
853e226812
6 files changed
+172
-5
No files matched your search
+48
@@ -106,6 +106,50 @@ static void peer_reap(void *arg)
|
||||
* stopped, so nothing touches it in the meantime. */
|
||||
static struct wq reap_work = { .cb = peer_reap, .delay = 10 };
|
||||
|
||||
/*
|
||||
* Nothing in libink can time itself out, it has no event loop, so the
|
||||
* deadline for a parked call and for a call we made on the broker is
|
||||
* ours to keep. The sweep only runs while something is outstanding:
|
||||
* expire_arm() starts it, and it stops rearming as soon as nothing is
|
||||
* left, so a system that never talks to a broker never wakes up for
|
||||
* this.
|
||||
*/
|
||||
#define DBUS_CALL_TIMEOUT_MS 5000
|
||||
#define DBUS_SWEEP_MS 1000
|
||||
|
||||
static void expire_sweep(void *arg);
|
||||
static struct wq expire_work = { .cb = expire_sweep, .delay = DBUS_SWEEP_MS };
|
||||
static int expire_armed;
|
||||
|
||||
/* Idempotent: several parks in one turn of the loop share one sweep. */
|
||||
static void expire_arm(void)
|
||||
{
|
||||
if (expire_armed)
|
||||
return;
|
||||
if (!schedule_work(&expire_work))
|
||||
expire_armed = 1;
|
||||
}
|
||||
|
||||
static void expire_sweep(void *arg)
|
||||
{
|
||||
struct peer *p, *tmp;
|
||||
int live = 0;
|
||||
|
||||
(void)arg;
|
||||
expire_armed = 0;
|
||||
|
||||
/* _SAFE because expiring a call runs its callback, and a
|
||||
* callback that ends up writing to a peer can drop it, which
|
||||
* unlinks it from this very list. */
|
||||
TAILQ_FOREACH_SAFE(p, &peers, link, tmp) {
|
||||
if (!p->dead)
|
||||
live += link_connection_expire(p->conn, DBUS_CALL_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
if (live)
|
||||
expire_arm();
|
||||
}
|
||||
|
||||
/*
|
||||
* A peer can be dropped from inside its own read loop: a handler emits
|
||||
* a signal, the write to this very peer fails, and dbus_emit_signal()
|
||||
@@ -1410,6 +1454,10 @@ static int sysbus_uid_resolver(link_connection_t *conn, const char *sender,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Both the call and the park it belongs to now have a deadline
|
||||
* to answer by, so make sure something is watching the clock. */
|
||||
expire_arm();
|
||||
|
||||
return 1; /* parked; uid_reply_cb() answers */
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user