ccan: update to get io_loop fairness.
What changed, and why it matters
This commit updates an internal helper library (CCAN) used by Core Lightning to make the program's main event loop fairer when handling many network connections. Previously, lower-numbered file descriptors could be serviced first every time, which in extreme cases might let one connection starve others. The change rotates through connections and interleaves 'always-run' callbacks. The commit message explicitly says this is not currently security-relevant for Core Lightning ('This doesn't really make a difference until we start using it').
Treat as a routine reliability/fairness improvement. No urgent security action is warranted based on this commit alone. If Core Lightning later begins relying on io_loop fairness guarantees, reassess.
Security signals we found
Fairness improvement in I/O loop scheduling
Potential denial-of-service mitigation against low-fd connection starvation
No explicit security claim by vendor; author says change is not yet impactful
No input validation, memory safety, or cryptographic changes
Evidence from the diff
The patch imports CCAN revision init-2606-g5f219f03 into ccan/ccan/io/poll.c. It restructures io_loop(): a static fairness_counter is incremented each iteration and used to rotate the starting index when scanning polled file descriptors, preventing persistent preference for low fd indices. It also moves handle_always() handling so ‘always’ callbacks are interleaved before the first rotated fd and after a poll timeout, and adjusts the assertions/timeout logic to account for num_always. The commit message states this fairness behavior is not yet depended upon by Core Lightning.
Changed components
ccan/ccan/io/poll.cio_loop event loop schedulingInspect captured patch +26 / −11
diff --git a/ccan/README b/ccan/README
index 022df6bf..8b589bc9 100644
--- a/ccan/README
+++ b/ccan/README
@@ -1,3 +1,3 @@
CCAN imported from http://ccodearchive.net.
-CCAN version: init-2605-gc47bf0d9
+CCAN version: init-2606-g5f219f03
diff --git a/ccan/ccan/io/poll.c b/ccan/ccan/io/poll.c
index 7fe9e2c5..656cc0e3 100644
--- a/ccan/ccan/io/poll.c
+++ b/ccan/ccan/io/poll.c
@@ -373,6 +373,8 @@ static void restore_pollfds(void)
void *io_loop(struct timers *timers, struct timer **expired)
{
void *ret;
+ /* This ensures we don't always service lower fds first */
+ static int fairness_counter;
/* if timers is NULL, expired must be. If not, not. */
assert(!timers == !expired);
@@ -384,17 +386,12 @@ void *io_loop(struct timers *timers, struct timer **expired)
while (!io_loop_return) {
int i, r, ms_timeout = -1;
- if (handle_always()) {
- /* Could have started/finished more. */
- continue;
- }
-
/* Everything closed? */
if (num_fds == 0)
break;
/* You can't tell them all to go to sleep! */
- assert(num_waiting);
+ assert(num_waiting || num_always);
if (timers) {
struct timemono now, first;
@@ -417,6 +414,10 @@ void *io_loop(struct timers *timers, struct timer **expired)
}
}
+ /* Don't wait if we have always requests pending! */
+ if (num_always != 0)
+ ms_timeout = 0;
+
/* We do this temporarily, assuming exclusive is unusual */
exclude_pollfds();
r = pollfn(pollfds, num_fds, ms_timeout);
@@ -430,15 +431,29 @@ void *io_loop(struct timers *timers, struct timer **expired)
break;
}
- for (i = 0; i < num_fds && !io_loop_return; i++) {
- struct io_conn *c = (void *)fds[i];
- int events = pollfds[i].revents;
+ fairness_counter++;
+ for (size_t rotation = 0; rotation < num_fds && !io_loop_return; rotation++) {
+ struct io_conn *c;
+ int events;
+
+ i = (rotation + fairness_counter) % num_fds;
+ c = (void *)fds[i];
/* Clear so we don't get confused if exclusive next time */
+ events = pollfds[i].revents;
pollfds[i].revents = 0;
- if (r == 0)
+ /* Timeout? */
+ if (r == 0) {
+ handle_always();
break;
+ }
+
+ /* We interleave always before the first fd */
+ if (i == 0 && handle_always()) {
+ /* Could have started/finished more. */
+ break;
+ }
if (fds[i]->listener) {
struct io_listener *l = (void *)fds[i];
Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.