Commit 04ac7e0e37 for frr

commit 04ac7e0e3771bd6931c317f1d7f65a12536f7fa9
Author: Donald Sharp <sharpd@nvidia.com>
Date:   Mon Oct 5 19:24:41 2026 -0400

    lib: Fix crash in event.c on FreeBSD

    lib/event.c is crashing on freebsd in bgpd:

    6  0x0000000828503fda in thr_kill () from /lib/libsys.so.7
    7  0x000000082633ae74 in raise () from /lib/libc.so.7
    8  0x00000008263edb29 in abort () from /lib/libc.so.7
    9  0x000000082591cbea in ?? () from /lib/libthr.so.3
    10 0x00000008259212d5 in ?? () from /lib/libthr.so.3
    11 0x0000000825920461 in pthread_mutex_lock () from /lib/libthr.so.3
    12 0x00000008216b585a in _frr_mtx_lock (mutex=0xdc2a0408978) at lib/frr_pthread.h:255
    13 _event_add_read_write (xref=<optimized out>, m=0xdc29e44ee40, func=0x4020f0 <bgp_process_reads>, arg=0xdc29fc33080, fd=66, t_ptr=0xdc29fc330c0) at lib/event.c:1397
    14 0x0000000000402562 in bgp_process_reads (event=<optimized out>) at bgpd/bgp_io.c:317
    15 0x00000008216b7660 in event_call (event=event@entry=0x82bb21f28) at lib/event.c:2744
    16 0x000000082164c686 in fpt_run (arg=0xdc29edf9e00) at lib/frr_pthread.c:386

    bgpd.err has this:

    Fatal error 'mutex 0x81191c73988 own 0x18c5f is on list 0x0 0x81191c69908' at line 151 in file /home/pkgbuild/worktrees/main/lib/libthr/thread/thr_mutex.c (errno = 35)

    Examination of the event code shows that FRR is copying the event in event_run, this includes a hard copy of the mutex.
    Then when add_unused is called it frees the mutex.  FreeBSD is noticing that the mutex is the same as something that
    was freed when we still have a copy of the mutex.  When making a copy of the event, hard clear the mutex in
    event_run.  Additionally the event->yield data was being protecteed (partially) by the event->mtx.  Convert
    the protection over to the master->mtx as that it is protecting the event->yield values in all the other
    spots.  So let's just use that.

    Signed-off-by: Donald Sharp <sharpd@nvidia.com>

diff --git a/lib/event.c b/lib/event.c
index 0457f9d007..1ad0f3048b 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -865,17 +865,12 @@ void event_master_set_name(struct event_loop *master, const char *name)
 /* Move thread to unuse list. */
 static void thread_add_unuse(struct event_loop *m, struct event *event)
 {
-	pthread_mutex_t mtxc = event->mtx;
-
 	assert(m != NULL && event != NULL);

 	event->hist->total_active--;
 	memset(event, 0, sizeof(struct event));
 	event->type = EVENT_UNUSED;

-	/* Restore the event mutex context. */
-	event->mtx = mtxc;
-
 	if (event_list_count(&m->unuse) < EVENT_UNUSED_DEPTH) {
 		event_list_add_tail(&m->unuse, event);
 		return;
@@ -973,7 +968,7 @@ unsigned long event_timer_remain_msec(struct event *event)
 	if (!event_is_scheduled(event))
 		return 0;

-	frr_with_mutex (&event->mtx) {
+	frr_with_mutex (&event->master->mtx) {
 		remain = monotime_until(&event->u.sands, NULL) / 1000LL;
 	}

@@ -990,7 +985,7 @@ struct timeval event_timer_remain(struct event *event)
 {
 	struct timeval remain;

-	frr_with_mutex (&event->mtx) {
+	frr_with_mutex (&event->master->mtx) {
 		monotime_until(&event->u.sands, &remain);
 	}
 	return remain;
@@ -1031,11 +1026,8 @@ static struct event *event_get(struct event_loop *m, uint8_t type,
 {
 	struct event *event = event_list_pop(&m->unuse);

-	if (!event) {
+	if (!event)
 		event = XCALLOC(MTYPE_THREAD, sizeof(struct event));
-		/* mutex only needs to be initialized at struct creation. */
-		pthread_mutex_init(&event->mtx, NULL);
-	}

 	event->type = type;
 	event->add_type = type;
@@ -1073,7 +1065,6 @@ static struct event *event_get(struct event_loop *m, uint8_t type,
 static void thread_free(struct event_loop *master, struct event *event)
 {
 	/* Free allocated resources. */
-	pthread_mutex_destroy(&event->mtx);
 	XFREE(MTYPE_THREAD, event);
 }

@@ -1394,10 +1385,8 @@ void _event_add_read_write(const struct xref_eventsched *xref,
 		event = event_get(m, dir, func, arg, xref);

 		if (event) {
-			frr_with_mutex (&event->mtx) {
-				event->u.fd = fd;
-				thread_array[event->u.fd] = event;
-			}
+			event->u.fd = fd;
+			thread_array[event->u.fd] = event;

 			if (t_ptr) {
 				*t_ptr = event;
@@ -1439,13 +1428,11 @@ static void _event_add_timer_timeval(const struct xref_eventsched *xref,
 		/* default lateness warning: 4s */
 		event->tardy_threshold = TARDY_DEFAULT_THRESHOLD;

-		frr_with_mutex (&event->mtx) {
-			event->u.sands = t;
-			event_timer_list_add(&m->timer, event);
-			if (t_ptr) {
-				*t_ptr = event;
-				event->ref = t_ptr;
-			}
+		event->u.sands = t;
+		event_timer_list_add(&m->timer, event);
+		if (t_ptr) {
+			*t_ptr = event;
+			event->ref = t_ptr;
 		}

 		/* The timer list is sorted - if this new timer
@@ -1520,10 +1507,8 @@ void _event_add_event(const struct xref_eventsched *xref, struct event_loop *m,
 			break;

 		event = event_get(m, EVENT_EVENT, func, arg, xref);
-		frr_with_mutex (&event->mtx) {
-			event->u.val = val;
-			event_list_add_tail(&m->event, event);
-		}
+		event->u.val = val;
+		event_list_add_tail(&m->event, event);

 		if (t_ptr) {
 			*t_ptr = event;
@@ -2089,6 +2074,7 @@ static struct timeval *thread_timer_wait(struct event_timer_list_head *timers,
 static struct event *event_run(struct event_loop *m, struct event *event, struct event *fetch)
 {
 	*fetch = *event;
+
 	thread_add_unuse(m, event);
 	return fetch;
 }
@@ -2624,7 +2610,7 @@ int event_should_yield(struct event *event)
 {
 	int result;

-	frr_with_mutex (&event->mtx) {
+	frr_with_mutex (&event->master->mtx) {
 		result = monotime_since(&event->real, NULL)
 			 > (int64_t)event->yield;
 	}
@@ -2633,7 +2619,7 @@ int event_should_yield(struct event *event)

 void event_set_yield_time(struct event *event, unsigned long yield_time)
 {
-	frr_with_mutex (&event->mtx) {
+	frr_with_mutex (&event->master->mtx) {
 		event->yield = yield_time;
 	}
 }
@@ -2832,10 +2818,8 @@ void _event_execute(const struct xref_eventsched *xref, struct event_loop *m,
 		event = event_get(m, EVENT_EXECUTE, func, arg, xref);

 		/* Set its event value. */
-		frr_with_mutex (&event->mtx) {
-			event->u.val = val;
-			event->ref = &event;
-		}
+		event->u.val = val;
+		event->ref = &event;
 	}

 	/* Execute thread doing all accounting. */
diff --git a/lib/frrevent.h b/lib/frrevent.h
index 0e276249b3..86cd4a3a4c 100644
--- a/lib/frrevent.h
+++ b/lib/frrevent.h
@@ -90,7 +90,6 @@ struct event {
 	/* lateness warning threshold, usec.  0 if it's not a timer. */
 	unsigned long tardy_threshold;
 	const struct xref_eventsched *xref; /* origin location */
-	pthread_mutex_t mtx;		    /* mutex for thread.c functions */
 };

 /* rate limit late timer warnings */