diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2023-07-12 15:02:39 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2023-07-12 15:02:39 -0700 |
commit | d300ae29bc3af249374c668c4a67b8aaa153d405 (patch) | |
tree | e26168a1ae2fcb41d1b3d8232eb2b37e8c3dba85 /src | |
parent | 3c244f304dd3f2a7050c5313e412ded0315bfb0c (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')
-rw-r--r-- | src/til_stream.c | 59 |
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); } |