Fix T63748: Long startups after network drives are disconnected.
authorBastien Montagne <montagne29@wanadoo.fr>
Wed, 15 May 2019 14:20:14 +0000 (16:20 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Wed, 15 May 2019 14:26:47 +0000 (16:26 +0200)
We need to make those paths validation async, since some infamous OS is
unable to provide a quick way to check whether a path is valid or not...

Not much to say here, this is basic wmJob stuff really... We don’t even
need complex threaded coordination locks or atomics, given how simple
the changes are here.

Fake-tested with some `sleep()` calls to add atificial delay, seems to
work as expected.

source/blender/editors/space_file/file_ops.c
source/blender/editors/space_file/fsmenu.c
source/blender/editors/space_file/fsmenu.h
source/blender/editors/space_file/space_file.c
source/blender/windowmanager/WM_api.h

index 674735f..5ac7ff7 100644 (file)
@@ -1011,7 +1011,7 @@ static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
     BLI_make_file_string(
         "/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
     fsmenu_write_file(fsmenu, name);
-    fsmenu_refresh_bookmarks_status(fsmenu);
+    fsmenu_refresh_bookmarks_status(CTX_wm_manager(C), fsmenu);
     ED_area_tag_refresh(sa);
     ED_area_tag_redraw(sa);
   }
@@ -1567,6 +1567,9 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
   /* refresh system directory menu */
   fsmenu_refresh_system_category(fsmenu);
 
+  /* Update bookmarks 'valid' state. */
+  fsmenu_refresh_bookmarks_status(wm, fsmenu);
+
   WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
 
   return OPERATOR_FINISHED;
index 38423a8..25187d5 100644 (file)
@@ -35,6 +35,9 @@
 
 #include "ED_fileselect.h"
 
+#include "WM_api.h"
+#include "WM_types.h"
+
 #ifdef WIN32
 /* Need to include windows.h so _WIN32_IE is defined. */
 #  include <windows.h>
@@ -721,31 +724,59 @@ void fsmenu_refresh_system_category(struct FSMenu *fsmenu)
   fsmenu_read_system(fsmenu, true);
 }
 
-void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu)
+static void fsmenu_free_ex(FSMenu **fsmenu)
 {
-  int categories[] = {
-      FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT};
-  int i;
-
-  for (i = sizeof(categories) / sizeof(*categories); i--;) {
-    FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]);
-    for (; fsm_iter; fsm_iter = fsm_iter->next) {
-      fsmenu_entry_refresh_valid(fsm_iter);
-    }
+  if (*fsmenu != NULL) {
+    fsmenu_free_category(*fsmenu, FS_CATEGORY_SYSTEM);
+    fsmenu_free_category(*fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS);
+    fsmenu_free_category(*fsmenu, FS_CATEGORY_BOOKMARKS);
+    fsmenu_free_category(*fsmenu, FS_CATEGORY_RECENT);
+    MEM_freeN(*fsmenu);
   }
+
+  *fsmenu = NULL;
 }
 
 void fsmenu_free(void)
 {
-  if (g_fsmenu) {
-    fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM);
-    fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS);
-    fsmenu_free_category(g_fsmenu, FS_CATEGORY_BOOKMARKS);
-    fsmenu_free_category(g_fsmenu, FS_CATEGORY_RECENT);
-    MEM_freeN(g_fsmenu);
+  fsmenu_free_ex(&g_fsmenu);
+}
+
+static void fsmenu_copy_category(struct FSMenu *fsmenu_dst,
+                                 struct FSMenu *fsmenu_src,
+                                 const FSMenuCategory category)
+{
+  FSMenuEntry *fsm_dst_prev = NULL, *fsm_dst_head = NULL;
+  FSMenuEntry *fsm_src_iter = ED_fsmenu_get_category(fsmenu_src, category);
+
+  for (; fsm_src_iter != NULL; fsm_src_iter = fsm_src_iter->next) {
+    FSMenuEntry *fsm_dst = MEM_dupallocN(fsm_src_iter);
+    if (fsm_dst->path != NULL) {
+      fsm_dst->path = MEM_dupallocN(fsm_dst->path);
+    }
+
+    if (fsm_dst_prev != NULL) {
+      fsm_dst_prev->next = fsm_dst;
+    }
+    else {
+      fsm_dst_head = fsm_dst;
+    }
+    fsm_dst_prev = fsm_dst;
   }
 
-  g_fsmenu = NULL;
+  ED_fsmenu_set_category(fsmenu_dst, category, fsm_dst_head);
+}
+
+static FSMenu *fsmenu_copy(FSMenu *fsmenu)
+{
+  FSMenu *fsmenu_copy = MEM_dupallocN(fsmenu);
+
+  fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_SYSTEM);
+  fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_SYSTEM_BOOKMARKS);
+  fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_BOOKMARKS);
+  fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_RECENT);
+
+  return fsmenu_copy;
 }
 
 int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir)
@@ -761,3 +792,99 @@ int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory categor
 
   return -1;
 }
+
+/* Thanks to some bookmarks sometimes being network drives that can have tens of seconds of delay
+ * before being defined as unreachable by the OS, we need to validate the bookmarks in an async
+ * job...
+ */
+static void fsmenu_bookmark_validate_job_startjob(void *fsmenuv,
+                                                  short *stop,
+                                                  short *do_update,
+                                                  float *UNUSED(progress))
+{
+  FSMenu *fsmenu = fsmenuv;
+
+  int categories[] = {
+      FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT};
+
+  for (size_t i = ARRAY_SIZE(categories); i--;) {
+    FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]);
+    for (; fsm_iter; fsm_iter = fsm_iter->next) {
+      if (*stop) {
+        return;
+      }
+      /* Note that we do not really need atomics primitives or thread locks here, since this only
+       * sets one short, which is assumed to be 'atomic'-enough for us here. */
+      fsmenu_entry_refresh_valid(fsm_iter);
+      *do_update = true;
+    }
+  }
+}
+
+static void fsmenu_bookmark_validate_job_update(void *fsmenuv)
+{
+  FSMenu *fsmenu_job = fsmenuv;
+
+  int categories[] = {
+      FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT};
+
+  for (size_t i = ARRAY_SIZE(categories); i--;) {
+    FSMenuEntry *fsm_iter_src = ED_fsmenu_get_category(fsmenu_job, categories[i]);
+    FSMenuEntry *fsm_iter_dst = ED_fsmenu_get_category(ED_fsmenu_get(), categories[i]);
+    for (; fsm_iter_dst != NULL; fsm_iter_dst = fsm_iter_dst->next) {
+      while (fsm_iter_src != NULL && !STREQ(fsm_iter_dst->path, fsm_iter_src->path)) {
+        fsm_iter_src = fsm_iter_src->next;
+      }
+      if (fsm_iter_src == NULL) {
+        return;
+      }
+      fsm_iter_dst->valid = fsm_iter_src->valid;
+    }
+  }
+}
+
+static void fsmenu_bookmark_validate_job_end(void *fsmenuv)
+{
+  /* In case there would be some dangling update... */
+  fsmenu_bookmark_validate_job_update(fsmenuv);
+}
+
+static void fsmenu_bookmark_validate_job_free(void *fsmenuv)
+{
+  FSMenu *fsmenu = fsmenuv;
+  fsmenu_free_ex(&fsmenu);
+}
+
+static void fsmenu_bookmark_validate_job_start(wmWindowManager *wm)
+{
+  wmJob *wm_job;
+  FSMenu *fsmenu_job = fsmenu_copy(g_fsmenu);
+
+  /* setup job */
+  wm_job = WM_jobs_get(
+      wm, wm->winactive, wm, "Validating Bookmarks...", 0, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE);
+  WM_jobs_customdata_set(wm_job, fsmenu_job, fsmenu_bookmark_validate_job_free);
+  WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
+  WM_jobs_callbacks(wm_job,
+                    fsmenu_bookmark_validate_job_startjob,
+                    NULL,
+                    fsmenu_bookmark_validate_job_update,
+                    fsmenu_bookmark_validate_job_end);
+
+  /* start the job */
+  WM_jobs_start(wm, wm_job);
+}
+
+static void fsmenu_bookmark_validate_job_stop(wmWindowManager *wm)
+{
+  WM_jobs_kill_type(wm, wm, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE);
+}
+
+void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu)
+{
+  BLI_assert(fsmenu == ED_fsmenu_get());
+  UNUSED_VARS_NDEBUG(fsmenu);
+
+  fsmenu_bookmark_validate_job_stop(wm);
+  fsmenu_bookmark_validate_job_start(wm);
+}
index cb0dccf..d9850cb 100644 (file)
@@ -68,7 +68,7 @@ void fsmenu_free(void);
 void fsmenu_refresh_system_category(struct FSMenu *fsmenu);
 
 /** Refresh 'valid' status of all menu entries */
-void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu);
+void fsmenu_refresh_bookmarks_status(struct wmWindowManager *wm, struct FSMenu *fsmenu);
 
 /** Get active index based on given directory. */
 int fsmenu_get_active_indices(struct FSMenu *fsmenu,
index 9fb0704..1fd878e 100644 (file)
@@ -142,18 +142,16 @@ static void file_free(SpaceLink *sl)
 }
 
 /* spacetype; init callback, area size changes, screen set, etc */
-static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void file_init(wmWindowManager *wm, ScrArea *sa)
 {
   SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+  struct FSMenu *fsmenu = ED_fsmenu_get();
 
   /* refresh system directory list */
-  fsmenu_refresh_system_category(ED_fsmenu_get());
+  fsmenu_refresh_system_category(fsmenu);
 
-  /* Update bookmarks 'valid' state.
-   * Done here, because it seems BLI_is_dir() can have huge impact on performances
-   * in some cases, on win systems... See T43684.
-   */
-  fsmenu_refresh_bookmarks_status(ED_fsmenu_get());
+  /* Update bookmarks 'valid' state. */
+  fsmenu_refresh_bookmarks_status(wm, fsmenu);
 
   if (sfile->layout) {
     sfile->layout->dirty = true;
index 780add8..bd02a1e 100644 (file)
@@ -661,6 +661,7 @@ enum {
   WM_JOB_TYPE_SHADER_COMPILATION,
   WM_JOB_TYPE_STUDIOLIGHT,
   WM_JOB_TYPE_LIGHT_BAKE,
+  WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE,
   /* add as needed, screencast, seq proxy build
    * if having hard coded values is a problem */
 };