diff --git a/src/dusk/asset/asset.c b/src/dusk/asset/asset.c index aa55e948..791d016c 100644 --- a/src/dusk/asset/asset.c +++ b/src/dusk/asset/asset.c @@ -82,17 +82,23 @@ errorret_t assetRequireLoaded(assetentry_t *entry) { assertNotNull(entry, "Entry cannot be NULL."); assertTrue(entry->type != ASSET_LOADER_TYPE_NULL, "Invalid loader type."); - // Already loaded? if(entry->state == ASSET_ENTRY_STATE_LOADED) { errorOk(); } - // Not loaded, just spin the wheel + // Lock to prevent the reaper from collecting the entry mid-spin. + assetEntryLock(entry); + while(entry->state != ASSET_ENTRY_STATE_LOADED) { usleep(1000); - errorChain(assetUpdate()); + errorret_t ret = assetUpdate(); + if(errorIsNotOk(ret)) { + assetEntryUnlock(entry); + errorChain(ret); + } } + assetEntryUnlock(entry); errorOk(); } @@ -246,9 +252,9 @@ errorret_t assetUpdate(void) { } while(loading < ASSET.loading + ASSET_LOADING_COUNT_MAX); - // Reap entries that have no external locks (refs.count == 1 means only the - // system hold remains). Only safe to reap LOADED and NOT_STARTED states — - // mid-load entries are left for the next cycle. + // Reap entries that have no external locks (refs.count == 0) AND have been + // explicitly locked at least once. Entries that were never locked are left + // alone — raw-pointer callers hold no ref but should not lose the entry. entry = ASSET.entries; do { if(entry->state != ASSET_ENTRY_STATE_LOADED) { @@ -261,6 +267,11 @@ errorret_t assetUpdate(void) { continue; } + if(!entry->wasLocked) { + entry++; + continue; + } + if(entry->refs.count > 0) { entry++; continue; diff --git a/src/dusk/asset/loader/assetentry.c b/src/dusk/asset/loader/assetentry.c index cd86105f..c8a815b7 100644 --- a/src/dusk/asset/loader/assetentry.c +++ b/src/dusk/asset/loader/assetentry.c @@ -33,6 +33,7 @@ void assetEntryInit( void assetEntryLock(assetentry_t *entry) { assertNotNull(entry, "Entry cannot be NULL"); assertTrue(entry->type != ASSET_LOADER_TYPE_NULL, "Invalid loader type."); + entry->wasLocked = true; refLock(&entry->refs); } diff --git a/src/dusk/asset/loader/assetentry.h b/src/dusk/asset/loader/assetentry.h index aa346948..ab8c38ca 100644 --- a/src/dusk/asset/loader/assetentry.h +++ b/src/dusk/asset/loader/assetentry.h @@ -30,6 +30,11 @@ typedef struct assetentry_s { assetentrystate_t state; // What is referencing this asset entry. ref_t refs; + // True once assetEntryLock has been called at least once. The reaper only + // collects entries that have been explicitly locked (and later unlocked to + // zero). Entries that nobody has ever locked are left alone so raw-pointer + // callers (tests, requireLoaded before locking) are not surprised. + bool_t wasLocked; // Data that will be passed to the loader about how it should load. assetloaderinput_t *input; } assetentry_t;