Skip to content

Commit f26328e

Browse files
committed
Revert recently added approach to cross-thread lambda survival
Commits reverted: - 1ed6919 - 2715117
1 parent c2f8fb3 commit f26328e

File tree

4 files changed

+16
-107
lines changed

4 files changed

+16
-107
lines changed

modules/gdscript/gdscript.cpp

Lines changed: 11 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,17 +1392,14 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
13921392
#endif
13931393

13941394
thread_local GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_thread_local;
1395-
GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_main_thread = &func_ptrs_to_update_thread_local;
13961395

1397-
List<GDScript::UpdatableFuncPtrElement>::Element *GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) {
1398-
MutexLock lock(func_ptrs_to_update_mutex);
1399-
1400-
List<UpdatableFuncPtrElement>::Element *result = func_ptrs_to_update_elems.push_back(UpdatableFuncPtrElement());
1396+
GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) {
1397+
UpdatableFuncPtrElement result = {};
14011398

14021399
{
1403-
MutexLock lock2(func_ptrs_to_update_thread_local.mutex);
1404-
result->get().element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr);
1405-
result->get().mutex = &func_ptrs_to_update_thread_local.mutex;
1400+
MutexLock lock(func_ptrs_to_update_thread_local.mutex);
1401+
result.element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr);
1402+
result.mutex = &func_ptrs_to_update_thread_local.mutex;
14061403

14071404
if (likely(func_ptrs_to_update_thread_local.initialized)) {
14081405
return result;
@@ -1411,89 +1408,17 @@ List<GDScript::UpdatableFuncPtrElement>::Element *GDScript::_add_func_ptr_to_upd
14111408
func_ptrs_to_update_thread_local.initialized = true;
14121409
}
14131410

1411+
MutexLock lock(func_ptrs_to_update_mutex);
14141412
func_ptrs_to_update.push_back(&func_ptrs_to_update_thread_local);
14151413

14161414
return result;
14171415
}
14181416

1419-
void GDScript::_remove_func_ptr_to_update(List<UpdatableFuncPtrElement>::Element *p_func_ptr_element) {
1420-
// None of these checks should ever fail, unless there's a bug.
1421-
// They can be removed once we are sure they never catch anything.
1422-
// Left here now due to extra safety needs late in the release cycle.
1423-
ERR_FAIL_NULL(p_func_ptr_element);
1424-
MutexLock lock(func_ptrs_to_update_thread_local.mutex);
1425-
ERR_FAIL_NULL(p_func_ptr_element->get().element);
1426-
ERR_FAIL_NULL(p_func_ptr_element->get().mutex);
1427-
MutexLock lock2(*p_func_ptr_element->get().mutex);
1428-
p_func_ptr_element->get().element->erase();
1429-
p_func_ptr_element->erase();
1430-
}
1431-
1432-
void GDScript::_fixup_thread_function_bookkeeping() {
1433-
// Transfer the ownership of these update items to the main thread,
1434-
// because the current one is dying, leaving theirs orphan, dangling.
1435-
1436-
HashSet<GDScript *> scripts;
1437-
1438-
DEV_ASSERT(!Thread::is_main_thread());
1439-
MutexLock lock(func_ptrs_to_update_main_thread->mutex);
1440-
1441-
{
1442-
MutexLock lock2(func_ptrs_to_update_thread_local.mutex);
1443-
1444-
while (!func_ptrs_to_update_thread_local.ptrs.is_empty()) {
1445-
// Transfer the thread-to-script records from the dying thread to the main one.
1446-
1447-
List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local.ptrs.front();
1448-
List<GDScriptFunction **>::Element *new_E = func_ptrs_to_update_main_thread->ptrs.push_front(E->get());
1449-
1450-
GDScript *script = (*E->get())->get_script();
1451-
if (!scripts.has(script)) {
1452-
scripts.insert(script);
1453-
1454-
// Replace dying thread by the main thread in the script-to-thread records.
1455-
1456-
MutexLock lock3(script->func_ptrs_to_update_mutex);
1457-
DEV_ASSERT(script->func_ptrs_to_update.find(&func_ptrs_to_update_thread_local));
1458-
{
1459-
for (List<UpdatableFuncPtrElement>::Element *F = script->func_ptrs_to_update_elems.front(); F; F = F->next()) {
1460-
bool is_dying_thread_entry = F->get().mutex == &func_ptrs_to_update_thread_local.mutex;
1461-
if (is_dying_thread_entry) {
1462-
// This may lead to multiple main-thread entries, but that's not a problem
1463-
// and allows to reuse the element, which is needed, since it's tracked by pointer.
1464-
F->get().element = new_E;
1465-
F->get().mutex = &func_ptrs_to_update_main_thread->mutex;
1466-
}
1467-
}
1468-
}
1469-
}
1470-
1471-
E->erase();
1472-
}
1473-
}
1474-
func_ptrs_to_update_main_thread->initialized = true;
1475-
1476-
{
1477-
// Remove orphan thread-to-script entries from every script.
1478-
// FIXME: This involves iterating through every script whenever a thread dies.
1479-
// While it's OK that thread creation/destruction are heavy operations,
1480-
// additional bookkeeping can be used to outperform this brute-force approach.
1481-
1482-
GDScriptLanguage *gd_lang = GDScriptLanguage::get_singleton();
1483-
1484-
MutexLock lock2(gd_lang->mutex);
1485-
1486-
for (SelfList<GDScript> *s = gd_lang->script_list.first(); s; s = s->next()) {
1487-
GDScript *script = s->self();
1488-
for (List<UpdatableFuncPtr *>::Element *E = script->func_ptrs_to_update.front(); E; E = E->next()) {
1489-
bool is_dying_thread_entry = &E->get()->mutex == &func_ptrs_to_update_thread_local.mutex;
1490-
if (is_dying_thread_entry) {
1491-
E->erase();
1492-
break;
1493-
}
1494-
}
1495-
}
1496-
}
1417+
void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement p_func_ptr_element) {
1418+
ERR_FAIL_NULL(p_func_ptr_element.element);
1419+
ERR_FAIL_NULL(p_func_ptr_element.mutex);
1420+
MutexLock lock(*p_func_ptr_element.mutex);
1421+
p_func_ptr_element.element->erase();
14971422
}
14981423

14991424
void GDScript::clear(ClearData *p_clear_data) {
@@ -1521,7 +1446,6 @@ void GDScript::clear(ClearData *p_clear_data) {
15211446
*func_ptr_ptr = nullptr;
15221447
}
15231448
}
1524-
func_ptrs_to_update_elems.clear();
15251449
}
15261450

15271451
RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies();
@@ -2141,10 +2065,6 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
21412065
named_globals.erase(p_name);
21422066
}
21432067

2144-
void GDScriptLanguage::thread_exit() {
2145-
GDScript::_fixup_thread_function_bookkeeping();
2146-
}
2147-
21482068
void GDScriptLanguage::init() {
21492069
//populate global constants
21502070
int gcc = CoreConstants::get_global_constant_count();

modules/gdscript/gdscript.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,11 @@ class GDScript : public Script {
128128
Mutex *mutex = nullptr;
129129
};
130130
static thread_local UpdatableFuncPtr func_ptrs_to_update_thread_local;
131-
static thread_local LocalVector<List<UpdatableFuncPtr *>::Element> func_ptrs_to_update_entries_thread_local;
132-
static UpdatableFuncPtr *func_ptrs_to_update_main_thread;
133131
List<UpdatableFuncPtr *> func_ptrs_to_update;
134-
List<UpdatableFuncPtrElement> func_ptrs_to_update_elems;
135132
Mutex func_ptrs_to_update_mutex;
136133

137-
List<UpdatableFuncPtrElement>::Element *_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr);
138-
static void _remove_func_ptr_to_update(List<UpdatableFuncPtrElement>::Element *p_func_ptr_element);
139-
140-
static void _fixup_thread_function_bookkeeping();
134+
UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr);
135+
static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement p_func_ptr_element);
141136

142137
#ifdef TOOLS_ENABLED
143138
// For static data storage during hot-reloading.
@@ -559,10 +554,6 @@ class GDScriptLanguage : public ScriptLanguage {
559554
virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override;
560555
virtual void remove_named_global_constant(const StringName &p_name) override;
561556

562-
/* MULTITHREAD FUNCTIONS */
563-
564-
virtual void thread_exit() override;
565-
566557
/* DEBUGGER FUNCTIONS */
567558

568559
virtual String debug_get_error() const override;

modules/gdscript/gdscript_lambda_callable.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,5 @@ GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptF
296296
}
297297

298298
GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() {
299-
if (updatable_func_ptr_element) {
300-
GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element);
301-
}
299+
GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element);
302300
}

modules/gdscript/gdscript_lambda_callable.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class GDScriptLambdaCallable : public CallableCustom {
4545
GDScriptFunction *function = nullptr;
4646
Ref<GDScript> script;
4747
uint32_t h;
48-
List<GDScript::UpdatableFuncPtrElement>::Element *updatable_func_ptr_element = nullptr;
48+
GDScript::UpdatableFuncPtrElement updatable_func_ptr_element;
4949

5050
Vector<Variant> captures;
5151

@@ -72,7 +72,7 @@ class GDScriptLambdaSelfCallable : public CallableCustom {
7272
Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference.
7373
Object *object = nullptr; // For non RefCounted objects, use a direct pointer.
7474
uint32_t h;
75-
List<GDScript::UpdatableFuncPtrElement>::Element *updatable_func_ptr_element = nullptr;
75+
GDScript::UpdatableFuncPtrElement updatable_func_ptr_element;
7676

7777
Vector<Variant> captures;
7878

0 commit comments

Comments
 (0)