[master] f72dcc886 Allow VEV_Stop() called from within a VEV callback

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Wed Jul 3 09:32:08 UTC 2024


commit f72dcc8860547a3fa48f43d6ea0a3d65c1e8a5b3
Author: Dag Haavi Finstad <daghf at varnish-software.com>
Date:   Fri Jun 14 12:58:02 2024 +0200

    Allow VEV_Stop() called from within a VEV callback
    
    The routine in VEV looping to report on all of the fd events gets confused
    if an event is removed while in another callback event.
    
    This will typically cause the mgt event loop to just spin, making the
    manager unresponsive.
    
    Original patch and commit message by Martin Blix Grydeland.

diff --git a/lib/libvarnish/vev.c b/lib/libvarnish/vev.c
index aacdbbb23..8ce5837fb 100644
--- a/lib/libvarnish/vev.c
+++ b/lib/libvarnish/vev.c
@@ -67,6 +67,7 @@ static int			vev_nsig;
 struct vev_root {
 	unsigned		magic;
 #define VEV_BASE_MAGIC		0x477bcf3d
+	unsigned		n_fd_events;
 	struct pollfd		*pfd;
 	struct vev		**pev;
 	unsigned		npfd;
@@ -325,6 +326,12 @@ VEV_Stop(struct vev_root *evb, struct vev *e)
 	assert(e->__binheap_idx == VBH_NOIDX);
 	evb->lpfd--;
 
+	if (e->fd_events) {
+		assert(evb->n_fd_events > 0);
+		evb->n_fd_events--;
+		e->fd_events = 0;
+	}
+
 	if (e->sig > 0) {
 		assert(e->sig < vev_nsig);
 		es = &vev_sigs[e->sig];
@@ -409,6 +416,7 @@ VEV_Once(struct vev_root *evb)
 	struct vev *e;
 	int i, k, tmo, retval = 1;
 	unsigned u;
+	int progress;
 
 	CHECK_OBJ_NOTNULL(evb, VEV_BASE_MAGIC);
 	assert(pthread_equal(evb->thread, pthread_self()));
@@ -447,16 +455,18 @@ VEV_Once(struct vev_root *evb)
 			return (vev_sched_timeout(evb, e, t));
 	}
 
-	k = 0;
+	AZ(evb->n_fd_events);
 	for (u = 1; u < evb->lpfd; u++) {
+		AZ(evb->pev[u]->fd_events);
 		evb->pev[u]->fd_events = evb->pfd[u].revents;
 		if (evb->pev[u]->fd_events)
-			k++;
+			evb->n_fd_events++;
 	}
-	assert(k == i);
+	assert(evb->n_fd_events == i);
 
 	DBG(evb, "EVENTS %d\n", i);
-	while (i > 0) {
+	while (evb->n_fd_events > 0) {
+		progress = 0;
 		for (u = VBH_NOIDX + 1; u < evb->lpfd; u++) {
 			e = evb->pev[u];
 			if (e->fd_events == 0)
@@ -465,7 +475,9 @@ VEV_Once(struct vev_root *evb)
 			    e, u, e->fd, e->fd_events, i);
 			k = e->callback(e, e->fd_events);
 			e->fd_events = 0;
-			i--;
+			assert(evb->n_fd_events > 0);
+			evb->n_fd_events--;
+			progress++;
 			if (k) {
 				VEV_Stop(evb, e);
 				free(e);
@@ -473,7 +485,8 @@ VEV_Once(struct vev_root *evb)
 			if (k < 0)
 				retval = k;
 		}
+		assert(progress > 0);
 	}
-	AZ(i);
+
 	return (retval);
 }


More information about the varnish-commit mailing list