diff -Naurp pcp-5.3.7.orig/src/libpcp_web/src/load.h pcp-5.3.7/src/libpcp_web/src/load.h --- pcp-5.3.7.orig/src/libpcp_web/src/load.h 2021-02-17 15:27:41.000000000 +1100 +++ pcp-5.3.7/src/libpcp_web/src/load.h 2024-09-09 13:45:56.531933622 +1000 @@ -42,8 +42,9 @@ typedef struct context { unsigned int setup : 1; /* context established */ unsigned int cached : 1; /* context/source in cache */ unsigned int garbage : 1; /* context pending removal */ + unsigned int inactive: 1; /* context removal deferred */ unsigned int updated : 1; /* context labels are updated */ - unsigned int padding : 4; /* zero-filled struct padding */ + unsigned int padding : 3; /* zero-filled struct padding */ unsigned int refcount : 16; /* currently-referenced counter */ unsigned int timeout; /* context timeout in milliseconds */ uv_timer_t timer; diff -Naurp pcp-5.3.7.orig/src/libpcp_web/src/webgroup.c pcp-5.3.7/src/libpcp_web/src/webgroup.c --- pcp-5.3.7.orig/src/libpcp_web/src/webgroup.c 2024-09-09 13:44:34.166748200 +1000 +++ pcp-5.3.7/src/libpcp_web/src/webgroup.c 2024-09-09 13:45:56.531933622 +1000 @@ -134,9 +134,18 @@ webgroup_timeout_context(uv_timer_t *arg * is returned to zero by the caller, or background cleanup * finds this context and cleans it. */ - if (cp->refcount == 0 && cp->garbage == 0) { - cp->garbage = 1; - uv_timer_stop(&cp->timer); + if (cp->refcount == 0) { + if (cp->garbage == 0) { + cp->garbage = 1; + uv_timer_stop(&cp->timer); + } + } else { + /* + * Context timed out but still referenced, must wait + * until the caller releases its reference (shortly) + * before beginning garbage collection process. + */ + cp->inactive = 1; } } @@ -298,20 +307,28 @@ webgroup_garbage_collect(struct webgroup dictIterator *iterator; dictEntry *entry; context_t *cp; - unsigned int count = 0, drops = 0; + unsigned int count = 0, drops = 0, garbageset = 0, inactiveset = 0; if (pmDebugOptions.http || pmDebugOptions.libweb) - fprintf(stderr, "%s: started\n", "webgroup_garbage_collect"); + fprintf(stderr, "%s: started for groups %p\n", + "webgroup_garbage_collect", groups); /* do context GC if we get the lock (else don't block here) */ if (uv_mutex_trylock(&groups->mutex) == 0) { iterator = dictGetSafeIterator(groups->contexts); for (entry = dictNext(iterator); entry;) { cp = (context_t *)dictGetVal(entry); + if (cp->privdata != groups) + continue; entry = dictNext(iterator); - if (cp->garbage && cp->privdata == groups) { + if (cp->garbage) + garbageset++; + if (cp->inactive && cp->refcount == 0) + inactiveset++; + if (cp->garbage || (cp->inactive && cp->refcount == 0)) { if (pmDebugOptions.http || pmDebugOptions.libweb) - fprintf(stderr, "GC context %u (%p)\n", cp->randomid, cp); + fprintf(stderr, "GC dropping context %u (%p)\n", + cp->randomid, cp); uv_mutex_unlock(&groups->mutex); webgroup_drop_context(cp, groups); uv_mutex_lock(&groups->mutex); @@ -324,7 +341,8 @@ webgroup_garbage_collect(struct webgroup /* if dropping the last remaining context, do cleanup */ if (groups->active && drops == count) { if (pmDebugOptions.http || pmDebugOptions.libweb) - fprintf(stderr, "%s: freezing\n", "webgroup_garbage_collect"); + fprintf(stderr, "%s: freezing groups %p\n", + "webgroup_garbage_collect", groups); webgroup_timers_stop(groups); } uv_mutex_unlock(&groups->mutex); @@ -334,8 +352,10 @@ webgroup_garbage_collect(struct webgroup mmv_set(groups->map, groups->metrics[WEBGROUP_GC_COUNT], &count); if (pmDebugOptions.http || pmDebugOptions.libweb) - fprintf(stderr, "%s: finished [%u drops from %u entries]\n", - "webgroup_garbage_collect", drops, count); + fprintf(stderr, "%s: finished [%u drops from %u entries," + " %u garbageset, %u inactiveset]\n", + "webgroup_garbage_collect", drops, count, + garbageset, inactiveset); } static void @@ -354,7 +374,7 @@ webgroup_use_context(struct context *cp, int sts; struct webgroups *gp = (struct webgroups *)cp->privdata; - if (cp->garbage == 0) { + if (cp->garbage == 0 && cp->inactive == 0) { if (cp->setup == 0) { if ((sts = pmReconnectContext(cp->context)) < 0) { infofmt(*message, "cannot reconnect context: %s", @@ -424,7 +444,7 @@ webgroup_lookup_context(pmWebGroupSettin *status = -ENOTCONN; return NULL; } - if (cp->garbage == 0) { + if (cp->garbage == 0 && cp->inactive == 0) { access.username = cp->username; access.password = cp->password; access.realm = cp->realm;