diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/SCsub | 129 | ||||
-rw-r--r-- | core/object/object.cpp | 7 | ||||
-rw-r--r-- | core/templates/command_queue_mt.h | 36 |
3 files changed, 128 insertions, 44 deletions
diff --git a/core/SCsub b/core/SCsub index 91620cb075..640c6de6a1 100644 --- a/core/SCsub +++ b/core/SCsub @@ -4,44 +4,9 @@ Import("env") import core_builders import methods - -env.core_sources = [] - - -# Generate AES256 script encryption key import os -txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0" -if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ: - key = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"] - ec_valid = True - if len(key) != 64: - ec_valid = False - else: - txt = "" - for i in range(len(key) >> 1): - if i > 0: - txt += "," - txts = "0x" + key[i * 2 : i * 2 + 2] - try: - int(txts, 16) - except Exception: - ec_valid = False - txt += txts - if not ec_valid: - methods.print_error( - f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{key}".\n' - "Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment " - "or make sure that it contains exactly 64 hexadecimal characters." - ) - Exit(255) - - -script_encryption_key_contents = ( - '#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n" -) - -methods.write_file_if_needed("script_encryption_key.gen.cpp", script_encryption_key_contents) +env.core_sources = [] # Add required thirdparty code. @@ -193,8 +158,96 @@ env.core_sources += thirdparty_obj # Godot source files env.add_source_files(env.core_sources, "*.cpp") -env.add_source_files(env.core_sources, "script_encryption_key.gen.cpp") -env.add_source_files(env.core_sources, "version_hash.gen.cpp") + + +# Generate disabled classes +def disabled_class_builder(target, source, env): + with methods.generated_wrapper(target) as file: + for c in source[0].read(): + cs = c.strip() + if cs != "": + file.write(f"#define ClassDB_Disable_{cs} 1") + + +env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder)) + + +# Generate version info +def version_info_builder(target, source, env): + with methods.generated_wrapper(target) as file: + file.write( + """\ +#define VERSION_SHORT_NAME "{short_name}" +#define VERSION_NAME "{name}" +#define VERSION_MAJOR {major} +#define VERSION_MINOR {minor} +#define VERSION_PATCH {patch} +#define VERSION_STATUS "{status}" +#define VERSION_BUILD "{build}" +#define VERSION_MODULE_CONFIG "{module_config}" +#define VERSION_WEBSITE "{website}" +#define VERSION_DOCS_BRANCH "{docs_branch}" +#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH +""".format( + **env.version_info + ) + ) + + +env.CommandNoCache("version_generated.gen.h", "#version.py", env.Run(version_info_builder)) + + +# Generate version hash +def version_hash_builder(target, source, env): + with methods.generated_wrapper(target) as file: + file.write( + """\ +#include "core/version.h" + +const char *const VERSION_HASH = "{git_hash}"; +const uint64_t VERSION_TIMESTAMP = {git_timestamp}; +""".format( + **env.version_info + ) + ) + + +gen_hash = env.CommandNoCache( + "version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder) +) +env.add_source_files(env.core_sources, gen_hash) + + +# Generate AES256 script encryption key +def encryption_key_builder(target, source, env): + with methods.generated_wrapper(target) as file: + file.write( + f"""\ +#include "core/config/project_settings.h" + +uint8_t script_encryption_key[32] = {{ + {source[0]} +}};""" + ) + + +gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64) +ec_valid = len(gdkey) == 64 +if ec_valid: + try: + gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])]) + except Exception: + ec_valid = False +if not ec_valid: + methods.print_error( + f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n' + "Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment " + "or make sure that it contains exactly 64 hexadecimal characters." + ) + Exit(255) +gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder)) +env.add_source_files(env.core_sources, gen_encrypt) + # Certificates env.Depends( diff --git a/core/object/object.cpp b/core/object/object.cpp index ab89f96a0d..dfc8e2a29a 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -2307,9 +2307,9 @@ void ObjectDB::setup() { } void ObjectDB::cleanup() { - if (slot_count > 0) { - spin_lock.lock(); + spin_lock.lock(); + if (slot_count > 0) { WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details)."); if (OS::get_singleton()->is_stdout_verbose()) { // Ensure calling the native classes because if a leaked instance has a script @@ -2340,10 +2340,11 @@ void ObjectDB::cleanup() { } print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`)."); } - spin_lock.unlock(); } if (object_slots) { memfree(object_slots); } + + spin_lock.unlock(); } diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index bb36f38d54..dbf938a117 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -302,7 +302,7 @@ class CommandQueueMT { struct CommandBase { bool sync = false; virtual void call() = 0; - virtual ~CommandBase() = default; // Won't be called. + virtual ~CommandBase() = default; }; struct SyncCommand : public CommandBase { @@ -327,7 +327,6 @@ class CommandQueueMT { enum { DEFAULT_COMMAND_MEM_SIZE_KB = 256, - SYNC_SEMAPHORES = 8 }; BinaryMutex mutex; @@ -335,6 +334,7 @@ class CommandQueueMT { ConditionVariable sync_cond_var; uint32_t sync_head = 0; uint32_t sync_tail = 0; + uint32_t sync_awaiters = 0; WorkerThreadPool::TaskID pump_task_id = WorkerThreadPool::INVALID_TASK_ID; uint64_t flush_read_ptr = 0; @@ -349,6 +349,15 @@ class CommandQueueMT { return cmd; } + _FORCE_INLINE_ void _prevent_sync_wraparound() { + bool safe_to_reset = !sync_awaiters; + bool already_sync_to_latest = sync_head == sync_tail; + if (safe_to_reset && already_sync_to_latest) { + sync_head = 0; + sync_tail = 0; + } + } + void _flush() { if (unlikely(flush_read_ptr)) { // Re-entrant call. @@ -365,25 +374,39 @@ class CommandQueueMT { cmd->call(); if (unlikely(cmd->sync)) { sync_head++; + unlock(); // Give an opportunity to awaiters right away. sync_cond_var.notify_all(); + lock(); } + // If the command involved reallocating the buffer, the address may have changed. + cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]); + cmd->~CommandBase(); + flush_read_ptr += size; } WorkerThreadPool::thread_exit_command_queue_mt_flush(); command_mem.clear(); flush_read_ptr = 0; + + _prevent_sync_wraparound(); + unlock(); } _FORCE_INLINE_ void _wait_for_sync(MutexLock<BinaryMutex> &p_lock) { + sync_awaiters++; uint32_t sync_head_goal = sync_tail; do { sync_cond_var.wait(p_lock); - } while (sync_head != sync_head_goal); // Can't use lower-than because of wraparound. + } while (sync_head < sync_head_goal); + sync_awaiters--; + _prevent_sync_wraparound(); } + void _no_op() {} + public: void lock(); void unlock(); @@ -405,10 +428,15 @@ public: _flush(); } } + void flush_all() { _flush(); } + void sync() { + push_and_sync(this, &CommandQueueMT::_no_op); + } + void wait_and_flush() { ERR_FAIL_COND(pump_task_id == WorkerThreadPool::INVALID_TASK_ID); WorkerThreadPool::get_singleton()->wait_for_task_completion(pump_task_id); @@ -416,7 +444,9 @@ public: } void set_pump_task_id(WorkerThreadPool::TaskID p_task_id) { + lock(); pump_task_id = p_task_id; + unlock(); } CommandQueueMT(); |