Fix race condition when loading multiple File/Asset Browsers at once

When multiple File or Asset Browsers would load at once (e.g. when loading a
file with two File Browsers open) and they would load multiple directories or
.blend files (using the Recursions option in the File Browser or loading an
asset library with multiple .blends), often only one File/Asset Browser would
correctly load all files. Others would be incomplete or entirely empty. That
was because of a race condition, where the directories or .blend files would be
loaded concurrently and the first one that finished would cancel the other
ones. This again happened because they used the job system with the same
"owner", which by design makes all jobs with the same owner cancel as soon as
the first is finished.
Address this by making sure they have different owners. That is, not the scene
anymore, but the filelist the job belongs to. Doesn't make much sense to use
the scene as owner for scene-unrelated file loading anyway.

Steps to reproduce were:
* Open two File Browsers as regular editors.
* In the Display Settings popover, set "Recursions" to 2 or 3 levels.
* Navigate to a directory with plenty of subdirectories in both File Browsers.
* Save the file.
* Reload the file, one of the File Browsers likely has an incomplete file list.

Alternatively, use Asset Browsers and open an asset library containing multiple
.blends.
This commit is contained in:
Julian Eisel 2021-07-01 15:09:08 +02:00
parent a112adf16a
commit 4617172740
8 changed files with 25 additions and 33 deletions

View File

@ -136,13 +136,9 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
void ED_fileselect_clear(struct wmWindowManager *wm,
struct Scene *owner_scene,
struct SpaceFile *sfile);
void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile);
void ED_fileselect_exit(struct wmWindowManager *wm,
struct Scene *owner_scene,
struct SpaceFile *sfile);
void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
@ -166,7 +162,7 @@ int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);
void ED_file_change_dir_ex(struct bContext *C, struct bScreen *screen, struct ScrArea *area);
void ED_file_change_dir_ex(struct bContext *C, struct ScrArea *area);
void ED_file_change_dir(struct bContext *C);
void ED_file_path_button(struct bScreen *screen,

View File

@ -552,7 +552,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
}
/* to make sure we show what is on disk */
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
}
ED_region_tag_redraw(region);

View File

@ -1882,7 +1882,7 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
/* refresh system directory menu */
fsmenu_refresh_system_category(fsmenu);
@ -2360,7 +2360,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op)
sfile->scroll_offset = 0;
/* reload dir to make sure we're seeing what's in the directory */
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
if (do_diropen) {
BLI_strncpy(params->dir, path, sizeof(params->dir));
@ -2611,7 +2611,7 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
if (params) {
params->flag ^= FILE_HIDE_DOT;
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@ -2908,7 +2908,7 @@ static int file_delete_exec(bContext *C, wmOperator *op)
}
}
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;

View File

@ -3505,7 +3505,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
/* setup job */
wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
CTX_data_scene(C),
filelist,
"Listing Dirs...",
WM_JOB_PROGRESS,
WM_JOB_TYPE_FILESEL_READDIR);
@ -3521,12 +3521,12 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene)
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
{
WM_jobs_kill_type(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR);
WM_jobs_kill_type(wm, filelist, WM_JOB_TYPE_FILESEL_READDIR);
}
int filelist_readjob_running(wmWindowManager *wm, Scene *owner_scene)
int filelist_readjob_running(FileList *filelist, wmWindowManager *wm)
{
return WM_jobs_test(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR);
return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_READDIR);
}

View File

@ -141,8 +141,8 @@ bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group);
void filelist_freelib(struct FileList *filelist);
void filelist_readjob_start(struct FileList *filelist, const struct bContext *C);
void filelist_readjob_stop(struct wmWindowManager *wm, struct Scene *owner_scene);
int filelist_readjob_running(struct wmWindowManager *wm, struct Scene *owner_scene);
void filelist_readjob_stop(struct FileList *filelist, struct wmWindowManager *wm);
int filelist_readjob_running(struct FileList *filelist, struct wmWindowManager *wm);
bool filelist_cache_previews_update(struct FileList *filelist);
void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);

View File

@ -1047,7 +1047,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *region)
* Support updating the directory even when this isn't the active space
* needed so RNA properties update function isn't context sensitive, see T70255.
*/
void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area)
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
{
/* May happen when manipulating non-active spaces. */
if (UNLIKELY(area->spacetype != SPACE_FILE)) {
@ -1057,10 +1057,7 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area)
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
if (params) {
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
if (LIKELY(scene != NULL)) {
ED_fileselect_clear(wm, scene, sfile);
}
ED_fileselect_clear(wm, sfile);
/* Clear search string, it is very rare to want to keep that filter while changing dir,
* and usually very annoying to keep it actually! */
@ -1085,9 +1082,8 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area)
void ED_file_change_dir(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ED_file_change_dir_ex(C, screen, area);
ED_file_change_dir_ex(C, area);
}
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file)
@ -1183,11 +1179,11 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
return match;
}
void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfile)
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
{
/* only NULL in rare cases - T29734. */
if (sfile->files) {
filelist_readjob_stop(wm, owner_scene);
filelist_readjob_stop(sfile->files, wm);
filelist_freelib(sfile->files);
filelist_clear(sfile->files);
}
@ -1197,7 +1193,7 @@ void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfi
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfile)
void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
{
if (!sfile) {
return;
@ -1224,7 +1220,7 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil
folder_history_list_free(sfile);
if (sfile->files) {
ED_fileselect_clear(wm, owner_scene, sfile);
ED_fileselect_clear(wm, sfile);
filelist_free(sfile->files);
MEM_freeN(sfile->files);
sfile->files = NULL;

View File

@ -206,7 +206,7 @@ static void file_exit(wmWindowManager *wm, ScrArea *area)
sfile->previews_timer = NULL;
}
ED_fileselect_exit(wm, NULL, sfile);
ED_fileselect_exit(wm, sfile);
}
static SpaceLink *file_duplicate(SpaceLink *sl)
@ -360,7 +360,7 @@ static void file_refresh(const bContext *C, ScrArea *area)
sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir);
if (filelist_needs_force_reset(sfile->files)) {
filelist_readjob_stop(wm, CTX_data_scene(C));
filelist_readjob_stop(sfile->files, wm);
filelist_clear(sfile->files);
}

View File

@ -2980,7 +2980,7 @@ static void rna_FileBrowser_FSMenu_active_range(PointerRNA *UNUSED(ptr),
static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *ptr)
{
ScrArea *area = rna_area_from_space(ptr);
ED_file_change_dir_ex(C, (bScreen *)ptr->owner_id, area);
ED_file_change_dir_ex(C, area);
}
static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr)