@@ -3061,6 +3061,8 @@ void EditorHelp::_load_doc_thread(void *p_udata) {
30613061 }
30623062
30633063 OS::get_singleton ()->benchmark_end_measure (" EditorHelp" , vformat (" Generate Documentation (Run %d)" , doc_generation_count));
3064+
3065+ _worker_thread_done.set ();
30643066}
30653067
30663068void EditorHelp::_gen_doc_thread (void *p_udata) {
@@ -3094,6 +3096,8 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
30943096 }
30953097
30963098 OS::get_singleton ()->benchmark_end_measure (" EditorHelp" , vformat (" Generate Documentation (Run %d)" , doc_generation_count));
3099+
3100+ _worker_thread_done.set ();
30973101}
30983102
30993103void EditorHelp::_gen_extensions_docs () {
@@ -3109,6 +3113,10 @@ static void _load_script_doc_cache(bool p_changes) {
31093113}
31103114
31113115void EditorHelp::load_script_doc_cache () {
3116+ if (_cleanup_in_progress.is_set ()) {
3117+ return ;
3118+ }
3119+
31123120 if (!ProjectSettings::get_singleton ()->is_project_loaded ()) {
31133121 print_verbose (" Skipping loading script doc cache since no project is open." );
31143122 return ;
@@ -3132,6 +3140,7 @@ void EditorHelp::load_script_doc_cache() {
31323140 return ;
31333141 }
31343142
3143+ _worker_thread_done.set_to (false );
31353144 worker_thread.start (_load_script_doc_cache_thread, nullptr );
31363145}
31373146
@@ -3152,13 +3161,18 @@ void EditorHelp::_process_postponed_docs() {
31523161
31533162void EditorHelp::_load_script_doc_cache_thread (void *p_udata) {
31543163 ERR_FAIL_COND_MSG (!ProjectSettings::get_singleton ()->is_project_loaded (), " Error: cannot load script doc cache without a project." );
3164+ _worker_thread_done.set ();
3165+ return ;
31553166 ERR_FAIL_COND_MSG (!ResourceLoader::exists (get_script_doc_cache_full_path ()), " Error: cannot load script doc cache from inexistent file." );
3167+ _worker_thread_done.set ();
3168+ return ;
31563169
31573170 Ref<Resource> script_doc_cache_res = ResourceLoader::load (get_script_doc_cache_full_path (), " " , ResourceFormatLoader::CACHE_MODE_IGNORE );
31583171 if (script_doc_cache_res.is_null ()) {
31593172 print_verbose (" Script doc cache is corrupted. Regenerating it instead." );
31603173 _delete_script_doc_cache ();
31613174 callable_mp_static (EditorHelp::regenerate_script_doc_cache).call_deferred ();
3175+ _worker_thread_done.set ();
31623176 return ;
31633177 }
31643178
@@ -3175,6 +3189,8 @@ void EditorHelp::_load_script_doc_cache_thread(void *p_udata) {
31753189
31763190 // Always delete the doc cache after successful load since most uses of editor will change a script, invalidating cache.
31773191 _delete_script_doc_cache ();
3192+
3193+ _worker_thread_done.set ();
31783194}
31793195
31803196// / Helper method to deal with "sources_changed" signal having a parameter.
@@ -3183,6 +3199,10 @@ static void _regenerate_script_doc_cache(bool p_changes) {
31833199}
31843200
31853201void EditorHelp::regenerate_script_doc_cache () {
3202+ if (_cleanup_in_progress.is_set ()) {
3203+ return ;
3204+ }
3205+
31863206 if (EditorFileSystem::get_singleton ()->is_scanning ()) {
31873207 // Wait until EditorFileSystem scanning is complete to use updated filesystem structure.
31883208 EditorFileSystem::get_singleton ()->connect (SNAME (" sources_changed" ), callable_mp_static (_regenerate_script_doc_cache), CONNECT_ONE_SHOT );
@@ -3191,6 +3211,7 @@ void EditorHelp::regenerate_script_doc_cache() {
31913211
31923212 _wait_for_thread (worker_thread);
31933213 _wait_for_thread (loader_thread);
3214+ _loader_thread_done.set_to (false );
31943215 loader_thread.start (_regen_script_doc_thread, EditorFileSystem::get_singleton ()->get_filesystem ());
31953216}
31963217
@@ -3200,6 +3221,8 @@ void EditorHelp::_finish_regen_script_doc_thread(void *p_udata) {
32003221 _script_docs_loaded.set ();
32013222
32023223 OS::get_singleton ()->benchmark_end_measure (" EditorHelp" , " Generate Script Documentation" );
3224+
3225+ _worker_thread_done.set ();
32033226}
32043227
32053228void EditorHelp::_regen_script_doc_thread (void *p_udata) {
@@ -3215,6 +3238,9 @@ void EditorHelp::_regen_script_doc_thread(void *p_udata) {
32153238
32163239 _reload_scripts_documentation (dir);
32173240
3241+ _loader_thread_done.set ();
3242+ _worker_thread_done.set_to (false ); // worker_thread is about to start
3243+
32183244 // All ResourceLoader::load() calls are done, so we can no longer deadlock with main thread.
32193245 // Switch to back to worker_thread from loader_thread to resynchronize access to DocData.
32203246 worker_thread.start (_finish_regen_script_doc_thread, nullptr );
@@ -3265,6 +3291,10 @@ void EditorHelp::save_script_doc_cache() {
32653291}
32663292
32673293void EditorHelp::generate_doc (bool p_use_cache, bool p_use_script_cache) {
3294+ if (_cleanup_in_progress.is_set ()) {
3295+ return ;
3296+ }
3297+
32683298 doc_generation_count++;
32693299 OS::get_singleton ()->benchmark_begin_measure (" EditorHelp" , vformat (" Generate Documentation (Run %d)" , doc_generation_count));
32703300
@@ -3280,10 +3310,12 @@ void EditorHelp::generate_doc(bool p_use_cache, bool p_use_script_cache) {
32803310 }
32813311
32823312 if (p_use_cache && FileAccess::exists (get_cache_full_path ())) {
3313+ _worker_thread_done.set_to (false );
32833314 worker_thread.start (_load_doc_thread, (void *)p_use_script_cache);
32843315 } else {
32853316 print_verbose (" Regenerating editor help cache" );
32863317 doc->generate ();
3318+ _worker_thread_done.set_to (false );
32873319 worker_thread.start (_gen_doc_thread, (void *)p_use_script_cache);
32883320 }
32893321}
@@ -3376,7 +3408,28 @@ void EditorHelp::update_doc() {
33763408}
33773409
33783410void EditorHelp::cleanup_doc () {
3379- _wait_for_thread ();
3411+ _cleanup_in_progress.set ();
3412+
3413+ // loader_thread runs _regen_script_doc_thread which calls ResourceLoader::load().
3414+ // Flush the message queue so load tasks can dispatch to the main thread.
3415+ if (loader_thread.is_started ()) {
3416+ while (!_loader_thread_done.is_set ()) {
3417+ MessageQueue::get_singleton ()->flush ();
3418+ OS::get_singleton ()->delay_usec (1000 );
3419+ }
3420+ loader_thread.wait_to_finish ();
3421+ }
3422+
3423+ // worker_thread runs _load_doc_thread, _gen_doc_thread, _load_script_doc_cache_thread,
3424+ // or _finish_regen_script_doc_thread. All may post deferred calls needing the main thread.
3425+ if (worker_thread.is_started ()) {
3426+ while (!_worker_thread_done.is_set ()) {
3427+ MessageQueue::get_singleton ()->flush ();
3428+ OS::get_singleton ()->delay_usec (1000 );
3429+ }
3430+ worker_thread.wait_to_finish ();
3431+ }
3432+
33803433 memdelete (doc);
33813434 doc = nullptr ;
33823435}
0 commit comments