Commit 7303f286ca for asterisk.org
commit 7303f286ca291e1d7ec028e4e94e00ce5bf11014
Author: phoneben <3232963@gmail.com>
Date: Mon Oct 26 14:12:15 2026 +0200
manager.c: Don't block the AMI accept thread on busy session locks.
manager.c: Don't block the AMI accept thread on busy session locks.
new AMI connections can stall under load.
purge_sessions() runs from the AMI accept loop and took every
session's lock while looking for expired HTTP sessions. A session
thread holding its lock (for example while writing events to a slow
client) stalled the accept thread, so new AMI connections queued up
and could overflow the listen queue.
Use ao2_trylock() and skip sessions that are currently locked. Expired
session cleanup is opportunistic; a skipped session is checked again
on a later pass.
Assisted-by: Claude (Anthropic AI assistant)
Resolves: #2248
diff --git a/main/manager.c b/main/manager.c
index 6ffa7e3484..3ea06efd7d 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -7532,7 +7532,17 @@ static int purge_sessions(int n_max)
/* The order of operations is significant */
while (n_max > 0 && (session = ao2_iterator_next(&i))) {
- ao2_lock(session);
+ /*
+ * This runs in the AMI accept thread. Only HTTP sessions have a
+ * session timeout, so skip non-HTTP sessions (managerid of zero)
+ * without taking their lock. If an HTTP session is locked by another
+ * thread, skip it rather than stall new connections; cleanup is
+ * opportunistic and it will be examined again on a later pass.
+ */
+ if (!session->managerid || ao2_trylock(session)) {
+ unref_mansession(session);
+ continue;
+ }
if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
if (session->authenticated
&& VERBOSITY_ATLEAST(2)