summaryrefslogtreecommitdiff
path: root/src/til_stream.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2023-07-12 15:02:39 -0700
committerVito Caputo <vcaputo@pengaru.com>2023-07-12 15:02:39 -0700
commitd300ae29bc3af249374c668c4a67b8aaa153d405 (patch)
treee26168a1ae2fcb41d1b3d8232eb2b37e8c3dba85 /src/til_stream.c
parent3c244f304dd3f2a7050c5313e412ded0315bfb0c (diff)
til_stream: loop gc passes until nothing gets freed
Due to how meta-modules reference other modules from within their context, they pin the related refcounts until their gc is performed. So repeat the gc passess until nothing gets freed, to gc those recursive references immediately. Fortunately this isn't intended to be done at perf-sensitive times...
Diffstat (limited to 'src/til_stream.c')
-rw-r--r--src/til_stream.c59
1 files changed, 33 insertions, 26 deletions
diff --git a/src/til_stream.c b/src/til_stream.c
index f6cf987..aeab4b7 100644
--- a/src/til_stream.c
+++ b/src/til_stream.c
@@ -640,6 +640,8 @@ int til_stream_find_module_contexts(til_stream_t *stream, const char *path, size
void til_stream_gc_module_contexts(til_stream_t *stream)
{
+ unsigned freed;
+
assert(stream);
/* This may not remain long-term, but there's no current way to unregister contexts - and by
@@ -656,39 +658,44 @@ void til_stream_gc_module_contexts(til_stream_t *stream)
* very tentative and mostly just to keep "rtv" from meltdown while the dust settles on the rkt
* front.
*/
- for (size_t b = 0; b < TIL_STREAM_CTXT_BUCKETS_COUNT; b++) {
- til_stream_module_context_t *c, *c_prev, *c_next;
+ do {
+ freed = 0;
- for (c = stream->module_context_buckets[b], c_prev = NULL; c != NULL; c = c_next) {
- size_t i;
+ for (size_t b = 0; b < TIL_STREAM_CTXT_BUCKETS_COUNT; b++) {
+ til_stream_module_context_t *c, *c_prev, *c_next;
- c_next = c->next;
+ for (c = stream->module_context_buckets[b], c_prev = NULL; c != NULL; c = c_next) {
+ size_t i;
- for (i = 0; i < c->n_module_contexts; i++) {
- if (c->module_contexts[i]->refcount != 1)
- break;
- }
+ c_next = c->next;
- if (i < c->n_module_contexts) {
- c_prev = c;
- continue;
- }
+ for (i = 0; i < c->n_module_contexts; i++) {
+ if (c->module_contexts[i]->refcount != 1)
+ break;
+ }
- /* if all the contexts in the set are rc=1, that implies they're only on-stream
- * and not actively referenced by any user, so we "gc" them.
- */
- { /* free(stream_module_context_t) */
- for (i = 0; i < c->n_module_contexts; i++)
- c->module_contexts[i] = til_module_context_free(c->module_contexts[i]);
- free(c);
- }
+ if (i < c->n_module_contexts) {
+ c_prev = c;
+ continue;
+ }
+
+ /* if all the contexts in the set are rc=1, that implies they're only on-stream
+ * and not actively referenced by any user, so we "gc" them.
+ */
+ { /* free(stream_module_context_t) */
+ for (i = 0; i < c->n_module_contexts; i++)
+ c->module_contexts[i] = til_module_context_free(c->module_contexts[i]);
+ free(c);
+ freed = 1;
+ }
- if (c_prev)
- c_prev->next = c_next;
- else
- stream->module_context_buckets[b] = c_next;
+ if (c_prev)
+ c_prev->next = c_next;
+ else
+ stream->module_context_buckets[b] = c_next;
+ }
}
- }
+ } while (freed);
}
© All Rights Reserved