Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make languages bookkeeping thread-safe #84657

Merged
merged 1 commit into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions core/object/script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@

ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
int ScriptServer::_language_count = 0;
bool ScriptServer::languages_ready = false;
Mutex ScriptServer::languages_mutex;

bool ScriptServer::scripting_enabled = true;
bool ScriptServer::reload_scripts_on_save = false;
SafeFlag ScriptServer::languages_finished; // Used until GH-76581 is fixed properly.
ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr;

void Script::_notification(int p_what) {
Expand Down Expand Up @@ -160,12 +161,13 @@ bool ScriptServer::is_scripting_enabled() {
}

ScriptLanguage *ScriptServer::get_language(int p_idx) {
MutexLock lock(languages_mutex);
ERR_FAIL_INDEX_V(p_idx, _language_count, nullptr);

return _languages[p_idx];
}

Error ScriptServer::register_language(ScriptLanguage *p_language) {
MutexLock lock(languages_mutex);
ERR_FAIL_NULL_V(p_language, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(_language_count >= MAX_LANGUAGES, ERR_UNAVAILABLE, "Script languages limit has been reach, cannot register more.");
for (int i = 0; i < _language_count; i++) {
Expand All @@ -179,6 +181,8 @@ Error ScriptServer::register_language(ScriptLanguage *p_language) {
}

Error ScriptServer::unregister_language(const ScriptLanguage *p_language) {
MutexLock lock(languages_mutex);

for (int i = 0; i < _language_count; i++) {
if (_languages[i] == p_language) {
_language_count--;
Expand Down Expand Up @@ -219,17 +223,31 @@ void ScriptServer::init_languages() {
}
}

for (int i = 0; i < _language_count; i++) {
_languages[i]->init();
{
MutexLock lock(languages_mutex);

for (int i = 0; i < _language_count; i++) {
_languages[i]->init();
}

languages_ready = true;
}
}

void ScriptServer::finish_languages() {
MutexLock lock(languages_mutex);

for (int i = 0; i < _language_count; i++) {
_languages[i]->finish();
}
global_classes_clear();
languages_finished.set();

languages_ready = false;
}

bool ScriptServer::are_languages_initialized() {
MutexLock lock(languages_mutex);
return languages_ready;
}

void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
Expand All @@ -241,7 +259,8 @@ bool ScriptServer::is_reload_scripts_on_save_enabled() {
}

void ScriptServer::thread_enter() {
if (!languages_finished.is_set()) {
MutexLock lock(languages_mutex);
if (!languages_ready) {
return;
}
for (int i = 0; i < _language_count; i++) {
Expand All @@ -250,7 +269,8 @@ void ScriptServer::thread_enter() {
}

void ScriptServer::thread_exit() {
if (!languages_finished.is_set()) {
MutexLock lock(languages_mutex);
if (!languages_ready) {
return;
}
for (int i = 0; i < _language_count; i++) {
Expand Down
7 changes: 4 additions & 3 deletions core/object/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ class ScriptServer {

static ScriptLanguage *_languages[MAX_LANGUAGES];
static int _language_count;
static bool languages_ready;
static Mutex languages_mutex;

static bool scripting_enabled;
static bool reload_scripts_on_save;
static SafeFlag languages_finished; // Used until GH-76581 is fixed properly.

struct GlobalScriptClass {
StringName language;
Expand Down Expand Up @@ -98,8 +100,7 @@ class ScriptServer {

static void init_languages();
static void finish_languages();

static bool are_languages_finished() { return languages_finished.is_set(); }
static bool are_languages_initialized();
};

class PlaceHolderScriptInstance;
Expand Down
9 changes: 9 additions & 0 deletions core/object/worker_thread_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "worker_thread_pool.h"

#include "core/object/script_language.h"
#include "core/os/os.h"
#include "core/os/thread_safe.h"

Expand Down Expand Up @@ -60,6 +61,14 @@ void WorkerThreadPool::_process_task(Task *p_task) {
set_current_thread_safe_for_nodes(false);
pool_thread_index = thread_ids[Thread::get_caller_id()];
ThreadData &curr_thread = threads[pool_thread_index];
// Since the WorkerThreadPool is started before the script server,
// its pre-created threads can't have ScriptServer::thread_enter() called on them early.
// Therefore, we do it late at the first opportunity, so in case the task
// about to be run uses scripting, guarantees are held.
if (!curr_thread.ready_for_scripting && ScriptServer::are_languages_initialized()) {
ScriptServer::thread_enter();
curr_thread.ready_for_scripting = true;
}
task_mutex.lock();
p_task->pool_thread_index = pool_thread_index;
if (low_priority) {
Expand Down
1 change: 1 addition & 0 deletions core/object/worker_thread_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class WorkerThreadPool : public Object {
uint32_t index;
Thread thread;
Task *current_low_prio_task = nullptr;
bool ready_for_scripting = false;
};

TightLocalVector<ThreadData> threads;
Expand Down
Loading