avoid mid-scope change to reloaded sprite

This commit is contained in:
jacob 2025-05-14 14:05:21 -05:00
parent 885652082d
commit 8310bba397

View File

@ -91,6 +91,7 @@ struct cache_entry {
struct cache_bin { struct cache_bin {
struct sys_mutex mutex; struct sys_mutex mutex;
struct cache_entry *first; struct cache_entry *first;
struct cache_entry *last;
}; };
struct cache { struct cache {
@ -798,58 +799,44 @@ INTERNAL struct sprite_scope_cache_ref *cache_entry_lookup_touch(struct sprite_s
__prof; __prof;
struct sprite_scope_cache_ref *scope_ref = NULL; struct sprite_scope_cache_ref *scope_ref = NULL;
struct cache_entry *entry = NULL;
struct cache_entry *nonmatching = NULL;
struct cache_entry **nonmatching_next = NULL;
struct cache_entry_hash hash = cache_entry_hash_from_tag_hash(tag.hash, kind); struct cache_entry_hash hash = cache_entry_hash_from_tag_hash(tag.hash, kind);
u64 bin_index = hash.v % CACHE_BINS_COUNT; u64 bin_index = hash.v % CACHE_BINS_COUNT;
struct cache_bin *bin = &G.cache.bins[bin_index]; struct cache_bin *bin = &G.cache.bins[bin_index];
/* Lookup */ /* Lookup */
/* TODO: Spinlock */
{ {
struct sys_lock bin_lock = sys_mutex_lock_s(&bin->mutex); struct sys_lock bin_lock = sys_mutex_lock_s(&bin->mutex);
nonmatching_next = &bin->first; struct cache_entry *match = NULL;
entry = *nonmatching_next; for (struct cache_entry *entry = bin->first; entry; entry = entry->next_in_bin) {
while (entry) {
b32 match = false;
if (entry->hash.v == hash.v) { if (entry->hash.v == hash.v) {
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
scope_ref = scope_get_ref_or_null(scope, entry, bin_index, &bin_lock); b32 has_ref = scope_get_ref_or_null(scope, entry, bin_index, &bin_lock) != NULL;
if (scope_ref) { if (has_ref) {
match = true; match = entry;
} else { break;
if (atomic_i32_eval(&entry->out_of_date)) { } else if (!atomic_i32_eval(&entry->out_of_date)) {
/* If entry is out of date and the scope doesn't already hold a reference to it, then ignore entry */ match = entry;
} else {
match = true;
scope_ref = scope_ensure_ref(scope, entry, bin_index, &bin_lock);
}
} }
#else #else
scope_ref = scope_ensure_ref(scope, entry, ref_node, &bin_lock); match = entry;
match = true; break;
#endif #endif
} }
if (match) {
break;
} else {
nonmatching = entry;
nonmatching_next = &nonmatching->next_in_bin;
entry = *nonmatching_next;
} }
if (match) {
scope_ref = scope_ensure_ref(scope, match, bin_index, &bin_lock);
} }
sys_mutex_unlock(&bin_lock); sys_mutex_unlock(&bin_lock);
} }
/* Allocate new entry if necessary */ /* Allocate new entry if necessary */
if (!entry) { if (!scope_ref) {
__profscope(entry_lookup_allocate); __profscope(entry_lookup_allocate);
struct sys_lock bin_lock = sys_mutex_lock_e(&bin->mutex); struct sys_lock bin_lock = sys_mutex_lock_e(&bin->mutex);
{ {
/* Alloc entry */ /* Alloc entry */
struct cache_entry *entry = NULL;
{ {
struct sys_lock pool_lock = sys_mutex_lock_e(&G.cache.entry_pool_mutex); struct sys_lock pool_lock = sys_mutex_lock_e(&G.cache.entry_pool_mutex);
if (G.cache.entry_pool_first_free) { if (G.cache.entry_pool_first_free) {
@ -864,10 +851,14 @@ INTERNAL struct sprite_scope_cache_ref *cache_entry_lookup_touch(struct sprite_s
/* Init node and add to bin */ /* Init node and add to bin */
scope_ref = scope_ensure_ref(scope, entry, bin_index, &bin_lock); scope_ref = scope_ensure_ref(scope, entry, bin_index, &bin_lock);
*nonmatching_next = entry; {
if (nonmatching) { if (bin->last) {
nonmatching->next_in_bin = entry; bin->last->next_in_bin = entry;
entry->prev_in_bin = nonmatching; entry->prev_in_bin = bin->last;
} else {
bin->first = entry;
}
bin->last = entry;
} }
entry->hash = cache_entry_hash_from_tag_hash(tag.hash, kind); entry->hash = cache_entry_hash_from_tag_hash(tag.hash, kind);
entry->kind = kind; entry->kind = kind;
@ -1098,7 +1089,7 @@ INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, name)
{ {
for (struct cache_entry *n = bin->first; n; n = n->next_in_bin) { for (struct cache_entry *n = bin->first; n; n = n->next_in_bin) {
if (n->hash.v == hash.v) { if (n->hash.v == hash.v) {
logf_info("Sprite resource file \"%F\" has changed and will be reloaded.", FMT_STR(name)); logf_info("Sprite resource file \"%F\" has changed.", FMT_STR(name));
atomic_i32_eval_exchange(&n->out_of_date, 1); atomic_i32_eval_exchange(&n->out_of_date, 1);
} }
} }
@ -1218,13 +1209,17 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
/* Cache node has been referenced since scan, skip node. */ /* Cache node has been referenced since scan, skip node. */
} else if (cache_over_budget_target || last_ref_cycle == 0) { } else if (cache_over_budget_target || last_ref_cycle == 0) {
/* Remove from cache bin */ /* Remove from cache bin */
if (entry->prev_in_bin) { struct cache_entry *prev = entry->prev_in_bin;
entry->prev_in_bin->next_in_bin = entry->next_in_bin; struct cache_entry *next = entry->next_in_bin;
if (prev) {
prev->next_in_bin = next;
} else { } else {
bin->first = entry->next_in_bin; bin->first = next;
} }
if (entry->next_in_bin) { if (next) {
entry->next_in_bin->prev_in_bin = entry->prev_in_bin; next->prev_in_bin = prev;
} else {
bin->last = prev;
} }
atomic_u64_eval_add_i64(&G.cache.memory_usage, -((i64)entry->memory_usage)); atomic_u64_eval_add_i64(&G.cache.memory_usage, -((i64)entry->memory_usage));