Skip to content

Commit

Permalink
Merge pull request #85939 from adamscott/single-threaded-godot-4
Browse files Browse the repository at this point in the history
Add `THREADS_ENABLED` macro in order to compile Godot to run on the main thread
  • Loading branch information
akien-mga committed Jan 18, 2024
2 parents b5dcb5f + bd70b8e commit fa81059
Show file tree
Hide file tree
Showing 33 changed files with 447 additions and 72 deletions.
30 changes: 26 additions & 4 deletions .github/workflows/web_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,24 @@ concurrency:
jobs:
web-template:
runs-on: "ubuntu-22.04"
name: Template (target=template_release)
name: ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- name: Template w/ threads (target=template_release, threads=yes)
cache-name: web-template
target: template_release
sconsflags: threads=yes
tests: false
artifact: true

- name: Template w/o threads (target=template_release, threads=no)
cache-name: web-nothreads-template
target: template_release
sconsflags: threads=no
tests: false
artifact: true

steps:
- uses: actions/checkout@v4
Expand All @@ -34,6 +51,8 @@ jobs:
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true

- name: Setup python and scons
Expand All @@ -42,10 +61,13 @@ jobs:
- name: Compilation
uses: ./.github/actions/godot-build
with:
sconsflags: ${{ env.SCONSFLAGS }}
sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }}
platform: web
target: template_release
tests: false
target: ${{ matrix.target }}
tests: ${{ matrix.tests }}

- name: Upload artifact
uses: ./.github/actions/upload-artifact
if: ${{ matrix.artifact }}
with:
name: ${{ matrix.cache-name }}
8 changes: 8 additions & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ opts.Add(BoolVariable("separate_debug_symbols", "Extract debugging symbols to a
opts.Add(EnumVariable("lto", "Link-time optimization (production builds)", "none", ("none", "auto", "thin", "full")))
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
opts.Add(BoolVariable("generate_apk", "Generate an APK/AAB after building Android library by calling Gradle", False))
opts.Add(BoolVariable("threads", "Enable threading support", True))

# Components
opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True))
Expand Down Expand Up @@ -832,6 +833,10 @@ if selected_platform in platform_list:
suffix += ".double"

suffix += "." + env["arch"]

if not env["threads"]:
suffix += ".nothreads"

suffix += env.extra_suffix

sys.path.remove(tmppath)
Expand Down Expand Up @@ -972,6 +977,9 @@ if selected_platform in platform_list:
env.Tool("compilation_db")
env.Alias("compiledb", env.CompilationDatabase())

if env["threads"]:
env.Append(CPPDEFINES=["THREADS_ENABLED"])

Export("env")

# Build subdirs, the build order is dependent on link order.
Expand Down
6 changes: 6 additions & 0 deletions core/object/worker_thread_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ WorkerThreadPool *WorkerThreadPool::singleton = nullptr;
thread_local CommandQueueMT *WorkerThreadPool::flushing_cmd_queue = nullptr;

void WorkerThreadPool::_process_task(Task *p_task) {
#ifdef THREADS_ENABLED
int pool_thread_index = thread_ids[Thread::get_caller_id()];
ThreadData &curr_thread = threads[pool_thread_index];
Task *prev_task = nullptr; // In case this is recursively called.
Expand All @@ -69,6 +70,7 @@ void WorkerThreadPool::_process_task(Task *p_task) {
curr_thread.current_task = p_task;
task_mutex.unlock();
}
#endif

if (p_task->group) {
// Handling a group
Expand Down Expand Up @@ -143,6 +145,7 @@ void WorkerThreadPool::_process_task(Task *p_task) {
}
}

#ifdef THREADS_ENABLED
{
curr_thread.current_task = prev_task;
if (p_task->low_priority) {
Expand All @@ -159,6 +162,7 @@ void WorkerThreadPool::_process_task(Task *p_task) {
}

set_current_thread_safe_for_nodes(safe_for_nodes_backup);
#endif
}

void WorkerThreadPool::_thread_function(void *p_user) {
Expand Down Expand Up @@ -542,6 +546,7 @@ bool WorkerThreadPool::is_group_task_completed(GroupID p_group) const {
}

void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
#ifdef THREADS_ENABLED
task_mutex.lock();
Group **groupp = groups.getptr(p_group);
task_mutex.unlock();
Expand Down Expand Up @@ -574,6 +579,7 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
task_mutex.lock(); // This mutex is needed when Physics 2D and/or 3D is selected to run on a separate thread.
groups.erase(p_group);
task_mutex.unlock();
#endif
}

int WorkerThreadPool::get_thread_index() {
Expand Down
14 changes: 14 additions & 0 deletions core/os/condition_variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#include "core/os/mutex.h"

#ifdef THREADS_ENABLED

#ifdef MINGW_ENABLED
#define MINGW_STDTHREAD_REDUNDANCY_WARNING
#include "thirdparty/mingw-std-threads/mingw.condition_variable.h"
Expand Down Expand Up @@ -66,4 +68,16 @@ class ConditionVariable {
}
};

#else // No threads.

class ConditionVariable {
public:
template <class BinaryMutexT>
void wait(const MutexLock<BinaryMutexT> &p_lock) const {}
void notify_one() const {}
void notify_all() const {}
};

#endif // THREADS_ENABLED

#endif // CONDITION_VARIABLE_H
4 changes: 4 additions & 0 deletions core/os/mutex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ void _global_unlock() {
_global_mutex.unlock();
}

#ifdef THREADS_ENABLED

template class MutexImpl<THREADING_NAMESPACE::recursive_mutex>;
template class MutexImpl<THREADING_NAMESPACE::mutex>;
template class MutexLock<MutexImpl<THREADING_NAMESPACE::recursive_mutex>>;
template class MutexLock<MutexImpl<THREADING_NAMESPACE::mutex>>;

#endif
40 changes: 38 additions & 2 deletions core/os/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#define THREADING_NAMESPACE std
#endif

#ifdef THREADS_ENABLED

template <class MutexT>
class MutexLock;

Expand Down Expand Up @@ -125,8 +127,8 @@ class MutexLock {
THREADING_NAMESPACE::unique_lock<typename MutexT::StdMutexType> lock;

public:
_ALWAYS_INLINE_ explicit MutexLock(const MutexT &p_mutex) :
lock(p_mutex.mutex){};
explicit MutexLock(const MutexT &p_mutex) :
lock(p_mutex.mutex) {}
};

// This specialization is needed so manual locking and MutexLock can be used
Expand Down Expand Up @@ -155,4 +157,38 @@ extern template class MutexImpl<THREADING_NAMESPACE::mutex>;
extern template class MutexLock<MutexImpl<THREADING_NAMESPACE::recursive_mutex>>;
extern template class MutexLock<MutexImpl<THREADING_NAMESPACE::mutex>>;

#else // No threads.

class MutexImpl {
mutable THREADING_NAMESPACE::mutex mutex;

public:
void lock() const {}
void unlock() const {}
bool try_lock() const { return true; }
};

template <int Tag>
class SafeBinaryMutex : public MutexImpl {
static thread_local uint32_t count;
};

template <class MutexT>
class MutexLock {
public:
MutexLock(const MutexT &p_mutex) {}
};

template <int Tag>
class MutexLock<SafeBinaryMutex<Tag>> {
public:
MutexLock(const SafeBinaryMutex<Tag> &p_mutex) {}
~MutexLock() {}
};

using Mutex = MutexImpl;
using BinaryMutex = MutexImpl;

#endif // THREADS_ENABLED

#endif // MUTEX_H
6 changes: 6 additions & 0 deletions core/os/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,12 @@ bool OS::has_feature(const String &p_feature) {
}
#endif

#ifdef THREADS_ENABLED
if (p_feature == "threads") {
return true;
}
#endif

if (_check_internal_feature_support(p_feature)) {
return true;
}
Expand Down
17 changes: 17 additions & 0 deletions core/os/semaphore.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#ifndef SEMAPHORE_H
#define SEMAPHORE_H

#include <cstdint>

#ifdef THREADS_ENABLED

#include "core/error/error_list.h"
#include "core/typedefs.h"
#ifdef DEBUG_ENABLED
Expand Down Expand Up @@ -132,4 +136,17 @@ class Semaphore {
#endif
};

#else // No threads.

class Semaphore {
public:
void post(uint32_t p_count = 1) const {}
void wait() const {}
bool try_wait() const {
return true;
}
};

#endif // THREADS_ENABLED

#endif // SEMAPHORE_H
9 changes: 7 additions & 2 deletions core/os/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,22 @@

#include "thread.h"

#ifdef THREADS_ENABLED
#include "core/object/script_language.h"
#include "core/templates/safe_refcount.h"

Thread::PlatformFunctions Thread::platform_functions;

SafeNumeric<uint64_t> Thread::id_counter(1); // The first value after .increment() is 2, hence by default the main thread ID should be 1.

thread_local Thread::ID Thread::caller_id = Thread::UNASSIGNED_ID;
#endif

Thread::PlatformFunctions Thread::platform_functions;

void Thread::_set_platform_functions(const PlatformFunctions &p_functions) {
platform_functions = p_functions;
}

#ifdef THREADS_ENABLED
void Thread::callback(ID p_caller_id, const Settings &p_settings, Callback p_callback, void *p_userdata) {
Thread::caller_id = p_caller_id;
if (platform_functions.set_priority) {
Expand Down Expand Up @@ -107,4 +110,6 @@ Thread::~Thread() {
}
}

#endif // THREADS_ENABLED

#endif // PLATFORM_THREAD_OVERRIDE
64 changes: 62 additions & 2 deletions core/os/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@

class String;

#ifdef THREADS_ENABLED

class Thread {
public:
typedef void (*Callback)(void *p_userdata);
Expand Down Expand Up @@ -86,15 +88,15 @@ class Thread {
private:
friend class Main;

static PlatformFunctions platform_functions;

ID id = UNASSIGNED_ID;
static SafeNumeric<uint64_t> id_counter;
static thread_local ID caller_id;
THREADING_NAMESPACE::thread thread;

static void callback(ID p_caller_id, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata);

static PlatformFunctions platform_functions;

static void make_main_thread() { caller_id = MAIN_ID; }
static void release_main_thread() { caller_id = UNASSIGNED_ID; }

Expand Down Expand Up @@ -125,6 +127,64 @@ class Thread {
~Thread();
};

#else // No threads.

class Thread {
public:
typedef void (*Callback)(void *p_userdata);

typedef uint64_t ID;

enum : ID {
UNASSIGNED_ID = 0,
MAIN_ID = 1
};

enum Priority {
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH
};

struct Settings {
Priority priority;
Settings() { priority = PRIORITY_NORMAL; }
};

struct PlatformFunctions {
Error (*set_name)(const String &) = nullptr;
void (*set_priority)(Thread::Priority) = nullptr;
void (*init)() = nullptr;
void (*wrapper)(Thread::Callback, void *) = nullptr;
void (*term)() = nullptr;
};

private:
friend class Main;

static PlatformFunctions platform_functions;

static void make_main_thread() {}
static void release_main_thread() {}

public:
static void _set_platform_functions(const PlatformFunctions &p_functions);

_FORCE_INLINE_ ID get_id() const { return 0; }
_FORCE_INLINE_ static ID get_caller_id() { return MAIN_ID; }
_FORCE_INLINE_ static ID get_main_id() { return MAIN_ID; }

_FORCE_INLINE_ static bool is_main_thread() { return true; }

static Error set_name(const String &p_name) { return ERR_UNAVAILABLE; }

void start(Thread::Callback p_callback, void *p_user, const Settings &p_settings = Settings()) {}
bool is_started() const { return false; }
void wait_to_finish() {}
};

#endif // THREADS_ENABLED

#endif // THREAD_H

#endif // PLATFORM_THREAD_OVERRIDE
Loading

0 comments on commit fa81059

Please sign in to comment.