Browse Source

Merge pull request #45618 from RandomShaper/modernize_mt_3.2

Backport of all the multi-threading modernization (3.2)
Hein-Pieter van Braam 4 years ago
parent
commit
220f24c191
100 changed files with 1080 additions and 2983 deletions
  1. 16 50
      core/bind/core_bind.cpp
  2. 5 10
      core/bind/core_bind.h
  3. 3 10
      core/class_db.cpp
  4. 1 2
      core/class_db.h
  5. 3 12
      core/command_queue_mt.cpp
  6. 5 5
      core/command_queue_mt.h
  7. 12 9
      core/cowdata.h
  8. 8 6
      core/error_macros.h
  9. 28 45
      core/io/file_access_network.cpp
  10. 7 7
      core/io/file_access_network.h
  11. 41 66
      core/io/ip.cpp
  12. 12 42
      core/io/resource_loader.cpp
  13. 1 2
      core/io/resource_loader.h
  14. 14 21
      core/object.cpp
  15. 5 5
      core/object.h
  16. 13 13
      core/os/memory.cpp
  17. 3 3
      core/os/memory.h
  18. 9 21
      core/os/mutex.cpp
  19. 71 24
      core/os/mutex.h
  20. 0 2
      core/os/os.h
  21. 0 47
      core/os/rw_lock.cpp
  22. 56 20
      core/os/rw_lock.h
  23. 0 45
      core/os/semaphore.cpp
  24. 47 7
      core/os/semaphore.h
  25. 70 22
      core/os/thread.cpp
  26. 57 20
      core/os/thread.h
  27. 0 65
      core/os/thread_dummy.cpp
  28. 0 89
      core/os/thread_dummy.h
  29. 0 49
      core/os/thread_safe.cpp
  30. 4 45
      core/os/thread_safe.h
  31. 11 12
      core/os/threaded_array_processor.h
  32. 2 5
      core/pool_vector.cpp
  33. 26 25
      core/pool_vector.h
  34. 2 2
      core/reference.cpp
  35. 1 11
      core/register_core_types.cpp
  36. 33 60
      core/resource.cpp
  37. 2 3
      core/resource.h
  38. 0 169
      core/safe_refcount.cpp
  39. 218 107
      core/safe_refcount.h
  40. 23 27
      core/string_name.cpp
  41. 1 1
      core/string_name.h
  42. 5 22
      drivers/alsa/audio_driver_alsa.cpp
  43. 2 2
      drivers/alsa/audio_driver_alsa.h
  44. 5 21
      drivers/alsamidi/midi_driver_alsamidi.cpp
  45. 2 2
      drivers/alsamidi/midi_driver_alsamidi.h
  46. 3 15
      drivers/coreaudio/audio_driver_coreaudio.cpp
  47. 1 1
      drivers/coreaudio/audio_driver_coreaudio.h
  48. 5 20
      drivers/pulseaudio/audio_driver_pulseaudio.cpp
  49. 2 2
      drivers/pulseaudio/audio_driver_pulseaudio.h
  50. 0 73
      drivers/unix/mutex_posix.cpp
  51. 0 61
      drivers/unix/mutex_posix.h
  52. 6 22
      drivers/unix/os_unix.cpp
  53. 0 102
      drivers/unix/rw_lock_posix.cpp
  54. 0 63
      drivers/unix/rw_lock_posix.h
  55. 0 87
      drivers/unix/semaphore_posix.cpp
  56. 0 58
      drivers/unix/semaphore_posix.h
  57. 6 96
      drivers/unix/thread_posix.cpp
  58. 2 37
      drivers/unix/thread_posix.h
  59. 5 21
      drivers/wasapi/audio_driver_wasapi.cpp
  60. 2 2
      drivers/wasapi/audio_driver_wasapi.h
  61. 0 101
      drivers/windows/mutex_windows.cpp
  62. 0 63
      drivers/windows/mutex_windows.h
  63. 0 95
      drivers/windows/rw_lock_windows.cpp
  64. 0 64
      drivers/windows/rw_lock_windows.h
  65. 0 98
      drivers/windows/semaphore_windows.cpp
  66. 0 58
      drivers/windows/semaphore_windows.h
  67. 0 100
      drivers/windows/thread_windows.cpp
  68. 0 68
      drivers/windows/thread_windows.h
  69. 5 17
      drivers/xaudio2/audio_driver_xaudio2.cpp
  70. 2 2
      drivers/xaudio2/audio_driver_xaudio2.h
  71. 9 6
      editor/audio_stream_preview.cpp
  72. 13 1
      editor/audio_stream_preview.h
  73. 16 25
      editor/editor_file_system.cpp
  74. 5 3
      editor/editor_file_system.h
  75. 7 13
      editor/editor_node.cpp
  76. 4 3
      editor/editor_node.h
  77. 27 36
      editor/editor_resource_preview.cpp
  78. 6 5
      editor/editor_resource_preview.h
  79. 11 15
      editor/fileserver/editor_file_server.cpp
  80. 3 3
      editor/fileserver/editor_file_server.h
  81. 9 15
      editor/import/resource_importer_texture.cpp
  82. 1 2
      editor/import/resource_importer_texture.h
  83. 9 9
      editor/plugins/editor_preview_plugins.cpp
  84. 5 3
      editor/plugins/editor_preview_plugins.h
  85. 3 5
      main/main.cpp
  86. 7 5
      modules/cvtt/image_compress_cvtt.cpp
  87. 1 1
      modules/gdnative/android/android_gdn.cpp
  88. 7 34
      modules/gdnative/nativescript/nativescript.cpp
  89. 4 5
      modules/gdnative/nativescript/nativescript.h
  90. 2 26
      modules/gdnative/pluginscript/pluginscript_language.cpp
  91. 2 2
      modules/gdnative/pluginscript/pluginscript_language.h
  92. 30 106
      modules/gdscript/gdscript.cpp
  93. 1 1
      modules/gdscript/gdscript.h
  94. 8 26
      modules/gdscript/gdscript_function.cpp
  95. 3 7
      modules/gdscript/language_server/gdscript_language_server.cpp
  96. 1 1
      modules/gdscript/language_server/gdscript_language_server.h
  97. 3 3
      modules/lightmapper_cpu/lightmapper_cpu.cpp
  98. 14 56
      modules/mono/csharp_script.cpp
  99. 5 5
      modules/mono/csharp_script.h
  100. 1 2
      modules/mono/mono_gd/gd_mono_utils.cpp

+ 16 - 50
core/bind/core_bind.cpp

@@ -2689,12 +2689,14 @@ void _Marshalls::_bind_methods() {
 
 Error _Semaphore::wait() {
 
-	return semaphore->wait();
+	semaphore.wait();
+	return OK; // Can't fail anymore; keep compat
 }
 
 Error _Semaphore::post() {
 
-	return semaphore->post();
+	semaphore.post();
+	return OK; // Can't fail anymore; keep compat
 }
 
 void _Semaphore::_bind_methods() {
@@ -2703,31 +2705,21 @@ void _Semaphore::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("post"), &_Semaphore::post);
 }
 
-_Semaphore::_Semaphore() {
-
-	semaphore = Semaphore::create();
-}
-
-_Semaphore::~_Semaphore() {
-
-	memdelete(semaphore);
-}
-
 ///////////////
 
 void _Mutex::lock() {
 
-	mutex->lock();
+	mutex.lock();
 }
 
 Error _Mutex::try_lock() {
 
-	return mutex->try_lock();
+	return mutex.try_lock();
 }
 
 void _Mutex::unlock() {
 
-	mutex->unlock();
+	mutex.unlock();
 }
 
 void _Mutex::_bind_methods() {
@@ -2737,16 +2729,6 @@ void _Mutex::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("unlock"), &_Mutex::unlock);
 }
 
-_Mutex::_Mutex() {
-
-	mutex = Mutex::create();
-}
-
-_Mutex::~_Mutex() {
-
-	memdelete(mutex);
-}
-
 ///////////////
 
 void _Thread::_start_func(void *ud) {
@@ -2790,7 +2772,7 @@ void _Thread::_start_func(void *ud) {
 
 Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
 
-	ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "Thread already started.");
+	ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started.");
 	ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
 	ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
 	ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
@@ -2799,49 +2781,35 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia
 	target_method = p_method;
 	target_instance = p_instance;
 	userdata = p_userdata;
-	active = true;
+	active.set();
 
 	Ref<_Thread> *ud = memnew(Ref<_Thread>(this));
 
 	Thread::Settings s;
 	s.priority = (Thread::Priority)p_priority;
-	thread = Thread::create(_start_func, ud, s);
-	if (!thread) {
-		active = false;
-		target_method = StringName();
-		target_instance = NULL;
-		userdata = Variant();
-		return ERR_CANT_CREATE;
-	}
+	thread.start(_start_func, ud, s);
 
 	return OK;
 }
 
 String _Thread::get_id() const {
 
-	if (!thread)
-		return String();
-
-	return itos(thread->get_id());
+	return itos(thread.get_id());
 }
 
 bool _Thread::is_active() const {
 
-	return active;
+	return active.is_set();
 }
 Variant _Thread::wait_to_finish() {
 
-	ERR_FAIL_COND_V_MSG(!thread, Variant(), "Thread must exist to wait for its completion.");
-	ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion.");
-	Thread::wait_to_finish(thread);
+	ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion.");
+	thread.wait_to_finish();
 	Variant r = ret;
-	active = false;
 	target_method = StringName();
 	target_instance = NULL;
 	userdata = Variant();
-	if (thread)
-		memdelete(thread);
-	thread = NULL;
+	active.clear();
 
 	return r;
 }
@@ -2859,14 +2827,12 @@ void _Thread::_bind_methods() {
 }
 _Thread::_Thread() {
 
-	active = false;
-	thread = NULL;
 	target_instance = NULL;
 }
 
 _Thread::~_Thread() {
 
-	ERR_FAIL_COND_MSG(active, "Reference to a Thread object was lost while the thread is still running...");
+	ERR_FAIL_COND_MSG(active.is_set(), "Reference to a Thread object was lost while the thread is still running...");
 }
 
 /////////////////////////////////////

+ 5 - 10
core/bind/core_bind.h

@@ -40,6 +40,7 @@
 #include "core/os/os.h"
 #include "core/os/semaphore.h"
 #include "core/os/thread.h"
+#include "core/safe_refcount.h"
 
 class _ResourceLoader : public Object {
 	GDCLASS(_ResourceLoader, Object);
@@ -652,7 +653,7 @@ public:
 class _Mutex : public Reference {
 
 	GDCLASS(_Mutex, Reference);
-	Mutex *mutex;
+	Mutex mutex;
 
 	static void _bind_methods();
 
@@ -660,24 +661,18 @@ public:
 	void lock();
 	Error try_lock();
 	void unlock();
-
-	_Mutex();
-	~_Mutex();
 };
 
 class _Semaphore : public Reference {
 
 	GDCLASS(_Semaphore, Reference);
-	Semaphore *semaphore;
+	Semaphore semaphore;
 
 	static void _bind_methods();
 
 public:
 	Error wait();
 	Error post();
-
-	_Semaphore();
-	~_Semaphore();
 };
 
 class _Thread : public Reference {
@@ -687,10 +682,10 @@ class _Thread : public Reference {
 protected:
 	Variant ret;
 	Variant userdata;
-	volatile bool active;
+	SafeFlag active;
 	Object *target_instance;
 	StringName target_method;
-	Thread *thread;
+	Thread thread;
 	static void _bind_methods();
 	static void _start_func(void *ud);
 

+ 3 - 10
core/class_db.cpp

@@ -929,9 +929,9 @@ void ClassDB::add_property_group(StringName p_class, const String &p_name, const
 
 void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
 
-	lock->read_lock();
+	lock.read_lock();
 	ClassInfo *type = classes.getptr(p_class);
-	lock->read_unlock();
+	lock.read_unlock();
 
 	ERR_FAIL_COND(!type);
 
@@ -1447,12 +1447,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
 	return default_values[p_class][p_property];
 }
 
-RWLock *ClassDB::lock = NULL;
-
-void ClassDB::init() {
-
-	lock = RWLock::create();
-}
+RWLock ClassDB::lock;
 
 void ClassDB::cleanup_defaults() {
 
@@ -1479,8 +1474,6 @@ void ClassDB::cleanup() {
 	classes.clear();
 	resource_base_extensions.clear();
 	compat_classes.clear();
-
-	memdelete(lock);
 }
 
 //

+ 1 - 2
core/class_db.h

@@ -143,7 +143,7 @@ public:
 		return memnew(T);
 	}
 
-	static RWLock *lock;
+	static RWLock lock;
 	static HashMap<StringName, ClassInfo> classes;
 	static HashMap<StringName, StringName> resource_base_extensions;
 	static HashMap<StringName, StringName> compat_classes;
@@ -393,7 +393,6 @@ public:
 	static void get_extensions_for_type(const StringName &p_class, List<String> *p_extensions);
 
 	static void add_compatibility_class(const StringName &p_class, const StringName &p_fallback);
-	static void init();
 
 	static void set_current_api(APIType p_api);
 	static APIType get_current_api();

+ 3 - 12
core/command_queue_mt.cpp

@@ -35,14 +35,12 @@
 
 void CommandQueueMT::lock() {
 
-	if (mutex)
-		mutex->lock();
+	mutex.lock();
 }
 
 void CommandQueueMT::unlock() {
 
-	if (mutex)
-		mutex->unlock();
+	mutex.unlock();
 }
 
 void CommandQueueMT::wait_for_flush() {
@@ -107,7 +105,6 @@ CommandQueueMT::CommandQueueMT(bool p_sync) {
 	read_ptr_and_epoch = 0;
 	write_ptr_and_epoch = 0;
 	dealloc_ptr = 0;
-	mutex = Mutex::create();
 
 	command_mem_size = GLOBAL_DEF_RST("memory/limits/command_queue/multithreading_queue_size_kb", DEFAULT_COMMAND_MEM_SIZE_KB);
 	ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/command_queue/multithreading_queue_size_kb", PropertyInfo(Variant::INT, "memory/limits/command_queue/multithreading_queue_size_kb", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"));
@@ -116,11 +113,10 @@ CommandQueueMT::CommandQueueMT(bool p_sync) {
 
 	for (int i = 0; i < SYNC_SEMAPHORES; i++) {
 
-		sync_sems[i].sem = Semaphore::create();
 		sync_sems[i].in_use = false;
 	}
 	if (p_sync) {
-		sync = Semaphore::create();
+		sync = memnew(Semaphore);
 	} else {
 		sync = NULL;
 	}
@@ -130,10 +126,5 @@ CommandQueueMT::~CommandQueueMT() {
 
 	if (sync)
 		memdelete(sync);
-	memdelete(mutex);
-	for (int i = 0; i < SYNC_SEMAPHORES; i++) {
-
-		memdelete(sync_sems[i].sem);
-	}
 	memfree(command_mem);
 }

+ 5 - 5
core/command_queue_mt.h

@@ -250,7 +250,7 @@
 		cmd->sync_sem = ss;                                                                    \
 		unlock();                                                                              \
 		if (sync) sync->post();                                                                \
-		ss->sem->wait();                                                                       \
+		ss->sem.wait();                                                                        \
 		ss->in_use = false;                                                                    \
 	}
 
@@ -267,7 +267,7 @@
 		cmd->sync_sem = ss;                                                           \
 		unlock();                                                                     \
 		if (sync) sync->post();                                                       \
-		ss->sem->wait();                                                              \
+		ss->sem.wait();                                                               \
 		ss->in_use = false;                                                           \
 	}
 
@@ -277,7 +277,7 @@ class CommandQueueMT {
 
 	struct SyncSemaphore {
 
-		Semaphore *sem;
+		Semaphore sem;
 		bool in_use;
 	};
 
@@ -293,7 +293,7 @@ class CommandQueueMT {
 		SyncSemaphore *sync_sem;
 
 		virtual void post() {
-			sync_sem->sem->post();
+			sync_sem->sem.post();
 		}
 	};
 
@@ -321,7 +321,7 @@ class CommandQueueMT {
 	uint32_t dealloc_ptr;
 	uint32_t command_mem_size;
 	SyncSemaphore sync_sems[SYNC_SEMAPHORES];
-	Mutex *mutex;
+	Mutex mutex;
 	Semaphore *sync;
 
 	template <class T>

+ 12 - 9
core/cowdata.h

@@ -44,6 +44,9 @@ class CharString;
 template <class T, class V>
 class VMap;
 
+// CowData is relying on this to be true
+static_assert(sizeof(SafeNumeric<uint32_t>) == sizeof(uint32_t), "");
+
 template <class T>
 class CowData {
 	template <class TV>
@@ -58,12 +61,12 @@ private:
 
 	// internal helpers
 
-	_FORCE_INLINE_ uint32_t *_get_refcount() const {
+	_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
 
 		if (!_ptr)
 			return NULL;
 
-		return reinterpret_cast<uint32_t *>(_ptr) - 2;
+		return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
 	}
 
 	_FORCE_INLINE_ uint32_t *_get_size() const {
@@ -193,9 +196,9 @@ void CowData<T>::_unref(void *p_data) {
 	if (!p_data)
 		return;
 
-	uint32_t *refc = _get_refcount();
+	SafeNumeric<uint32_t> *refc = _get_refcount();
 
-	if (atomic_decrement(refc) > 0)
+	if (refc->decrement() > 0)
 		return; // still in use
 	// clean up
 
@@ -219,15 +222,15 @@ void CowData<T>::_copy_on_write() {
 	if (!_ptr)
 		return;
 
-	uint32_t *refc = _get_refcount();
+	SafeNumeric<uint32_t> *refc = _get_refcount();
 
-	if (unlikely(*refc > 1)) {
+	if (unlikely(refc->get() > 1)) {
 		/* in use by more than me */
 		uint32_t current_size = *_get_size();
 
 		uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
 
-		*(mem_new - 2) = 1; //refcount
+		reinterpret_cast<SafeNumeric<uint32_t> *>(mem_new - 2)->set(1); //refcount
 		*(mem_new - 1) = current_size; //size
 
 		T *_data = (T *)(mem_new);
@@ -279,7 +282,7 @@ Error CowData<T>::resize(int p_size) {
 				uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
 				ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
 				*(ptr - 1) = 0; //size, currently none
-				*(ptr - 2) = 1; //refcount
+				reinterpret_cast<SafeNumeric<uint32_t> *>(ptr - 2)->set(1); //refcount
 
 				_ptr = (T *)ptr;
 
@@ -360,7 +363,7 @@ void CowData<T>::_ref(const CowData &p_from) {
 	if (!p_from._ptr)
 		return; //nothing to do
 
-	if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference
+	if (p_from._get_refcount()->increment() > 0) { // could reference
 		_ptr = p_from._ptr;
 	}
 }

+ 8 - 6
core/error_macros.h

@@ -31,7 +31,9 @@
 #ifndef ERROR_MACROS_H
 #define ERROR_MACROS_H
 
+#include "core/safe_refcount.h"
 #include "core/typedefs.h"
+
 /**
  * Error macros. Unlike exceptions and asserts, these macros try to maintain consistency and stability
  * inside the code. It is recommended to always return processable data, so in case of an error,
@@ -532,10 +534,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
  */
 #define WARN_DEPRECATED                                                                                                                                    \
 	{                                                                                                                                                      \
-		static volatile bool warning_shown = false;                                                                                                        \
-		if (!warning_shown) {                                                                                                                              \
+		static SafeFlag warning_shown;                                                                                                                     \
+		if (!warning_shown.is_set()) {                                                                                                                     \
 			_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \
-			warning_shown = true;                                                                                                                          \
+			warning_shown.set();                                                                                                                           \
 		}                                                                                                                                                  \
 	}
 
@@ -545,10 +547,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
  */
 #define WARN_DEPRECATED_MSG(m_msg)                                                                                                                                \
 	{                                                                                                                                                             \
-		static volatile bool warning_shown = false;                                                                                                               \
-		if (!warning_shown) {                                                                                                                                     \
+		static SafeFlag warning_shown;                                                                                                                            \
+		if (!warning_shown.is_set()) {                                                                                                                            \
 			_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, ERR_HANDLER_WARNING); \
-			warning_shown = true;                                                                                                                                 \
+			warning_shown.set();                                                                                                                                  \
 		}                                                                                                                                                         \
 	}
 

+ 28 - 45
core/io/file_access_network.cpp

@@ -42,14 +42,14 @@
 
 void FileAccessNetworkClient::lock_mutex() {
 
-	mutex->lock();
+	mutex.lock();
 	lockcount++;
 }
 
 void FileAccessNetworkClient::unlock_mutex() {
 
 	lockcount--;
-	mutex->unlock();
+	mutex.unlock();
 }
 
 void FileAccessNetworkClient::put_32(int p_32) {
@@ -88,16 +88,14 @@ void FileAccessNetworkClient::_thread_func() {
 	while (!quit) {
 
 		DEBUG_PRINT("SEM WAIT - " + itos(sem->get()));
-		Error err = sem->wait();
-		if (err != OK)
-			ERR_PRINT("sem->wait() failed");
+		sem.wait();
 		DEBUG_TIME("sem_unlock");
 		//DEBUG_PRINT("semwait returned "+itos(werr));
 		DEBUG_PRINT("MUTEX LOCK " + itos(lockcount));
 		lock_mutex();
 		DEBUG_PRINT("MUTEX PASS");
 
-		blockrequest_mutex->lock();
+		blockrequest_mutex.lock();
 		while (block_requests.size()) {
 			put_32(block_requests.front()->get().id);
 			put_32(FileAccessNetwork::COMMAND_READ_BLOCK);
@@ -105,7 +103,7 @@ void FileAccessNetworkClient::_thread_func() {
 			put_32(block_requests.front()->get().size);
 			block_requests.pop_front();
 		}
-		blockrequest_mutex->unlock();
+		blockrequest_mutex.unlock();
 
 		DEBUG_PRINT("THREAD ITER");
 
@@ -140,7 +138,7 @@ void FileAccessNetworkClient::_thread_func() {
 					fa->_respond(len, Error(status));
 				}
 
-				fa->sem->post();
+				fa->sem.post();
 
 			} break;
 			case FileAccessNetwork::RESPONSE_DATA: {
@@ -160,14 +158,14 @@ void FileAccessNetworkClient::_thread_func() {
 
 				int status = get_32();
 				fa->exists_modtime = status != 0;
-				fa->sem->post();
+				fa->sem.post();
 
 			} break;
 			case FileAccessNetwork::RESPONSE_GET_MODTIME: {
 
 				uint64_t status = get_64();
 				fa->exists_modtime = status;
-				fa->sem->post();
+				fa->sem.post();
 
 			} break;
 		}
@@ -215,7 +213,7 @@ Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const S
 		return ERR_INVALID_PARAMETER;
 	}
 
-	thread = Thread::create(_thread_func, this);
+	thread.start(_thread_func, this);
 
 	return OK;
 }
@@ -224,29 +222,20 @@ FileAccessNetworkClient *FileAccessNetworkClient::singleton = NULL;
 
 FileAccessNetworkClient::FileAccessNetworkClient() {
 
-	thread = NULL;
-	mutex = Mutex::create();
-	blockrequest_mutex = Mutex::create();
 	quit = false;
 	singleton = this;
 	last_id = 0;
 	client.instance();
-	sem = Semaphore::create();
 	lockcount = 0;
 }
 
 FileAccessNetworkClient::~FileAccessNetworkClient() {
 
-	if (thread) {
+	if (thread.is_started()) {
 		quit = true;
-		sem->post();
-		Thread::wait_to_finish(thread);
-		memdelete(thread);
+		sem.post();
+		thread.wait_to_finish();
 	}
-
-	memdelete(blockrequest_mutex);
-	memdelete(mutex);
-	memdelete(sem);
 }
 
 void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) {
@@ -259,14 +248,14 @@ void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block)
 		ERR_FAIL_COND((p_block.size() != (int)(total_size % page_size)));
 	}
 
-	buffer_mutex->lock();
+	buffer_mutex.lock();
 	pages.write[page].buffer = p_block;
 	pages.write[page].queued = false;
-	buffer_mutex->unlock();
+	buffer_mutex.unlock();
 
 	if (waiting_on_page == page) {
 		waiting_on_page = -1;
-		page_sem->post();
+		page_sem.post();
 	}
 }
 
@@ -308,9 +297,9 @@ Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
 	nc->unlock_mutex();
 	DEBUG_PRINT("OPEN POST");
 	DEBUG_TIME("open_post");
-	nc->sem->post(); //awaiting answer
+	nc->sem.post(); //awaiting answer
 	DEBUG_PRINT("WAIT...");
-	sem->wait();
+	sem.wait();
 	DEBUG_TIME("open_end");
 	DEBUG_PRINT("WAIT ENDED...");
 
@@ -385,16 +374,16 @@ void FileAccessNetwork::_queue_page(int p_page) const {
 
 		FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
 
-		nc->blockrequest_mutex->lock();
+		nc->blockrequest_mutex.lock();
 		FileAccessNetworkClient::BlockRequest br;
 		br.id = id;
 		br.offset = size_t(p_page) * page_size;
 		br.size = page_size;
 		nc->block_requests.push_back(br);
 		pages.write[p_page].queued = true;
-		nc->blockrequest_mutex->unlock();
+		nc->blockrequest_mutex.unlock();
 		DEBUG_PRINT("QUEUE PAGE POST");
-		nc->sem->post();
+		nc->sem.post();
 		DEBUG_PRINT("queued " + itos(p_page));
 	}
 }
@@ -418,16 +407,16 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
 		int page = pos / page_size;
 
 		if (page != last_page) {
-			buffer_mutex->lock();
+			buffer_mutex.lock();
 			if (pages[page].buffer.empty()) {
 				waiting_on_page = page;
 				for (int j = 0; j < read_ahead; j++) {
 
 					_queue_page(page + j);
 				}
-				buffer_mutex->unlock();
+				buffer_mutex.unlock();
 				DEBUG_PRINT("wait");
-				page_sem->wait();
+				page_sem.wait();
 				DEBUG_PRINT("done");
 			} else {
 
@@ -436,7 +425,7 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
 					_queue_page(page + j);
 				}
 				//queue pages
-				buffer_mutex->unlock();
+				buffer_mutex.unlock();
 			}
 
 			buff = pages.write[page].buffer.ptrw();
@@ -476,8 +465,8 @@ bool FileAccessNetwork::file_exists(const String &p_path) {
 	nc->client->put_data((const uint8_t *)cs.ptr(), cs.length());
 	nc->unlock_mutex();
 	DEBUG_PRINT("FILE EXISTS POST");
-	nc->sem->post();
-	sem->wait();
+	nc->sem.post();
+	sem.wait();
 
 	return exists_modtime != 0;
 }
@@ -493,8 +482,8 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
 	nc->client->put_data((const uint8_t *)cs.ptr(), cs.length());
 	nc->unlock_mutex();
 	DEBUG_PRINT("MODTIME POST");
-	nc->sem->post();
-	sem->wait();
+	nc->sem.post();
+	sem.wait();
 
 	return exists_modtime;
 }
@@ -522,9 +511,6 @@ FileAccessNetwork::FileAccessNetwork() {
 	eof_flag = false;
 	opened = false;
 	pos = 0;
-	sem = Semaphore::create();
-	page_sem = Semaphore::create();
-	buffer_mutex = Mutex::create();
 	FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
 	nc->lock_mutex();
 	id = nc->last_id++;
@@ -540,9 +526,6 @@ FileAccessNetwork::FileAccessNetwork() {
 FileAccessNetwork::~FileAccessNetwork() {
 
 	close();
-	memdelete(sem);
-	memdelete(page_sem);
-	memdelete(buffer_mutex);
 
 	FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
 	nc->lock_mutex();

+ 7 - 7
core/io/file_access_network.h

@@ -49,11 +49,11 @@ class FileAccessNetworkClient {
 
 	List<BlockRequest> block_requests;
 
-	Semaphore *sem;
-	Thread *thread;
+	Semaphore sem;
+	Thread thread;
 	bool quit;
-	Mutex *mutex;
-	Mutex *blockrequest_mutex;
+	Mutex mutex;
+	Mutex blockrequest_mutex;
 	Map<int, FileAccessNetwork *> accesses;
 	Ref<StreamPeerTCP> client;
 	int last_id;
@@ -85,9 +85,9 @@ public:
 
 class FileAccessNetwork : public FileAccess {
 
-	Semaphore *sem;
-	Semaphore *page_sem;
-	Mutex *buffer_mutex;
+	Semaphore sem;
+	Semaphore page_sem;
+	Mutex buffer_mutex;
 	bool opened;
 	size_t total_size;
 	mutable size_t pos;

+ 41 - 66
core/io/ip.cpp

@@ -42,13 +42,13 @@ struct _IP_ResolverPrivate {
 
 	struct QueueItem {
 
-		volatile IP::ResolverStatus status;
+		SafeNumeric<IP::ResolverStatus> status;
 		IP_Address response;
 		String hostname;
 		IP::Type type;
 
 		void clear() {
-			status = IP::RESOLVER_STATUS_NONE;
+			status.set(IP::RESOLVER_STATUS_NONE);
 			response = IP_Address();
 			type = IP::TYPE_NONE;
 			hostname = "";
@@ -64,16 +64,16 @@ struct _IP_ResolverPrivate {
 	IP::ResolverID find_empty_id() const {
 
 		for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
-			if (queue[i].status == IP::RESOLVER_STATUS_NONE)
+			if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE)
 				return i;
 		}
 		return IP::RESOLVER_INVALID_ID;
 	}
 
-	Mutex *mutex;
-	Semaphore *sem;
+	Mutex mutex;
+	Semaphore sem;
 
-	Thread *thread;
+	Thread thread;
 	//Semaphore* semaphore;
 	bool thread_abort;
 
@@ -81,14 +81,14 @@ struct _IP_ResolverPrivate {
 
 		for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
 
-			if (queue[i].status != IP::RESOLVER_STATUS_WAITING)
+			if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING)
 				continue;
 			queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
 
 			if (!queue[i].response.is_valid())
-				queue[i].status = IP::RESOLVER_STATUS_ERROR;
+				queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
 			else
-				queue[i].status = IP::RESOLVER_STATUS_DONE;
+				queue[i].status.set(IP::RESOLVER_STATUS_DONE);
 		}
 	}
 
@@ -98,11 +98,11 @@ struct _IP_ResolverPrivate {
 
 		while (!ipr->thread_abort) {
 
-			ipr->sem->wait();
+			ipr->sem.wait();
 
-			ipr->mutex->lock();
+			ipr->mutex.lock();
 			ipr->resolve_queues();
-			ipr->mutex->unlock();
+			ipr->mutex.unlock();
 		}
 	}
 
@@ -115,30 +115,30 @@ struct _IP_ResolverPrivate {
 
 IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
 
-	resolver->mutex->lock();
+	resolver->mutex.lock();
 
 	String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
 	if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
 		IP_Address res = resolver->cache[key];
-		resolver->mutex->unlock();
+		resolver->mutex.unlock();
 		return res;
 	}
 
 	IP_Address res = _resolve_hostname(p_hostname, p_type);
 	resolver->cache[key] = res;
-	resolver->mutex->unlock();
+	resolver->mutex.unlock();
 	return res;
 }
 
 IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Type p_type) {
 
-	resolver->mutex->lock();
+	resolver->mutex.lock();
 
 	ResolverID id = resolver->find_empty_id();
 
 	if (id == RESOLVER_INVALID_ID) {
 		WARN_PRINT("Out of resolver queries");
-		resolver->mutex->unlock();
+		resolver->mutex.unlock();
 		return id;
 	}
 
@@ -147,17 +147,17 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
 	resolver->queue[id].type = p_type;
 	if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
 		resolver->queue[id].response = resolver->cache[key];
-		resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
+		resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
 	} else {
 		resolver->queue[id].response = IP_Address();
-		resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
-		if (resolver->thread)
-			resolver->sem->post();
+		resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
+		if (resolver->thread.is_started())
+			resolver->sem.post();
 		else
 			resolver->resolve_queues();
 	}
 
-	resolver->mutex->unlock();
+	resolver->mutex.unlock();
 	return id;
 }
 
@@ -165,15 +165,15 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
 
 	ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP::RESOLVER_STATUS_NONE);
 
-	resolver->mutex->lock();
-	if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) {
+	resolver->mutex.lock();
+	if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
 		ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
-		resolver->mutex->unlock();
+		resolver->mutex.unlock();
 		return IP::RESOLVER_STATUS_NONE;
 	}
-	IP::ResolverStatus res = resolver->queue[p_id].status;
+	IP::ResolverStatus res = resolver->queue[p_id].status.get();
 
-	resolver->mutex->unlock();
+	resolver->mutex.unlock();
 	return res;
 }
 
@@ -181,17 +181,17 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
 
 	ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP_Address());
 
-	resolver->mutex->lock();
+	resolver->mutex.lock();
 
-	if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
+	if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
 		ERR_PRINTS("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
-		resolver->mutex->unlock();
+		resolver->mutex.unlock();
 		return IP_Address();
 	}
 
 	IP_Address res = resolver->queue[p_id].response;
 
-	resolver->mutex->unlock();
+	resolver->mutex.unlock();
 	return res;
 }
 
@@ -199,16 +199,16 @@ void IP::erase_resolve_item(ResolverID p_id) {
 
 	ERR_FAIL_INDEX(p_id, IP::RESOLVER_MAX_QUERIES);
 
-	resolver->mutex->lock();
+	resolver->mutex.lock();
 
-	resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE;
+	resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
 
-	resolver->mutex->unlock();
+	resolver->mutex.unlock();
 }
 
 void IP::clear_cache(const String &p_hostname) {
 
-	resolver->mutex->lock();
+	resolver->mutex.lock();
 
 	if (p_hostname.empty()) {
 		resolver->cache.clear();
@@ -219,7 +219,7 @@ void IP::clear_cache(const String &p_hostname) {
 		resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_ANY));
 	}
 
-	resolver->mutex->unlock();
+	resolver->mutex.unlock();
 }
 
 Array IP::_get_local_addresses() const {
@@ -314,41 +314,16 @@ IP::IP() {
 
 	singleton = this;
 	resolver = memnew(_IP_ResolverPrivate);
-	resolver->sem = NULL;
-	resolver->mutex = Mutex::create();
 
-#ifndef NO_THREADS
-
-	resolver->sem = Semaphore::create();
-	if (resolver->sem) {
-		resolver->thread_abort = false;
-
-		resolver->thread = Thread::create(_IP_ResolverPrivate::_thread_function, resolver);
-
-		if (!resolver->thread)
-			memdelete(resolver->sem); //wtf
-	} else {
-		resolver->thread = NULL;
-	}
-#else
-	resolver->sem = NULL;
-	resolver->thread = NULL;
-#endif
+	resolver->thread_abort = false;
+	resolver->thread.start(_IP_ResolverPrivate::_thread_function, resolver);
 }
 
 IP::~IP() {
 
-#ifndef NO_THREADS
-	if (resolver->thread) {
-		resolver->thread_abort = true;
-		resolver->sem->post();
-		Thread::wait_to_finish(resolver->thread);
-		memdelete(resolver->thread);
-		memdelete(resolver->sem);
-	}
-
-#endif
+	resolver->thread_abort = true;
+	resolver->sem.post();
+	resolver->thread.wait_to_finish();
 
-	memdelete(resolver->mutex);
 	memdelete(resolver);
 }

+ 12 - 42
core/io/resource_loader.cpp

@@ -289,9 +289,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
 bool ResourceLoader::_add_to_loading_map(const String &p_path) {
 
 	bool success;
-	if (loading_map_mutex) {
-		loading_map_mutex->lock();
-	}
+	loading_map_mutex.lock();
 
 	LoadingMapKey key;
 	key.path = p_path;
@@ -304,17 +302,13 @@ bool ResourceLoader::_add_to_loading_map(const String &p_path) {
 		success = true;
 	}
 
-	if (loading_map_mutex) {
-		loading_map_mutex->unlock();
-	}
+	loading_map_mutex.unlock();
 
 	return success;
 }
 
 void ResourceLoader::_remove_from_loading_map(const String &p_path) {
-	if (loading_map_mutex) {
-		loading_map_mutex->lock();
-	}
+	loading_map_mutex.lock();
 
 	LoadingMapKey key;
 	key.path = p_path;
@@ -322,15 +316,11 @@ void ResourceLoader::_remove_from_loading_map(const String &p_path) {
 
 	loading_map.erase(key);
 
-	if (loading_map_mutex) {
-		loading_map_mutex->unlock();
-	}
+	loading_map_mutex.unlock();
 }
 
 void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread) {
-	if (loading_map_mutex) {
-		loading_map_mutex->lock();
-	}
+	loading_map_mutex.lock();
 
 	LoadingMapKey key;
 	key.path = p_path;
@@ -338,9 +328,7 @@ void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, T
 
 	loading_map.erase(key);
 
-	if (loading_map_mutex) {
-		loading_map_mutex->unlock();
-	}
+	loading_map_mutex.unlock();
 }
 
 RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
@@ -362,9 +350,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
 		}
 
 		//lock first if possible
-		if (ResourceCache::lock) {
-			ResourceCache::lock->read_lock();
-		}
+		ResourceCache::lock.read_lock();
 
 		//get ptr
 		Resource **rptr = ResourceCache::resources.getptr(local_path);
@@ -376,16 +362,12 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
 				//referencing is fine
 				if (r_error)
 					*r_error = OK;
-				if (ResourceCache::lock) {
-					ResourceCache::lock->read_unlock();
-				}
+				ResourceCache::lock.read_unlock();
 				_remove_from_loading_map(local_path);
 				return res;
 			}
 		}
-		if (ResourceCache::lock) {
-			ResourceCache::lock->read_unlock();
-		}
+		ResourceCache::lock.read_unlock();
 	}
 
 	bool xl_remapped = false;
@@ -851,9 +833,7 @@ String ResourceLoader::path_remap(const String &p_path) {
 
 void ResourceLoader::reload_translation_remaps() {
 
-	if (ResourceCache::lock) {
-		ResourceCache::lock->read_lock();
-	}
+	ResourceCache::lock.read_lock();
 
 	List<Resource *> to_reload;
 	SelfList<Resource> *E = remapped_list.first();
@@ -863,9 +843,7 @@ void ResourceLoader::reload_translation_remaps() {
 		E = E->next();
 	}
 
-	if (ResourceCache::lock) {
-		ResourceCache::lock->read_unlock();
-	}
+	ResourceCache::lock.read_unlock();
 
 	//now just make sure to not delete any of these resources while changing locale..
 	while (to_reload.front()) {
@@ -1004,15 +982,9 @@ void ResourceLoader::remove_custom_loaders() {
 	}
 }
 
-Mutex *ResourceLoader::loading_map_mutex = NULL;
+Mutex ResourceLoader::loading_map_mutex;
 HashMap<ResourceLoader::LoadingMapKey, int, ResourceLoader::LoadingMapKeyHasher> ResourceLoader::loading_map;
 
-void ResourceLoader::initialize() {
-#ifndef NO_THREADS
-	loading_map_mutex = Mutex::create();
-#endif
-}
-
 void ResourceLoader::finalize() {
 #ifndef NO_THREADS
 	const LoadingMapKey *K = NULL;
@@ -1020,8 +992,6 @@ void ResourceLoader::finalize() {
 		ERR_PRINTS("Exited while resource is being loaded: " + K->path);
 	}
 	loading_map.clear();
-	memdelete(loading_map_mutex);
-	loading_map_mutex = NULL;
 #endif
 }
 

+ 1 - 2
core/io/resource_loader.h

@@ -120,7 +120,7 @@ class ResourceLoader {
 	static ResourceLoadedCallback _loaded_callback;
 
 	static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path);
-	static Mutex *loading_map_mutex;
+	static Mutex loading_map_mutex;
 
 	//used to track paths being loaded in a thread, avoids cyclic recursion
 	struct LoadingMapKey {
@@ -197,7 +197,6 @@ public:
 	static void add_custom_loaders();
 	static void remove_custom_loaders();
 
-	static void initialize();
 	static void finalize();
 };
 

+ 14 - 21
core/object.cpp

@@ -1946,7 +1946,7 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
 	if (!_script_instance_bindings[p_script_language_index]) {
 		void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
 		if (script_data) {
-			atomic_increment(&instance_binding_count);
+			instance_binding_count.increment();
 			_script_instance_bindings[p_script_language_index] = script_data;
 		}
 	}
@@ -1976,7 +1976,6 @@ Object::Object() {
 	_can_translate = true;
 	_is_queued_for_deletion = false;
 	_emitting = false;
-	instance_binding_count = 0;
 	memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
 	script_instance = NULL;
 #ifdef DEBUG_ENABLED
@@ -2068,30 +2067,30 @@ ObjectID ObjectDB::add_instance(Object *p_object) {
 
 	ERR_FAIL_COND_V(p_object->get_instance_id() != 0, 0);
 
-	rw_lock->write_lock();
+	rw_lock.write_lock();
 	ObjectID instance_id = ++instance_counter;
 	instances[instance_id] = p_object;
 	instance_checks[p_object] = instance_id;
 
-	rw_lock->write_unlock();
+	rw_lock.write_unlock();
 
 	return instance_id;
 }
 
 void ObjectDB::remove_instance(Object *p_object) {
 
-	rw_lock->write_lock();
+	rw_lock.write_lock();
 
 	instances.erase(p_object->get_instance_id());
 	instance_checks.erase(p_object);
 
-	rw_lock->write_unlock();
+	rw_lock.write_unlock();
 }
 Object *ObjectDB::get_instance(ObjectID p_instance_id) {
 
-	rw_lock->read_lock();
+	rw_lock.read_lock();
 	Object **obj = instances.getptr(p_instance_id);
-	rw_lock->read_unlock();
+	rw_lock.read_unlock();
 
 	if (!obj)
 		return NULL;
@@ -2100,7 +2099,7 @@ Object *ObjectDB::get_instance(ObjectID p_instance_id) {
 
 void ObjectDB::debug_objects(DebugFunc p_func) {
 
-	rw_lock->read_lock();
+	rw_lock.read_lock();
 
 	const ObjectID *K = NULL;
 	while ((K = instances.next(K))) {
@@ -2108,7 +2107,7 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
 		p_func(instances[*K]);
 	}
 
-	rw_lock->read_unlock();
+	rw_lock.read_unlock();
 }
 
 void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
@@ -2116,23 +2115,18 @@ void Object::get_argument_options(const StringName &p_function, int p_idx, List<
 
 int ObjectDB::get_object_count() {
 
-	rw_lock->read_lock();
+	rw_lock.read_lock();
 	int count = instances.size();
-	rw_lock->read_unlock();
+	rw_lock.read_unlock();
 
 	return count;
 }
 
-RWLock *ObjectDB::rw_lock = NULL;
-
-void ObjectDB::setup() {
-
-	rw_lock = RWLock::create();
-}
+RWLock ObjectDB::rw_lock;
 
 void ObjectDB::cleanup() {
 
-	rw_lock->write_lock();
+	rw_lock.write_lock();
 	if (instances.size()) {
 
 		WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
@@ -2159,6 +2153,5 @@ void ObjectDB::cleanup() {
 	}
 	instances.clear();
 	instance_checks.clear();
-	rw_lock->write_unlock();
-	memdelete(rw_lock);
+	rw_lock.write_unlock();
 }

+ 5 - 5
core/object.h

@@ -36,6 +36,7 @@
 #include "core/map.h"
 #include "core/object_id.h"
 #include "core/os/rw_lock.h"
+#include "core/safe_refcount.h"
 #include "core/set.h"
 #include "core/variant.h"
 #include "core/vmap.h"
@@ -512,7 +513,7 @@ private:
 	Variant _get_indexed_bind(const NodePath &p_name) const;
 
 	friend class Reference;
-	uint32_t instance_binding_count;
+	SafeNumeric<uint32_t> instance_binding_count;
 	void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
 
 protected:
@@ -791,12 +792,11 @@ class ObjectDB {
 	friend class Object;
 	friend void unregister_core_types();
 
-	static RWLock *rw_lock;
+	static RWLock rw_lock;
 	static void cleanup();
 	static ObjectID add_instance(Object *p_object);
 	static void remove_instance(Object *p_object);
 	friend void register_core_types();
-	static void setup();
 
 public:
 	typedef void (*DebugFunc)(Object *p_obj);
@@ -806,11 +806,11 @@ public:
 	static int get_object_count();
 
 	_FORCE_INLINE_ static bool instance_validate(Object *p_ptr) {
-		rw_lock->read_lock();
+		rw_lock.read_lock();
 
 		bool exists = instance_checks.has(p_ptr);
 
-		rw_lock->read_unlock();
+		rw_lock.read_unlock();
 
 		return exists;
 	}

+ 13 - 13
core/os/memory.cpp

@@ -65,11 +65,11 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
 #endif
 
 #ifdef DEBUG_ENABLED
-uint64_t Memory::mem_usage = 0;
-uint64_t Memory::max_usage = 0;
+SafeNumeric<uint64_t> Memory::mem_usage;
+SafeNumeric<uint64_t> Memory::max_usage;
 #endif
 
-uint64_t Memory::alloc_count = 0;
+SafeNumeric<uint64_t> Memory::alloc_count;
 
 void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
 
@@ -83,7 +83,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
 
 	ERR_FAIL_COND_V(!mem, NULL);
 
-	atomic_increment(&alloc_count);
+	alloc_count.increment();
 
 	if (prepad) {
 		uint64_t *s = (uint64_t *)mem;
@@ -92,8 +92,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
 		uint8_t *s8 = (uint8_t *)mem;
 
 #ifdef DEBUG_ENABLED
-		atomic_add(&mem_usage, p_bytes);
-		atomic_exchange_if_greater(&max_usage, mem_usage);
+		uint64_t new_mem_usage = mem_usage.add(p_bytes);
+		max_usage.exchange_if_greater(new_mem_usage);
 #endif
 		return s8 + PAD_ALIGN;
 	} else {
@@ -121,10 +121,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
 
 #ifdef DEBUG_ENABLED
 		if (p_bytes > *s) {
-			atomic_add(&mem_usage, p_bytes - *s);
-			atomic_exchange_if_greater(&max_usage, mem_usage);
+			uint64_t new_mem_usage = mem_usage.add(p_bytes - *s);
+			max_usage.exchange_if_greater(new_mem_usage);
 		} else {
-			atomic_sub(&mem_usage, *s - p_bytes);
+			mem_usage.sub(*s - p_bytes);
 		}
 #endif
 
@@ -165,14 +165,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
 	bool prepad = p_pad_align;
 #endif
 
-	atomic_decrement(&alloc_count);
+	alloc_count.decrement();
 
 	if (prepad) {
 		mem -= PAD_ALIGN;
 
 #ifdef DEBUG_ENABLED
 		uint64_t *s = (uint64_t *)mem;
-		atomic_sub(&mem_usage, *s);
+		mem_usage.sub(*s);
 #endif
 
 		free(mem);
@@ -189,7 +189,7 @@ uint64_t Memory::get_mem_available() {
 
 uint64_t Memory::get_mem_usage() {
 #ifdef DEBUG_ENABLED
-	return mem_usage;
+	return mem_usage.get();
 #else
 	return 0;
 #endif
@@ -197,7 +197,7 @@ uint64_t Memory::get_mem_usage() {
 
 uint64_t Memory::get_mem_max_usage() {
 #ifdef DEBUG_ENABLED
-	return max_usage;
+	return max_usage.get();
 #else
 	return 0;
 #endif

+ 3 - 3
core/os/memory.h

@@ -44,11 +44,11 @@ class Memory {
 
 	Memory();
 #ifdef DEBUG_ENABLED
-	static uint64_t mem_usage;
-	static uint64_t max_usage;
+	static SafeNumeric<uint64_t> mem_usage;
+	static SafeNumeric<uint64_t> max_usage;
 #endif
 
-	static uint64_t alloc_count;
+	static SafeNumeric<uint64_t> alloc_count;
 
 public:
 	static void *alloc_static(size_t p_bytes, bool p_pad_align = false);

+ 9 - 21
core/os/mutex.cpp

@@ -30,31 +30,19 @@
 
 #include "mutex.h"
 
-#include "core/error_macros.h"
+static Mutex _global_mutex;
 
-#include <stddef.h>
-
-Mutex *(*Mutex::create_func)(bool) = 0;
-
-Mutex *Mutex::create(bool p_recursive) {
-
-	ERR_FAIL_COND_V(!create_func, 0);
-
-	return create_func(p_recursive);
+void _global_lock() {
+	_global_mutex.lock();
 }
 
-Mutex::~Mutex() {
+void _global_unlock() {
+	_global_mutex.unlock();
 }
 
-Mutex *_global_mutex = NULL;
+#ifndef NO_THREADS
 
-void _global_lock() {
+template class MutexImpl<std::recursive_mutex>;
+template class MutexImpl<std::mutex>;
 
-	if (_global_mutex)
-		_global_mutex->lock();
-}
-void _global_unlock() {
-
-	if (_global_mutex)
-		_global_mutex->unlock();
-}
+#endif

+ 71 - 24
core/os/mutex.h

@@ -32,42 +32,89 @@
 #define MUTEX_H
 
 #include "core/error_list.h"
+#include "core/typedefs.h"
 
-/**
- * @class Mutex
- * @author Juan Linietsky
- * Portable Mutex (thread-safe locking) implementation.
- * Mutexes are always recursive ( they don't self-lock in a single thread ).
- * Mutexes can be used with a Lockp object like this, to avoid having to worry about unlocking:
- * Lockp( mutex );
- */
+#if !defined(NO_THREADS)
 
-class Mutex {
-protected:
-	static Mutex *(*create_func)(bool);
+#include <mutex>
+
+template <class StdMutexT>
+class MutexImpl {
+	mutable StdMutexT mutex;
+	friend class MutexLock;
 
 public:
-	virtual void lock() = 0; ///< Lock the mutex, block if locked by someone else
-	virtual void unlock() = 0; ///< Unlock the mutex, let other threads continue
-	virtual Error try_lock() = 0; ///< Attempt to lock the mutex, OK on success, ERROR means it can't lock.
+	_ALWAYS_INLINE_ void lock() const {
+		mutex.lock();
+	}
 
-	static Mutex *create(bool p_recursive = true); ///< Create a mutex
+	_ALWAYS_INLINE_ void unlock() const {
+		mutex.unlock();
+	}
 
-	virtual ~Mutex();
+	_ALWAYS_INLINE_ Error try_lock() const {
+		return mutex.try_lock() ? OK : ERR_BUSY;
+	}
 };
 
+// This is written this way instead of being a template to overcome a limitation of C++ pre-17
+// that would require MutexLock to be used like this: MutexLock<Mutex> lock;
 class MutexLock {
-
-	Mutex *mutex;
+	union {
+		std::recursive_mutex *recursive_mutex;
+		std::mutex *mutex;
+	};
+	bool recursive;
 
 public:
-	MutexLock(Mutex *p_mutex) {
-		mutex = p_mutex;
-		if (mutex) mutex->lock();
+	_ALWAYS_INLINE_ explicit MutexLock(const MutexImpl<std::recursive_mutex> &p_mutex) :
+			recursive_mutex(&p_mutex.mutex),
+			recursive(true) {
+		recursive_mutex->lock();
 	}
-	~MutexLock() {
-		if (mutex) mutex->unlock();
+	_ALWAYS_INLINE_ explicit MutexLock(const MutexImpl<std::mutex> &p_mutex) :
+			mutex(&p_mutex.mutex),
+			recursive(false) {
+		mutex->lock();
+	}
+
+	_ALWAYS_INLINE_ ~MutexLock() {
+		if (recursive) {
+			recursive_mutex->unlock();
+		} else {
+			mutex->unlock();
+		}
 	}
 };
 
-#endif
+using Mutex = MutexImpl<std::recursive_mutex>; // Recursive, for general use
+using BinaryMutex = MutexImpl<std::mutex>; // Non-recursive, handle with care
+
+extern template class MutexImpl<std::recursive_mutex>;
+extern template class MutexImpl<std::mutex>;
+
+#else
+
+class FakeMutex {
+	FakeMutex() {}
+};
+
+template <class MutexT>
+class MutexImpl {
+public:
+	_ALWAYS_INLINE_ void lock() const {}
+	_ALWAYS_INLINE_ void unlock() const {}
+	_ALWAYS_INLINE_ Error try_lock() const { return OK; }
+};
+
+class MutexLock {
+public:
+	explicit MutexLock(const MutexImpl<FakeMutex> &p_mutex) {}
+};
+
+using Mutex = MutexImpl<FakeMutex>;
+using BinaryMutex = MutexImpl<FakeMutex>; // Non-recursive, handle with care
+
+#endif // !NO_THREADS
+
+#endif // MUTEX_H

+ 0 - 2
core/os/os.h

@@ -41,8 +41,6 @@
 
 #include <stdarg.h>
 
-class Mutex;
-
 class OS {
 
 	static OS *singleton;

+ 0 - 47
core/os/rw_lock.cpp

@@ -1,47 +0,0 @@
-/*************************************************************************/
-/*  rw_lock.cpp                                                          */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "rw_lock.h"
-
-#include "core/error_macros.h"
-
-#include <stddef.h>
-
-RWLock *(*RWLock::create_func)() = 0;
-
-RWLock *RWLock::create() {
-
-	ERR_FAIL_COND_V(!create_func, 0);
-
-	return create_func();
-}
-
-RWLock::~RWLock() {
-}

+ 56 - 20
core/os/rw_lock.h

@@ -33,49 +33,85 @@
 
 #include "core/error_list.h"
 
+#if !defined(NO_THREADS)
+
+#include <shared_mutex>
+
 class RWLock {
-protected:
-	static RWLock *(*create_func)();
+	mutable std::shared_timed_mutex mutex;
 
 public:
-	virtual void read_lock() = 0; ///< Lock the rwlock, block if locked by someone else
-	virtual void read_unlock() = 0; ///< Unlock the rwlock, let other threads continue
-	virtual Error read_try_lock() = 0; ///< Attempt to lock the rwlock, OK on success, ERROR means it can't lock.
+	// Lock the rwlock, block if locked by someone else
+	void read_lock() const {
+		mutex.lock_shared();
+	}
 
-	virtual void write_lock() = 0; ///< Lock the rwlock, block if locked by someone else
-	virtual void write_unlock() = 0; ///< Unlock the rwlock, let other thwrites continue
-	virtual Error write_try_lock() = 0; ///< Attempt to lock the rwlock, OK on success, ERROR means it can't lock.
+	// Unlock the rwlock, let other threads continue
+	void read_unlock() const {
+		mutex.unlock_shared();
+	}
 
-	static RWLock *create(); ///< Create a rwlock
+	// Attempt to lock the rwlock, OK on success, ERR_BUSY means it can't lock.
+	Error read_try_lock() const {
+		return mutex.try_lock_shared() ? OK : ERR_BUSY;
+	}
+
+	// Lock the rwlock, block if locked by someone else
+	void write_lock() {
+		mutex.lock();
+	}
+
+	// Unlock the rwlock, let other thwrites continue
+	void write_unlock() {
+		mutex.unlock();
+	}
 
-	virtual ~RWLock();
+	// Attempt to lock the rwlock, OK on success, ERR_BUSY means it can't lock.
+	Error write_try_lock() {
+		return mutex.try_lock() ? OK : ERR_BUSY;
+	}
+};
+
+#else
+
+class RWLock {
+public:
+	void read_lock() const {}
+	void read_unlock() const {}
+	Error read_try_lock() const { return OK; }
+
+	void write_lock() {}
+	void write_unlock() {}
+	Error write_try_lock() { return OK; }
 };
 
+#endif
+
 class RWLockRead {
 
-	RWLock *lock;
+	const RWLock &lock;
 
 public:
-	RWLockRead(const RWLock *p_lock) {
-		lock = const_cast<RWLock *>(p_lock);
-		if (lock) lock->read_lock();
+	RWLockRead(const RWLock &p_lock) :
+			lock(p_lock) {
+		lock.read_lock();
 	}
 	~RWLockRead() {
-		if (lock) lock->read_unlock();
+		lock.read_unlock();
 	}
 };
 
 class RWLockWrite {
 
-	RWLock *lock;
+	RWLock &lock;
 
 public:
-	RWLockWrite(RWLock *p_lock) {
-		lock = p_lock;
-		if (lock) lock->write_lock();
+	RWLockWrite(RWLock &p_lock) :
+			lock(p_lock) {
+		lock.write_lock();
 	}
 	~RWLockWrite() {
-		if (lock) lock->write_unlock();
+		lock.write_unlock();
 	}
 };
 

+ 0 - 45
core/os/semaphore.cpp

@@ -1,45 +0,0 @@
-/*************************************************************************/
-/*  semaphore.cpp                                                        */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "semaphore.h"
-
-#include "core/error_macros.h"
-
-Semaphore *(*Semaphore::create_func)() = 0;
-
-Semaphore *Semaphore::create() {
-
-	ERR_FAIL_COND_V(!create_func, 0);
-
-	return create_func();
-}
-
-Semaphore::~Semaphore() {
-}

+ 47 - 7
core/os/semaphore.h

@@ -32,19 +32,59 @@
 #define SEMAPHORE_H
 
 #include "core/error_list.h"
+#include "core/typedefs.h"
+
+#if !defined(NO_THREADS)
+
+#include <condition_variable>
+#include <mutex>
 
 class Semaphore {
-protected:
-	static Semaphore *(*create_func)();
+private:
+	mutable std::mutex mutex_;
+	mutable std::condition_variable condition_;
+	mutable unsigned long count_ = 0; // Initialized as locked.
 
 public:
-	virtual Error wait() = 0; ///< wait until semaphore has positive value, then decrement and pass
-	virtual Error post() = 0; ///< unlock the semaphore, incrementing the    value
-	virtual int get() const = 0; ///< get semaphore value
+	_ALWAYS_INLINE_ void post() const {
+		std::lock_guard<decltype(mutex_)> lock(mutex_);
+		++count_;
+		condition_.notify_one();
+	}
+
+	_ALWAYS_INLINE_ void wait() const {
+		std::unique_lock<decltype(mutex_)> lock(mutex_);
+		while (!count_) { // Handle spurious wake-ups.
+			condition_.wait(lock);
+		}
+		--count_;
+	}
 
-	static Semaphore *create(); ///< Create a mutex
+	_ALWAYS_INLINE_ bool try_wait() const {
+		std::lock_guard<decltype(mutex_)> lock(mutex_);
+		if (count_) {
+			--count_;
+			return true;
+		}
+		return false;
+	}
 
-	virtual ~Semaphore();
+	_ALWAYS_INLINE_ int get() const {
+		std::lock_guard<decltype(mutex_)> lock(mutex_);
+		return count_;
+	}
+};
+
+#else
+
+class Semaphore {
+public:
+	_ALWAYS_INLINE_ void post() const {}
+	_ALWAYS_INLINE_ void wait() const {}
+	_ALWAYS_INLINE_ bool try_wait() const { return true; }
+	_ALWAYS_INLINE_ int get() const { return 1; }
 };
 
 #endif
+
+#endif // SEMAPHORE_H

+ 70 - 22
core/os/thread.cpp

@@ -30,45 +30,93 @@
 
 #include "thread.h"
 
-Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = NULL;
-Thread::ID (*Thread::get_thread_id_func)() = NULL;
-void (*Thread::wait_to_finish_func)(Thread *) = NULL;
-Error (*Thread::set_name_func)(const String &) = NULL;
+#include "core/script_language.h"
 
-Thread::ID Thread::_main_thread_id = 0;
+#if !defined(NO_THREADS)
 
-Thread::ID Thread::get_caller_id() {
+#include "core/safe_refcount.h"
 
-	if (get_thread_id_func)
-		return get_thread_id_func();
-	return 0;
-}
+Error (*Thread::set_name_func)(const String &) = nullptr;
+void (*Thread::set_priority_func)(Thread::Priority) = nullptr;
+void (*Thread::init_func)() = nullptr;
+void (*Thread::term_func)() = nullptr;
 
-Thread *Thread::create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings) {
+Thread::ID Thread::main_thread_id = 1;
+SafeNumeric<Thread::ID> Thread::last_thread_id{ 1 };
+thread_local Thread::ID Thread::caller_id = 1;
 
-	if (create_func) {
+void Thread::_set_platform_funcs(
+		Error (*p_set_name_func)(const String &),
+		void (*p_set_priority_func)(Thread::Priority),
+		void (*p_init_func)(),
+		void (*p_term_func)()) {
+	Thread::set_name_func = p_set_name_func;
+	Thread::set_priority_func = p_set_priority_func;
+	Thread::init_func = p_init_func;
+	Thread::term_func = p_term_func;
+}
 
-		return create_func(p_callback, p_user, p_settings);
+void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) {
+	Thread::caller_id = p_self->id;
+	if (set_priority_func) {
+		set_priority_func(p_settings.priority);
+	}
+	if (init_func) {
+		init_func();
+	}
+	ScriptServer::thread_enter(); //scripts may need to attach a stack
+	p_callback(p_userdata);
+	ScriptServer::thread_exit();
+	if (term_func) {
+		term_func();
 	}
-	return NULL;
 }
 
-void Thread::wait_to_finish(Thread *p_thread) {
+void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_settings) {
+	if (id != 0) {
+#ifdef DEBUG_ENABLED
+		WARN_PRINT("A Thread object has been re-started without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
+#endif
+		thread.detach();
+		std::thread empty_thread;
+		thread.swap(empty_thread);
+	}
+	id = last_thread_id.increment();
+	std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user);
+	thread.swap(new_thread);
+}
 
-	if (wait_to_finish_func)
-		wait_to_finish_func(p_thread);
+bool Thread::is_started() const {
+	return id != 0;
 }
 
-Error Thread::set_name(const String &p_name) {
+void Thread::wait_to_finish() {
+	if (id != 0) {
+		thread.join();
+		std::thread empty_thread;
+		thread.swap(empty_thread);
+		id = 0;
+	}
+}
 
-	if (set_name_func)
+Error Thread::set_name(const String &p_name) {
+	if (set_name_func) {
 		return set_name_func(p_name);
+	}
 
 	return ERR_UNAVAILABLE;
-};
-
-Thread::Thread() {
 }
 
+Thread::Thread() :
+		id(0) {}
+
 Thread::~Thread() {
+	if (id != 0) {
+#ifdef DEBUG_ENABLED
+		WARN_PRINT("A Thread object has been destroyed without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
+#endif
+		thread.detach();
+	}
 }
+
+#endif

+ 57 - 20
core/os/thread.h

@@ -32,49 +32,86 @@
 #define THREAD_H
 
 #include "core/typedefs.h"
-#include "core/ustring.h"
 
-typedef void (*ThreadCreateCallback)(void *p_userdata);
+#if !defined(NO_THREADS)
+#include "core/safe_refcount.h"
+#include <thread>
+#endif
+
+class String;
 
 class Thread {
 public:
-	enum Priority {
+	typedef void (*Callback)(void *p_userdata);
+
+	typedef uint64_t ID;
 
+	enum Priority {
 		PRIORITY_LOW,
 		PRIORITY_NORMAL,
 		PRIORITY_HIGH
 	};
 
 	struct Settings {
-
 		Priority priority;
 		Settings() { priority = PRIORITY_NORMAL; }
 	};
 
-	typedef uint64_t ID;
+private:
+#if !defined(NO_THREADS)
+	friend class Main;
 
-protected:
-	static Thread *(*create_func)(ThreadCreateCallback p_callback, void *, const Settings &);
-	static ID (*get_thread_id_func)();
-	static void (*wait_to_finish_func)(Thread *);
-	static Error (*set_name_func)(const String &);
+	static ID main_thread_id;
+	static SafeNumeric<ID> last_thread_id;
 
-	friend class Main;
+	ID id;
+	static thread_local ID caller_id;
+	std::thread thread;
 
-	static ID _main_thread_id;
+	static void callback(Thread *p_self, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata);
 
-	Thread();
+	static Error (*set_name_func)(const String &);
+	static void (*set_priority_func)(Thread::Priority);
+	static void (*init_func)();
+	static void (*term_func)();
+#endif
 
 public:
-	virtual ID get_id() const = 0;
+	static void _set_platform_funcs(
+			Error (*p_set_name_func)(const String &),
+			void (*p_set_priority_func)(Thread::Priority),
+			void (*p_init_func)() = nullptr,
+			void (*p_term_func)() = nullptr);
+
+#if !defined(NO_THREADS)
+	_FORCE_INLINE_ ID get_id() const { return id; }
+	// get the ID of the caller thread
+	_FORCE_INLINE_ static ID get_caller_id() { return caller_id; }
+	// get the ID of the main thread
+	_FORCE_INLINE_ static ID get_main_id() { return main_thread_id; }
 
 	static Error set_name(const String &p_name);
-	_FORCE_INLINE_ static ID get_main_id() { return _main_thread_id; } ///< get the ID of the main thread
-	static ID get_caller_id(); ///< get the ID of the caller function ID
-	static void wait_to_finish(Thread *p_thread); ///< waits until thread is finished
-	static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings()); ///< Static function to create a thread, will call p_callback
 
-	virtual ~Thread();
-};
+	void start(Thread::Callback p_callback, void *p_user, const Settings &p_settings = Settings());
+	bool is_started() const;
+	///< waits until thread is finished, and deallocates it.
+	void wait_to_finish();
 
+	Thread();
+	~Thread();
+#else
+	_FORCE_INLINE_ ID get_id() const { return 0; }
+	// get the ID of the caller thread
+	_FORCE_INLINE_ static ID get_caller_id() { return 0; }
+	// get the ID of the main thread
+	_FORCE_INLINE_ static ID get_main_id() { return 0; }
+
+	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
+};
+
+#endif // THREAD_H

+ 0 - 65
core/os/thread_dummy.cpp

@@ -1,65 +0,0 @@
-/*************************************************************************/
-/*  thread_dummy.cpp                                                     */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "thread_dummy.h"
-
-#include "core/os/memory.h"
-
-Thread *ThreadDummy::create(ThreadCreateCallback p_callback, void *p_user, const Thread::Settings &p_settings) {
-	return memnew(ThreadDummy);
-};
-
-void ThreadDummy::make_default() {
-	Thread::create_func = &ThreadDummy::create;
-};
-
-Mutex *MutexDummy::create(bool p_recursive) {
-	return memnew(MutexDummy);
-};
-
-void MutexDummy::make_default() {
-	Mutex::create_func = &MutexDummy::create;
-};
-
-Semaphore *SemaphoreDummy::create() {
-	return memnew(SemaphoreDummy);
-};
-
-void SemaphoreDummy::make_default() {
-	Semaphore::create_func = &SemaphoreDummy::create;
-};
-
-RWLock *RWLockDummy::create() {
-	return memnew(RWLockDummy);
-};
-
-void RWLockDummy::make_default() {
-	RWLock::create_func = &RWLockDummy::create;
-};

+ 0 - 89
core/os/thread_dummy.h

@@ -1,89 +0,0 @@
-/*************************************************************************/
-/*  thread_dummy.h                                                       */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef THREAD_DUMMY_H
-#define THREAD_DUMMY_H
-
-#include "core/os/mutex.h"
-#include "core/os/rw_lock.h"
-#include "core/os/semaphore.h"
-#include "core/os/thread.h"
-
-class ThreadDummy : public Thread {
-
-	static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings());
-
-public:
-	virtual ID get_id() const { return 0; };
-
-	static void make_default();
-};
-
-class MutexDummy : public Mutex {
-
-	static Mutex *create(bool p_recursive);
-
-public:
-	virtual void lock(){};
-	virtual void unlock(){};
-	virtual Error try_lock() { return OK; };
-
-	static void make_default();
-};
-
-class SemaphoreDummy : public Semaphore {
-
-	static Semaphore *create();
-
-public:
-	virtual Error wait() { return OK; };
-	virtual Error post() { return OK; };
-	virtual int get() const { return 0; }; ///< get semaphore value
-
-	static void make_default();
-};
-
-class RWLockDummy : public RWLock {
-
-	static RWLock *create();
-
-public:
-	virtual void read_lock() {}
-	virtual void read_unlock() {}
-	virtual Error read_try_lock() { return OK; }
-
-	virtual void write_lock() {}
-	virtual void write_unlock() {}
-	virtual Error write_try_lock() { return OK; }
-
-	static void make_default();
-};
-
-#endif

+ 0 - 49
core/os/thread_safe.cpp

@@ -1,49 +0,0 @@
-/*************************************************************************/
-/*  thread_safe.cpp                                                      */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "thread_safe.h"
-
-#include "core/error_macros.h"
-#include "core/os/memory.h"
-
-ThreadSafe::ThreadSafe() {
-
-	mutex = Mutex::create();
-	if (!mutex) {
-
-		WARN_PRINT("THREAD_SAFE defined, but no default mutex type");
-	}
-}
-
-ThreadSafe::~ThreadSafe() {
-
-	if (mutex)
-		memdelete(mutex);
-}

+ 4 - 45
core/os/thread_safe.h

@@ -33,50 +33,9 @@
 
 #include "core/os/mutex.h"
 
-class ThreadSafe {
-
-	Mutex *mutex;
-
-public:
-	inline void lock() const {
-		if (mutex) mutex->lock();
-	}
-	inline void unlock() const {
-		if (mutex) mutex->unlock();
-	}
-
-	ThreadSafe();
-	~ThreadSafe();
-};
-
-class ThreadSafeMethod {
-
-	const ThreadSafe *_ts;
-
-public:
-	ThreadSafeMethod(const ThreadSafe *p_ts) {
-
-		_ts = p_ts;
-		_ts->lock();
-	}
-
-	~ThreadSafeMethod() { _ts->unlock(); }
-};
-
-#ifndef NO_THREADS
-
-#define _THREAD_SAFE_CLASS_ ThreadSafe __thread__safe__;
-#define _THREAD_SAFE_METHOD_ ThreadSafeMethod __thread_safe_method__(&__thread__safe__);
-#define _THREAD_SAFE_LOCK_ __thread__safe__.lock();
-#define _THREAD_SAFE_UNLOCK_ __thread__safe__.unlock();
-
-#else
-
-#define _THREAD_SAFE_CLASS_
-#define _THREAD_SAFE_METHOD_
-#define _THREAD_SAFE_LOCK_
-#define _THREAD_SAFE_UNLOCK_
-
-#endif
+#define _THREAD_SAFE_CLASS_ mutable Mutex _thread_safe_;
+#define _THREAD_SAFE_METHOD_ MutexLock _thread_safe_method_(_thread_safe_);
+#define _THREAD_SAFE_LOCK_ _thread_safe_.lock();
+#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
 
 #endif

+ 11 - 12
core/os/threaded_array_processor.h

@@ -40,7 +40,7 @@
 template <class C, class U>
 struct ThreadArrayProcessData {
 	uint32_t elements;
-	uint32_t index;
+	SafeNumeric<uint32_t> index;
 	C *instance;
 	U userdata;
 	void (C::*method)(uint32_t, U);
@@ -57,7 +57,7 @@ void process_array_thread(void *ud) {
 
 	T &data = *(T *)ud;
 	while (true) {
-		uint32_t index = atomic_increment(&data.index);
+		uint32_t index = data.index.increment();
 		if (index >= data.elements)
 			break;
 		data.process(index);
@@ -71,22 +71,21 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
 	data.method = p_method;
 	data.instance = p_instance;
 	data.userdata = p_userdata;
-	data.index = 0;
+	data.index.set(0);
 	data.elements = p_elements;
-	data.process(data.index); //process first, let threads increment for next
-
-	Vector<Thread *> threads;
+	data.process(0); //process first, let threads increment for next
 
-	threads.resize(OS::get_singleton()->get_processor_count());
+	int thread_count = OS::get_singleton()->get_processor_count();
+	Thread *threads = memnew_arr(Thread, thread_count);
 
-	for (int i = 0; i < threads.size(); i++) {
-		threads.write[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U> >, &data);
+	for (int i = 0; i < thread_count; i++) {
+		threads[i].start(process_array_thread<ThreadArrayProcessData<C, U> >, &data);
 	}
 
-	for (int i = 0; i < threads.size(); i++) {
-		Thread::wait_to_finish(threads[i]);
-		memdelete(threads[i]);
+	for (int i = 0; i < thread_count; i++) {
+		threads[i].wait_to_finish();
 	}
+	memdelete_arr(threads);
 }
 
 #else

+ 2 - 5
core/pool_vector.cpp

@@ -30,7 +30,7 @@
 
 #include "pool_vector.h"
 
-Mutex *pool_vector_lock = NULL;
+Mutex pool_vector_lock;
 
 PoolAllocator *MemoryPool::memory_pool = NULL;
 uint8_t *MemoryPool::pool_memory = NULL;
@@ -40,7 +40,7 @@ MemoryPool::Alloc *MemoryPool::allocs = NULL;
 MemoryPool::Alloc *MemoryPool::free_list = NULL;
 uint32_t MemoryPool::alloc_count = 0;
 uint32_t MemoryPool::allocs_used = 0;
-Mutex *MemoryPool::alloc_mutex = NULL;
+Mutex MemoryPool::alloc_mutex;
 
 size_t MemoryPool::total_memory = 0;
 size_t MemoryPool::max_memory = 0;
@@ -57,14 +57,11 @@ void MemoryPool::setup(uint32_t p_max_allocs) {
 	}
 
 	free_list = &allocs[0];
-
-	alloc_mutex = Mutex::create();
 }
 
 void MemoryPool::cleanup() {
 
 	memdelete_arr(allocs);
-	memdelete(alloc_mutex);
 
 	ERR_FAIL_COND_MSG(allocs_used > 0, "There are still MemoryPool allocs in use at exit!");
 }

+ 26 - 25
core/pool_vector.h

@@ -33,6 +33,7 @@
 
 #include "core/os/copymem.h"
 #include "core/os/memory.h"
+#include "core/os/mutex.h"
 #include "core/os/rw_lock.h"
 #include "core/pool_allocator.h"
 #include "core/safe_refcount.h"
@@ -49,7 +50,7 @@ struct MemoryPool {
 	struct Alloc {
 
 		SafeRefCount refcount;
-		uint32_t lock;
+		SafeNumeric<uint32_t> lock;
 		void *mem;
 		PoolAllocator::ID pool_id;
 		size_t size;
@@ -69,7 +70,7 @@ struct MemoryPool {
 	static Alloc *free_list;
 	static uint32_t alloc_count;
 	static uint32_t allocs_used;
-	static Mutex *alloc_mutex;
+	static Mutex alloc_mutex;
 	static size_t total_memory;
 	static size_t max_memory;
 
@@ -95,9 +96,9 @@ class PoolVector {
 
 		//must allocate something
 
-		MemoryPool::alloc_mutex->lock();
+		MemoryPool::alloc_mutex.lock();
 		if (MemoryPool::allocs_used == MemoryPool::alloc_count) {
-			MemoryPool::alloc_mutex->unlock();
+			MemoryPool::alloc_mutex.unlock();
 			ERR_FAIL_MSG("All memory pool allocations are in use, can't COW.");
 		}
 
@@ -113,7 +114,7 @@ class PoolVector {
 		alloc->size = old_alloc->size;
 		alloc->refcount.init();
 		alloc->pool_id = POOL_ALLOCATOR_INVALID_ID;
-		alloc->lock = 0;
+		alloc->lock.set(0);
 
 #ifdef DEBUG_ENABLED
 		MemoryPool::total_memory += alloc->size;
@@ -122,7 +123,7 @@ class PoolVector {
 		}
 #endif
 
-		MemoryPool::alloc_mutex->unlock();
+		MemoryPool::alloc_mutex.unlock();
 
 		if (MemoryPool::memory_pool) {
 
@@ -148,9 +149,9 @@ class PoolVector {
 			//this should never happen but..
 
 #ifdef DEBUG_ENABLED
-			MemoryPool::alloc_mutex->lock();
+			MemoryPool::alloc_mutex.lock();
 			MemoryPool::total_memory -= old_alloc->size;
-			MemoryPool::alloc_mutex->unlock();
+			MemoryPool::alloc_mutex.unlock();
 #endif
 
 			{
@@ -174,11 +175,11 @@ class PoolVector {
 				old_alloc->mem = NULL;
 				old_alloc->size = 0;
 
-				MemoryPool::alloc_mutex->lock();
+				MemoryPool::alloc_mutex.lock();
 				old_alloc->free_list = MemoryPool::free_list;
 				MemoryPool::free_list = old_alloc;
 				MemoryPool::allocs_used--;
-				MemoryPool::alloc_mutex->unlock();
+				MemoryPool::alloc_mutex.unlock();
 			}
 		}
 	}
@@ -227,9 +228,9 @@ class PoolVector {
 		}
 
 #ifdef DEBUG_ENABLED
-		MemoryPool::alloc_mutex->lock();
+		MemoryPool::alloc_mutex.lock();
 		MemoryPool::total_memory -= alloc->size;
-		MemoryPool::alloc_mutex->unlock();
+		MemoryPool::alloc_mutex.unlock();
 #endif
 
 		if (MemoryPool::memory_pool) {
@@ -242,11 +243,11 @@ class PoolVector {
 			alloc->mem = NULL;
 			alloc->size = 0;
 
-			MemoryPool::alloc_mutex->lock();
+			MemoryPool::alloc_mutex.lock();
 			alloc->free_list = MemoryPool::free_list;
 			MemoryPool::free_list = alloc;
 			MemoryPool::allocs_used--;
-			MemoryPool::alloc_mutex->unlock();
+			MemoryPool::alloc_mutex.unlock();
 		}
 
 		alloc = NULL;
@@ -263,7 +264,7 @@ public:
 		_FORCE_INLINE_ void _ref(MemoryPool::Alloc *p_alloc) {
 			alloc = p_alloc;
 			if (alloc) {
-				if (atomic_increment(&alloc->lock) == 1) {
+				if (alloc->lock.increment() == 1) {
 					if (MemoryPool::memory_pool) {
 						//lock it and get mem
 					}
@@ -276,7 +277,7 @@ public:
 		_FORCE_INLINE_ void _unref() {
 
 			if (alloc) {
-				if (atomic_decrement(&alloc->lock) == 0) {
+				if (alloc->lock.decrement() == 0) {
 					if (MemoryPool::memory_pool) {
 						//put mem back
 					}
@@ -452,7 +453,7 @@ public:
 		return rs;
 	}
 
-	bool is_locked() const { return alloc && alloc->lock > 0; }
+	bool is_locked() const { return alloc && alloc->lock.get() > 0; }
 
 	inline T operator[](int p_index) const;
 
@@ -523,9 +524,9 @@ Error PoolVector<T>::resize(int p_size) {
 			return OK; //nothing to do here
 
 		//must allocate something
-		MemoryPool::alloc_mutex->lock();
+		MemoryPool::alloc_mutex.lock();
 		if (MemoryPool::allocs_used == MemoryPool::alloc_count) {
-			MemoryPool::alloc_mutex->unlock();
+			MemoryPool::alloc_mutex.unlock();
 			ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "All memory pool allocations are in use.");
 		}
 
@@ -539,11 +540,11 @@ Error PoolVector<T>::resize(int p_size) {
 		alloc->size = 0;
 		alloc->refcount.init();
 		alloc->pool_id = POOL_ALLOCATOR_INVALID_ID;
-		MemoryPool::alloc_mutex->unlock();
+		MemoryPool::alloc_mutex.unlock();
 
 	} else {
 
-		ERR_FAIL_COND_V_MSG(alloc->lock > 0, ERR_LOCKED, "Can't resize PoolVector if locked."); //can't resize if locked!
+		ERR_FAIL_COND_V_MSG(alloc->lock.get() > 0, ERR_LOCKED, "Can't resize PoolVector if locked."); //can't resize if locked!
 	}
 
 	size_t new_size = sizeof(T) * p_size;
@@ -559,13 +560,13 @@ Error PoolVector<T>::resize(int p_size) {
 	_copy_on_write(); // make it unique
 
 #ifdef DEBUG_ENABLED
-	MemoryPool::alloc_mutex->lock();
+	MemoryPool::alloc_mutex.lock();
 	MemoryPool::total_memory -= alloc->size;
 	MemoryPool::total_memory += new_size;
 	if (MemoryPool::total_memory > MemoryPool::max_memory) {
 		MemoryPool::max_memory = MemoryPool::total_memory;
 	}
-	MemoryPool::alloc_mutex->unlock();
+	MemoryPool::alloc_mutex.unlock();
 #endif
 
 	int cur_elements = alloc->size / sizeof(T);
@@ -615,11 +616,11 @@ Error PoolVector<T>::resize(int p_size) {
 				alloc->mem = NULL;
 				alloc->size = 0;
 
-				MemoryPool::alloc_mutex->lock();
+				MemoryPool::alloc_mutex.lock();
 				alloc->free_list = MemoryPool::free_list;
 				MemoryPool::free_list = alloc;
 				MemoryPool::allocs_used--;
-				MemoryPool::alloc_mutex->unlock();
+				MemoryPool::alloc_mutex.unlock();
 
 			} else {
 				alloc->mem = memrealloc(alloc->mem, new_size);

+ 2 - 2
core/reference.cpp

@@ -67,7 +67,7 @@ bool Reference::reference() {
 		if (get_script_instance()) {
 			get_script_instance()->refcount_incremented();
 		}
-		if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
+		if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
 			for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
 				if (_script_instance_bindings[i]) {
 					ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
@@ -89,7 +89,7 @@ bool Reference::unreference() {
 			bool script_ret = get_script_instance()->refcount_decremented();
 			die = die && script_ret;
 		}
-		if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
+		if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
 			for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
 				if (_script_instance_bindings[i]) {
 					bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);

+ 1 - 11
core/register_core_types.cpp

@@ -90,7 +90,7 @@ static IP *ip = NULL;
 
 static _Geometry *_geometry = NULL;
 
-extern Mutex *_global_mutex;
+extern Mutex _global_mutex;
 
 extern void register_global_constants();
 extern void unregister_global_constants();
@@ -99,14 +99,9 @@ extern void unregister_variant_methods();
 
 void register_core_types() {
 
-	ObjectDB::setup();
-	ResourceCache::setup();
 	MemoryPool::setup();
 
-	_global_mutex = Mutex::create();
-
 	StringName::setup();
-	ResourceLoader::initialize();
 
 	register_global_constants();
 	register_variant_methods();
@@ -318,10 +313,5 @@ void unregister_core_types() {
 	CoreStringNames::free();
 	StringName::cleanup();
 
-	if (_global_mutex) {
-		memdelete(_global_mutex);
-		_global_mutex = NULL; //still needed at a few places
-	};
-
 	MemoryPool::cleanup();
 }

+ 33 - 60
core/resource.cpp

@@ -54,30 +54,30 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
 
 	if (path_cache != "") {
 
-		ResourceCache::lock->write_lock();
+		ResourceCache::lock.write_lock();
 		ResourceCache::resources.erase(path_cache);
-		ResourceCache::lock->write_unlock();
+		ResourceCache::lock.write_unlock();
 	}
 
 	path_cache = "";
 
-	ResourceCache::lock->read_lock();
+	ResourceCache::lock.read_lock();
 	bool has_path = ResourceCache::resources.has(p_path);
-	ResourceCache::lock->read_unlock();
+	ResourceCache::lock.read_unlock();
 
 	if (has_path) {
 		if (p_take_over) {
 
-			ResourceCache::lock->write_lock();
+			ResourceCache::lock.write_lock();
 			Resource **res = ResourceCache::resources.getptr(p_path);
 			if (res) {
 				(*res)->set_name("");
 			}
-			ResourceCache::lock->write_unlock();
+			ResourceCache::lock.write_unlock();
 		} else {
-			ResourceCache::lock->read_lock();
+			ResourceCache::lock.read_lock();
 			bool exists = ResourceCache::resources.has(p_path);
-			ResourceCache::lock->read_unlock();
+			ResourceCache::lock.read_unlock();
 
 			ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
 		}
@@ -86,9 +86,9 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
 
 	if (path_cache != "") {
 
-		ResourceCache::lock->write_lock();
+		ResourceCache::lock.write_lock();
 		ResourceCache::resources[path_cache] = this;
-		ResourceCache::lock->write_unlock();
+		ResourceCache::lock.write_unlock();
 	}
 
 	_change_notify("resource_path");
@@ -343,9 +343,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
 	if (remapped_list.in_list() == p_remapped)
 		return;
 
-	if (ResourceCache::lock) {
-		ResourceCache::lock->write_lock();
-	}
+	ResourceCache::lock.write_lock();
 
 	if (p_remapped) {
 		ResourceLoader::remapped_list.add(&remapped_list);
@@ -353,9 +351,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
 		ResourceLoader::remapped_list.remove(&remapped_list);
 	}
 
-	if (ResourceCache::lock) {
-		ResourceCache::lock->write_unlock();
-	}
+	ResourceCache::lock.write_unlock();
 }
 
 bool Resource::is_translation_remapped() const {
@@ -367,38 +363,24 @@ bool Resource::is_translation_remapped() const {
 //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
 void Resource::set_id_for_path(const String &p_path, int p_id) {
 	if (p_id == -1) {
-		if (ResourceCache::path_cache_lock) {
-			ResourceCache::path_cache_lock->write_lock();
-		}
+		ResourceCache::path_cache_lock.write_lock();
 		ResourceCache::resource_path_cache[p_path].erase(get_path());
-		if (ResourceCache::path_cache_lock) {
-			ResourceCache::path_cache_lock->write_unlock();
-		}
+		ResourceCache::path_cache_lock.write_unlock();
 	} else {
-		if (ResourceCache::path_cache_lock) {
-			ResourceCache::path_cache_lock->write_lock();
-		}
+		ResourceCache::path_cache_lock.write_lock();
 		ResourceCache::resource_path_cache[p_path][get_path()] = p_id;
-		if (ResourceCache::path_cache_lock) {
-			ResourceCache::path_cache_lock->write_unlock();
-		}
+		ResourceCache::path_cache_lock.write_unlock();
 	}
 }
 
 int Resource::get_id_for_path(const String &p_path) const {
-	if (ResourceCache::path_cache_lock) {
-		ResourceCache::path_cache_lock->read_lock();
-	}
+	ResourceCache::path_cache_lock.read_lock();
 	if (ResourceCache::resource_path_cache[p_path].has(get_path())) {
 		int result = ResourceCache::resource_path_cache[p_path][get_path()];
-		if (ResourceCache::path_cache_lock) {
-			ResourceCache::path_cache_lock->read_unlock();
-		}
+		ResourceCache::path_cache_lock.read_unlock();
 		return result;
 	} else {
-		if (ResourceCache::path_cache_lock) {
-			ResourceCache::path_cache_lock->read_unlock();
-		}
+		ResourceCache::path_cache_lock.read_unlock();
 		return -1;
 	}
 }
@@ -444,9 +426,9 @@ Resource::Resource() :
 Resource::~Resource() {
 
 	if (path_cache != "") {
-		ResourceCache::lock->write_lock();
+		ResourceCache::lock.write_lock();
 		ResourceCache::resources.erase(path_cache);
-		ResourceCache::lock->write_unlock();
+		ResourceCache::lock.write_unlock();
 	}
 	if (owners.size()) {
 		WARN_PRINT("Resource is still owned.");
@@ -458,19 +440,11 @@ HashMap<String, Resource *> ResourceCache::resources;
 HashMap<String, HashMap<String, int> > ResourceCache::resource_path_cache;
 #endif
 
-RWLock *ResourceCache::lock = NULL;
+RWLock ResourceCache::lock;
 #ifdef TOOLS_ENABLED
-RWLock *ResourceCache::path_cache_lock = NULL;
+RWLock ResourceCache::path_cache_lock;
 #endif
 
-void ResourceCache::setup() {
-
-	lock = RWLock::create();
-#ifdef TOOLS_ENABLED
-	path_cache_lock = RWLock::create();
-#endif
-}
-
 void ResourceCache::clear() {
 	if (resources.size()) {
 		ERR_PRINT("Resources still in use at exit (run with --verbose for details).");
@@ -484,7 +458,6 @@ void ResourceCache::clear() {
 	}
 
 	resources.clear();
-	memdelete(lock);
 }
 
 void ResourceCache::reload_externals() {
@@ -492,19 +465,19 @@ void ResourceCache::reload_externals() {
 
 bool ResourceCache::has(const String &p_path) {
 
-	lock->read_lock();
+	lock.read_lock();
 	bool b = resources.has(p_path);
-	lock->read_unlock();
+	lock.read_unlock();
 
 	return b;
 }
 Resource *ResourceCache::get(const String &p_path) {
 
-	lock->read_lock();
+	lock.read_lock();
 
 	Resource **res = resources.getptr(p_path);
 
-	lock->read_unlock();
+	lock.read_unlock();
 
 	if (!res) {
 		return NULL;
@@ -515,28 +488,28 @@ Resource *ResourceCache::get(const String &p_path) {
 
 void ResourceCache::get_cached_resources(List<Ref<Resource> > *p_resources) {
 
-	lock->read_lock();
+	lock.read_lock();
 	const String *K = NULL;
 	while ((K = resources.next(K))) {
 
 		Resource *r = resources[*K];
 		p_resources->push_back(Ref<Resource>(r));
 	}
-	lock->read_unlock();
+	lock.read_unlock();
 }
 
 int ResourceCache::get_cached_resource_count() {
 
-	lock->read_lock();
+	lock.read_lock();
 	int rc = resources.size();
-	lock->read_unlock();
+	lock.read_unlock();
 
 	return rc;
 }
 
 void ResourceCache::dump(const char *p_file, bool p_short) {
 #ifdef DEBUG_ENABLED
-	lock->read_lock();
+	lock.read_lock();
 
 	Map<String, int> type_count;
 
@@ -573,6 +546,6 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
 		memdelete(f);
 	}
 
-	lock->read_unlock();
+	lock.read_unlock();
 #endif
 }

+ 2 - 3
core/resource.h

@@ -148,16 +148,15 @@ typedef Ref<Resource> RES;
 class ResourceCache {
 	friend class Resource;
 	friend class ResourceLoader; //need the lock
-	static RWLock *lock;
+	static RWLock lock;
 	static HashMap<String, Resource *> resources;
 #ifdef TOOLS_ENABLED
 	static HashMap<String, HashMap<String, int> > resource_path_cache; // each tscn has a set of resource paths and IDs
-	static RWLock *path_cache_lock;
+	static RWLock path_cache_lock;
 #endif // TOOLS_ENABLED
 	friend void unregister_core_types();
 	static void clear();
 	friend void register_core_types();
-	static void setup();
 
 public:
 	static void reload_externals();

+ 0 - 169
core/safe_refcount.cpp

@@ -1,169 +0,0 @@
-/*************************************************************************/
-/*  safe_refcount.cpp                                                    */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "safe_refcount.h"
-
-#if defined(_MSC_VER)
-
-/* Implementation for MSVC-Windows */
-
-// don't pollute my namespace!
-#include <windows.h>
-
-#define ATOMIC_CONDITIONAL_INCREMENT_BODY(m_pw, m_win_type, m_win_cmpxchg, m_cpp_type) \
-	/* try to increment until it actually works */                                     \
-	/* taken from boost */                                                             \
-	while (true) {                                                                     \
-		m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw));            \
-		if (tmp == 0)                                                                  \
-			return 0; /* if zero, can't add to it anymore */                           \
-		if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp)         \
-			return tmp + 1;                                                            \
-	}
-
-#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \
-	while (true) {                                                                          \
-		m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw));                 \
-		if (tmp >= m_val)                                                                   \
-			return tmp; /* already greater, or equal */                                     \
-		if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp)                \
-			return m_val;                                                                   \
-	}
-
-_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){
-
-	ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t)
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
-
-	return InterlockedDecrement((LONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
-
-	return InterlockedIncrement((LONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
-
-	return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
-
-	return InterlockedAdd((LONG volatile *)pw, val);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){
-
-	ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t)
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){
-
-	ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t)
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
-
-	return InterlockedDecrement64((LONGLONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
-
-	return InterlockedIncrement64((LONGLONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
-
-	return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
-
-	return InterlockedAdd64((LONGLONG volatile *)pw, val);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){
-
-	ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t)
-}
-
-// The actual advertised functions; they'll call the right implementation
-
-uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
-	return _atomic_conditional_increment_impl(pw);
-}
-
-uint32_t atomic_decrement(volatile uint32_t *pw) {
-	return _atomic_decrement_impl(pw);
-}
-
-uint32_t atomic_increment(volatile uint32_t *pw) {
-	return _atomic_increment_impl(pw);
-}
-
-uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
-	return _atomic_sub_impl(pw, val);
-}
-
-uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
-	return _atomic_add_impl(pw, val);
-}
-
-uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
-	return _atomic_exchange_if_greater_impl(pw, val);
-}
-
-uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
-	return _atomic_conditional_increment_impl(pw);
-}
-
-uint64_t atomic_decrement(volatile uint64_t *pw) {
-	return _atomic_decrement_impl(pw);
-}
-
-uint64_t atomic_increment(volatile uint64_t *pw) {
-	return _atomic_increment_impl(pw);
-}
-
-uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
-	return _atomic_sub_impl(pw, val);
-}
-
-uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
-	return _atomic_add_impl(pw, val);
-}
-
-uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
-	return _atomic_exchange_if_greater_impl(pw, val);
-}
-#endif

+ 218 - 107
core/safe_refcount.h

@@ -31,181 +31,292 @@
 #ifndef SAFE_REFCOUNT_H
 #define SAFE_REFCOUNT_H
 
-#include "core/os/mutex.h"
 #include "core/typedefs.h"
-#include "platform_config.h"
 
-// Atomic functions, these are used for multithread safe reference counters!
+#if !defined(NO_THREADS)
 
-#ifdef NO_THREADS
+#include <atomic>
 
-/* Bogus implementation unaware of multiprocessing */
+// Design goals for these classes:
+// - No automatic conversions or arithmetic operators,
+//   to keep explicit the use of atomics everywhere.
+// - Using acquire-release semantics, even to set the first value.
+//   The first value may be set relaxedly in many cases, but adding the distinction
+//   between relaxed and unrelaxed operation to the interface would make it needlessly
+//   flexible. There's negligible waste in having release semantics for the initial
+//   value and, as an important benefit, you can be sure the value is properly synchronized
+//   even with threads that are already running.
 
 template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
+class SafeNumeric {
+	std::atomic<T> value;
 
-	if (*pw == 0)
-		return 0;
+public:
+	_ALWAYS_INLINE_ void set(T p_value) {
+		value.store(p_value, std::memory_order_release);
+	}
 
-	(*pw)++;
+	_ALWAYS_INLINE_ T get() const {
+		return value.load(std::memory_order_acquire);
+	}
 
-	return *pw;
-}
+	_ALWAYS_INLINE_ T increment() {
+		return value.fetch_add(1, std::memory_order_acq_rel) + 1;
+	}
 
-template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postincrement() {
+		return value.fetch_add(1, std::memory_order_acq_rel);
+	}
 
-	(*pw)--;
+	_ALWAYS_INLINE_ T decrement() {
+		return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
+	}
 
-	return *pw;
-}
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postdecrement() {
+		return value.fetch_sub(1, std::memory_order_acq_rel);
+	}
 
-template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
+	_ALWAYS_INLINE_ T add(T p_value) {
+		return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
+	}
 
-	(*pw)++;
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postadd(T p_value) {
+		return value.fetch_add(p_value, std::memory_order_acq_rel);
+	}
+
+	_ALWAYS_INLINE_ T sub(T p_value) {
+		return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
+	}
+
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postsub(T p_value) {
+		return value.fetch_sub(p_value, std::memory_order_acq_rel);
+	}
 
-	return *pw;
-}
+	_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+		while (true) {
+			T tmp = value.load(std::memory_order_acquire);
+			if (tmp >= p_value) {
+				return tmp; // already greater, or equal
+			}
+			if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
+				return p_value;
+			}
+		}
+	}
 
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
+	_ALWAYS_INLINE_ T conditional_increment() {
+		while (true) {
+			T c = value.load(std::memory_order_acquire);
+			if (c == 0) {
+				return 0;
+			}
+			if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
+				return c + 1;
+			}
+		}
+	}
 
-	(*pw) -= val;
+	_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
+		set(p_value);
+	}
+};
 
-	return *pw;
-}
+class SafeFlag {
+	std::atomic_bool flag;
 
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
+public:
+	_ALWAYS_INLINE_ bool is_set() const {
+		return flag.load(std::memory_order_acquire);
+	}
 
-	(*pw) += val;
+	_ALWAYS_INLINE_ void set() {
+		flag.store(true, std::memory_order_release);
+	}
 
-	return *pw;
-}
+	_ALWAYS_INLINE_ void clear() {
+		flag.store(false, std::memory_order_release);
+	}
 
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
+	_ALWAYS_INLINE_ void set_to(bool p_value) {
+		flag.store(p_value, std::memory_order_release);
+	}
 
-	if (val > *pw)
-		*pw = val;
+	_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
+		set_to(p_value);
+	}
+};
 
-	return *pw;
-}
+class SafeRefCount {
+	SafeNumeric<uint32_t> count;
 
-#elif defined(__GNUC__)
+public:
+	_ALWAYS_INLINE_ bool ref() { // true on success
+		return count.conditional_increment() != 0;
+	}
 
-/* Implementation for GCC & Clang */
+	_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+		return count.conditional_increment();
+	}
 
-// GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes.
-// Clang states it supports GCC atomic builtins.
+	_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+		return count.decrement() == 0;
+	}
 
-template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
+	_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+		return count.decrement();
+	}
 
-	while (true) {
-		T tmp = static_cast<T const volatile &>(*pw);
-		if (tmp == 0)
-			return 0; // if zero, can't add to it anymore
-		if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp)
-			return tmp + 1;
+	_ALWAYS_INLINE_ uint32_t get() const {
+		return count.get();
 	}
-}
 
-template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
+	_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
+		count.set(p_value);
+	}
+};
 
-	return __sync_sub_and_fetch(pw, 1);
-}
+#else
 
 template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
+class SafeNumeric {
+protected:
+	T value;
 
-	return __sync_add_and_fetch(pw, 1);
-}
+public:
+	_ALWAYS_INLINE_ void set(T p_value) {
+		value = p_value;
+	}
 
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
+	_ALWAYS_INLINE_ T get() const {
+		return value;
+	}
 
-	return __sync_sub_and_fetch(pw, val);
-}
+	_ALWAYS_INLINE_ T increment() {
+		return ++value;
+	}
 
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
+	_ALWAYS_INLINE_ T postincrement() {
+		return value++;
+	}
 
-	return __sync_add_and_fetch(pw, val);
-}
+	_ALWAYS_INLINE_ T decrement() {
+		return --value;
+	}
 
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
+	_ALWAYS_INLINE_ T postdecrement() {
+		return value--;
+	}
 
-	while (true) {
-		T tmp = static_cast<T const volatile &>(*pw);
-		if (tmp >= val)
-			return tmp; // already greater, or equal
-		if (__sync_val_compare_and_swap(pw, tmp, val) == tmp)
-			return val;
+	_ALWAYS_INLINE_ T add(T p_value) {
+		return value += p_value;
 	}
-}
 
-#elif defined(_MSC_VER)
-// For MSVC use a separate compilation unit to prevent windows.h from polluting
-// the global namespace.
-uint32_t atomic_conditional_increment(volatile uint32_t *pw);
-uint32_t atomic_decrement(volatile uint32_t *pw);
-uint32_t atomic_increment(volatile uint32_t *pw);
-uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val);
-uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val);
-uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val);
+	_ALWAYS_INLINE_ T postadd(T p_value) {
+		T old = value;
+		value += p_value;
+		return old;
+	}
 
-uint64_t atomic_conditional_increment(volatile uint64_t *pw);
-uint64_t atomic_decrement(volatile uint64_t *pw);
-uint64_t atomic_increment(volatile uint64_t *pw);
-uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val);
-uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val);
-uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val);
+	_ALWAYS_INLINE_ T sub(T p_value) {
+		return value -= p_value;
+	}
 
-#else
-//no threads supported?
-#error Must provide atomic functions for this platform or compiler!
-#endif
+	_ALWAYS_INLINE_ T postsub(T p_value) {
+		T old = value;
+		value -= p_value;
+		return old;
+	}
 
-struct SafeRefCount {
+	_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+		if (value < p_value) {
+			value = p_value;
+		}
+		return value;
+	}
 
-	uint32_t count;
+	_ALWAYS_INLINE_ T conditional_increment() {
+		if (value != 0) {
+			return 0;
+		} else {
+			return ++value;
+		}
+	}
 
-public:
-	// destroy() is called when weak_count_ drops to zero.
+	_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
+			value(p_value) {
+	}
+};
 
-	_ALWAYS_INLINE_ bool ref() { // true on success
+class SafeFlag {
+protected:
+	bool flag;
 
-		return atomic_conditional_increment(&count) != 0;
+public:
+	_ALWAYS_INLINE_ bool is_set() const {
+		return flag;
 	}
 
-	_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+	_ALWAYS_INLINE_ void set() {
+		flag = true;
+	}
 
-		return atomic_conditional_increment(&count);
+	_ALWAYS_INLINE_ void clear() {
+		flag = false;
 	}
 
-	_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+	_ALWAYS_INLINE_ void set_to(bool p_value) {
+		flag = p_value;
+	}
 
-		return atomic_decrement(&count) == 0;
+	_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
+			flag(p_value) {}
+};
+
+class SafeRefCount {
+	uint32_t count;
+
+public:
+	_ALWAYS_INLINE_ bool ref() { // true on success
+		if (count != 0) {
+			++count;
+			return true;
+		} else {
+			return false;
+		}
 	}
 
-	_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+	_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+		if (count != 0) {
+			return ++count;
+		} else {
+			return 0;
+		}
+	}
 
-		return atomic_decrement(&count);
+	_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+		return --count == 0;
 	}
 
-	_ALWAYS_INLINE_ uint32_t get() const { // nothrow
+	_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+		return --count;
+	}
 
+	_ALWAYS_INLINE_ uint32_t get() const {
 		return count;
 	}
 
 	_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
-
 		count = p_value;
 	}
+
+	SafeRefCount() :
+			count(0) {}
 };
 
 #endif
+
+#endif // SAFE_REFCOUNT_H

+ 23 - 27
core/string_name.cpp

@@ -47,12 +47,10 @@ StringName _scs_create(const char *p_chr) {
 }
 
 bool StringName::configured = false;
-Mutex *StringName::lock = NULL;
+Mutex StringName::lock;
 
 void StringName::setup() {
 
-	lock = Mutex::create();
-
 	ERR_FAIL_COND(configured);
 	for (int i = 0; i < STRING_TABLE_LEN; i++) {
 
@@ -63,7 +61,7 @@ void StringName::setup() {
 
 void StringName::cleanup() {
 
-	lock->lock();
+	lock.lock();
 
 	int lost_strings = 0;
 	for (int i = 0; i < STRING_TABLE_LEN; i++) {
@@ -87,9 +85,7 @@ void StringName::cleanup() {
 	if (lost_strings) {
 		print_verbose("StringName: " + itos(lost_strings) + " unclaimed string names at exit.");
 	}
-	lock->unlock();
-
-	memdelete(lock);
+	lock.unlock();
 }
 
 void StringName::unref() {
@@ -98,7 +94,7 @@ void StringName::unref() {
 
 	if (_data && _data->refcount.unref()) {
 
-		lock->lock();
+		lock.lock();
 
 		if (_data->prev) {
 			_data->prev->next = _data->next;
@@ -113,7 +109,7 @@ void StringName::unref() {
 			_data->next->prev = _data->prev;
 		}
 		memdelete(_data);
-		lock->unlock();
+		lock.unlock();
 	}
 
 	_data = NULL;
@@ -184,7 +180,7 @@ StringName::StringName(const char *p_name) {
 	if (!p_name || p_name[0] == 0)
 		return; //empty, ignore
 
-	lock->lock();
+	lock.lock();
 
 	uint32_t hash = String::hash(p_name);
 
@@ -203,7 +199,7 @@ StringName::StringName(const char *p_name) {
 	if (_data) {
 		if (_data->refcount.ref()) {
 			// exists
-			lock->unlock();
+			lock.unlock();
 			return;
 		}
 	}
@@ -220,7 +216,7 @@ StringName::StringName(const char *p_name) {
 		_table[idx]->prev = _data;
 	_table[idx] = _data;
 
-	lock->unlock();
+	lock.unlock();
 }
 
 StringName::StringName(const StaticCString &p_static_string) {
@@ -231,7 +227,7 @@ StringName::StringName(const StaticCString &p_static_string) {
 
 	ERR_FAIL_COND(!p_static_string.ptr || !p_static_string.ptr[0]);
 
-	lock->lock();
+	lock.lock();
 
 	uint32_t hash = String::hash(p_static_string.ptr);
 
@@ -250,7 +246,7 @@ StringName::StringName(const StaticCString &p_static_string) {
 	if (_data) {
 		if (_data->refcount.ref()) {
 			// exists
-			lock->unlock();
+			lock.unlock();
 			return;
 		}
 	}
@@ -267,7 +263,7 @@ StringName::StringName(const StaticCString &p_static_string) {
 		_table[idx]->prev = _data;
 	_table[idx] = _data;
 
-	lock->unlock();
+	lock.unlock();
 }
 
 StringName::StringName(const String &p_name) {
@@ -279,7 +275,7 @@ StringName::StringName(const String &p_name) {
 	if (p_name == String())
 		return;
 
-	lock->lock();
+	lock.lock();
 
 	uint32_t hash = p_name.hash();
 
@@ -297,7 +293,7 @@ StringName::StringName(const String &p_name) {
 	if (_data) {
 		if (_data->refcount.ref()) {
 			// exists
-			lock->unlock();
+			lock.unlock();
 			return;
 		}
 	}
@@ -314,7 +310,7 @@ StringName::StringName(const String &p_name) {
 		_table[idx]->prev = _data;
 	_table[idx] = _data;
 
-	lock->unlock();
+	lock.unlock();
 }
 
 StringName StringName::search(const char *p_name) {
@@ -325,7 +321,7 @@ StringName StringName::search(const char *p_name) {
 	if (!p_name[0])
 		return StringName();
 
-	lock->lock();
+	lock.lock();
 
 	uint32_t hash = String::hash(p_name);
 
@@ -342,12 +338,12 @@ StringName StringName::search(const char *p_name) {
 	}
 
 	if (_data && _data->refcount.ref()) {
-		lock->unlock();
+		lock.unlock();
 
 		return StringName(_data);
 	}
 
-	lock->unlock();
+	lock.unlock();
 	return StringName(); //does not exist
 }
 
@@ -359,7 +355,7 @@ StringName StringName::search(const CharType *p_name) {
 	if (!p_name[0])
 		return StringName();
 
-	lock->lock();
+	lock.lock();
 
 	uint32_t hash = String::hash(p_name);
 
@@ -376,18 +372,18 @@ StringName StringName::search(const CharType *p_name) {
 	}
 
 	if (_data && _data->refcount.ref()) {
-		lock->unlock();
+		lock.unlock();
 		return StringName(_data);
 	}
 
-	lock->unlock();
+	lock.unlock();
 	return StringName(); //does not exist
 }
 StringName StringName::search(const String &p_name) {
 
 	ERR_FAIL_COND_V(p_name == "", StringName());
 
-	lock->lock();
+	lock.lock();
 
 	uint32_t hash = p_name.hash();
 
@@ -404,11 +400,11 @@ StringName StringName::search(const String &p_name) {
 	}
 
 	if (_data && _data->refcount.ref()) {
-		lock->unlock();
+		lock.unlock();
 		return StringName(_data);
 	}
 
-	lock->unlock();
+	lock.unlock();
 	return StringName(); //does not exist
 }
 

+ 1 - 1
core/string_name.h

@@ -82,7 +82,7 @@ class StringName {
 	friend void register_core_types();
 	friend void unregister_core_types();
 
-	static Mutex *lock;
+	static Mutex lock;
 	static void setup();
 	static void cleanup();
 	static bool configured;

+ 5 - 22
drivers/alsa/audio_driver_alsa.cpp

@@ -169,8 +169,7 @@ Error AudioDriverALSA::init() {
 
 	Error err = init_device();
 	if (err == OK) {
-		mutex = Mutex::create();
-		thread = Thread::create(AudioDriverALSA::thread_func, this);
+		thread.start(AudioDriverALSA::thread_func, this);
 	}
 
 	return err;
@@ -314,16 +313,12 @@ void AudioDriverALSA::set_device(String device) {
 
 void AudioDriverALSA::lock() {
 
-	if (!thread || !mutex)
-		return;
-	mutex->lock();
+	mutex.lock();
 }
 
 void AudioDriverALSA::unlock() {
 
-	if (!thread || !mutex)
-		return;
-	mutex->unlock();
+	mutex.unlock();
 }
 
 void AudioDriverALSA::finish_device() {
@@ -336,25 +331,13 @@ void AudioDriverALSA::finish_device() {
 
 void AudioDriverALSA::finish() {
 
-	if (thread) {
-		exit_thread = true;
-		Thread::wait_to_finish(thread);
-
-		memdelete(thread);
-		thread = NULL;
-
-		if (mutex) {
-			memdelete(mutex);
-			mutex = NULL;
-		}
-	}
+	exit_thread = true;
+	thread.wait_to_finish();
 
 	finish_device();
 }
 
 AudioDriverALSA::AudioDriverALSA() :
-		thread(NULL),
-		mutex(NULL),
 		pcm_handle(NULL),
 		device_name("Default"),
 		new_device("Default") {

+ 2 - 2
drivers/alsa/audio_driver_alsa.h

@@ -41,8 +41,8 @@
 
 class AudioDriverALSA : public AudioDriver {
 
-	Thread *thread;
-	Mutex *mutex;
+	Thread thread;
+	Mutex mutex;
 
 	snd_pcm_t *pcm_handle;
 

+ 5 - 21
drivers/alsamidi/midi_driver_alsamidi.cpp

@@ -148,27 +148,16 @@ Error MIDIDriverALSAMidi::open() {
 	}
 	snd_device_name_free_hint(hints);
 
-	mutex = Mutex::create();
 	exit_thread = false;
-	thread = Thread::create(MIDIDriverALSAMidi::thread_func, this);
+	thread.start(MIDIDriverALSAMidi::thread_func, this);
 
 	return OK;
 }
 
 void MIDIDriverALSAMidi::close() {
 
-	if (thread) {
-		exit_thread = true;
-		Thread::wait_to_finish(thread);
-
-		memdelete(thread);
-		thread = NULL;
-	}
-
-	if (mutex) {
-		memdelete(mutex);
-		mutex = NULL;
-	}
+	exit_thread = true;
+	thread.wait_to_finish();
 
 	for (int i = 0; i < connected_inputs.size(); i++) {
 		snd_rawmidi_t *midi_in = connected_inputs[i];
@@ -179,14 +168,12 @@ void MIDIDriverALSAMidi::close() {
 
 void MIDIDriverALSAMidi::lock() const {
 
-	if (mutex)
-		mutex->lock();
+	mutex.lock();
 }
 
 void MIDIDriverALSAMidi::unlock() const {
 
-	if (mutex)
-		mutex->unlock();
+	mutex.unlock();
 }
 
 PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
@@ -210,9 +197,6 @@ PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
 
 MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
 
-	mutex = NULL;
-	thread = NULL;
-
 	exit_thread = false;
 }
 

+ 2 - 2
drivers/alsamidi/midi_driver_alsamidi.h

@@ -43,8 +43,8 @@
 
 class MIDIDriverALSAMidi : public MIDIDriver {
 
-	Thread *thread;
-	Mutex *mutex;
+	Thread thread;
+	Mutex mutex;
 
 	Vector<snd_rawmidi_t *> connected_inputs;
 

+ 3 - 15
drivers/coreaudio/audio_driver_coreaudio.cpp

@@ -69,8 +69,6 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID
 #endif
 
 Error AudioDriverCoreAudio::init() {
-	mutex = Mutex::create();
-
 	AudioComponentDescription desc;
 	zeromem(&desc, sizeof(desc));
 	desc.componentType = kAudioUnitType_Output;
@@ -280,19 +278,15 @@ AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
 };
 
 void AudioDriverCoreAudio::lock() {
-	if (mutex)
-		mutex->lock();
+	mutex.lock();
 };
 
 void AudioDriverCoreAudio::unlock() {
-	if (mutex)
-		mutex->unlock();
+	mutex.unlock();
 };
 
 bool AudioDriverCoreAudio::try_lock() {
-	if (mutex)
-		return mutex->try_lock() == OK;
-	return true;
+	return mutex.try_lock() == OK;
 }
 
 void AudioDriverCoreAudio::finish() {
@@ -344,11 +338,6 @@ void AudioDriverCoreAudio::finish() {
 		audio_unit = NULL;
 		unlock();
 	}
-
-	if (mutex) {
-		memdelete(mutex);
-		mutex = NULL;
-	}
 }
 
 Error AudioDriverCoreAudio::capture_init() {
@@ -691,7 +680,6 @@ AudioDriverCoreAudio::AudioDriverCoreAudio() :
 		audio_unit(NULL),
 		input_unit(NULL),
 		active(false),
-		mutex(NULL),
 		device_name("Default"),
 		capture_device_name("Default"),
 		mix_rate(0),

+ 1 - 1
drivers/coreaudio/audio_driver_coreaudio.h

@@ -46,7 +46,7 @@ class AudioDriverCoreAudio : public AudioDriver {
 	AudioComponentInstance input_unit;
 
 	bool active;
-	Mutex *mutex;
+	Mutex mutex;
 
 	String device_name;
 	String capture_device_name;

+ 5 - 20
drivers/pulseaudio/audio_driver_pulseaudio.cpp

@@ -294,8 +294,7 @@ Error AudioDriverPulseAudio::init() {
 
 	Error err = init_device();
 	if (err == OK) {
-		mutex = Mutex::create();
-		thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
+		thread.start(AudioDriverPulseAudio::thread_func, this);
 	}
 
 	return OK;
@@ -600,16 +599,12 @@ void AudioDriverPulseAudio::set_device(String device) {
 
 void AudioDriverPulseAudio::lock() {
 
-	if (!thread || !mutex)
-		return;
-	mutex->lock();
+	mutex.lock();
 }
 
 void AudioDriverPulseAudio::unlock() {
 
-	if (!thread || !mutex)
-		return;
-	mutex->unlock();
+	mutex.unlock();
 }
 
 void AudioDriverPulseAudio::finish_device() {
@@ -623,11 +618,11 @@ void AudioDriverPulseAudio::finish_device() {
 
 void AudioDriverPulseAudio::finish() {
 
-	if (!thread)
+	if (!thread.is_started())
 		return;
 
 	exit_thread = true;
-	Thread::wait_to_finish(thread);
+	thread.wait_to_finish();
 
 	finish_device();
 
@@ -641,14 +636,6 @@ void AudioDriverPulseAudio::finish() {
 		pa_mainloop_free(pa_ml);
 		pa_ml = NULL;
 	}
-
-	memdelete(thread);
-	if (mutex) {
-		memdelete(mutex);
-		mutex = NULL;
-	}
-
-	thread = NULL;
 }
 
 Error AudioDriverPulseAudio::capture_init_device() {
@@ -802,8 +789,6 @@ String AudioDriverPulseAudio::capture_get_device() {
 }
 
 AudioDriverPulseAudio::AudioDriverPulseAudio() :
-		thread(NULL),
-		mutex(NULL),
 		pa_ml(NULL),
 		pa_ctx(NULL),
 		pa_str(NULL),

+ 2 - 2
drivers/pulseaudio/audio_driver_pulseaudio.h

@@ -41,8 +41,8 @@
 
 class AudioDriverPulseAudio : public AudioDriver {
 
-	Thread *thread;
-	Mutex *mutex;
+	Thread thread;
+	Mutex mutex;
 
 	pa_mainloop *pa_ml;
 	pa_context *pa_ctx;

+ 0 - 73
drivers/unix/mutex_posix.cpp

@@ -1,73 +0,0 @@
-/*************************************************************************/
-/*  mutex_posix.cpp                                                      */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "mutex_posix.h"
-
-#include "core/os/memory.h"
-
-#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
-
-void MutexPosix::lock() {
-
-	pthread_mutex_lock(&mutex);
-}
-void MutexPosix::unlock() {
-
-	pthread_mutex_unlock(&mutex);
-}
-Error MutexPosix::try_lock() {
-
-	return (pthread_mutex_trylock(&mutex) == 0) ? OK : ERR_BUSY;
-}
-
-Mutex *MutexPosix::create_func_posix(bool p_recursive) {
-
-	return memnew(MutexPosix(p_recursive));
-}
-
-void MutexPosix::make_default() {
-
-	create_func = create_func_posix;
-}
-
-MutexPosix::MutexPosix(bool p_recursive) {
-
-	pthread_mutexattr_init(&attr);
-	if (p_recursive)
-		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-	pthread_mutex_init(&mutex, &attr);
-}
-
-MutexPosix::~MutexPosix() {
-
-	pthread_mutex_destroy(&mutex);
-}
-
-#endif

+ 0 - 61
drivers/unix/mutex_posix.h

@@ -1,61 +0,0 @@
-/*************************************************************************/
-/*  mutex_posix.h                                                        */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef MUTEX_POSIX_H
-#define MUTEX_POSIX_H
-
-#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
-
-#include "core/os/mutex.h"
-
-#include <pthread.h>
-
-class MutexPosix : public Mutex {
-
-	pthread_mutexattr_t attr;
-	pthread_mutex_t mutex;
-
-	static Mutex *create_func_posix(bool p_recursive);
-
-public:
-	virtual void lock();
-	virtual void unlock();
-	virtual Error try_lock();
-
-	static void make_default();
-
-	MutexPosix(bool p_recursive);
-
-	~MutexPosix();
-};
-
-#endif
-
-#endif

+ 6 - 22
drivers/unix/os_unix.cpp

@@ -32,14 +32,10 @@
 
 #ifdef UNIX_ENABLED
 
-#include "core/os/thread_dummy.h"
 #include "core/project_settings.h"
 #include "drivers/unix/dir_access_unix.h"
 #include "drivers/unix/file_access_unix.h"
-#include "drivers/unix/mutex_posix.h"
 #include "drivers/unix/net_socket_posix.h"
-#include "drivers/unix/rw_lock_posix.h"
-#include "drivers/unix/semaphore_posix.h"
 #include "drivers/unix/thread_posix.h"
 #include "servers/visual_server.h"
 
@@ -64,6 +60,7 @@
 #include <string.h>
 #include <sys/time.h>
 #include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 
 /// Clock Setup function (used by get_ticks_usec)
@@ -120,19 +117,10 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) {
 
 void OS_Unix::initialize_core() {
 
-#ifdef NO_THREADS
-	ThreadDummy::make_default();
-	SemaphoreDummy::make_default();
-	MutexDummy::make_default();
-	RWLockDummy::make_default();
-#else
-	ThreadPosix::make_default();
-#if !defined(OSX_ENABLED) && !defined(IPHONE_ENABLED)
-	SemaphorePosix::make_default();
-#endif
-	MutexPosix::make_default();
-	RWLockPosix::make_default();
+#if !defined(NO_THREADS)
+	init_thread_posix();
 #endif
+
 	FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
 	FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
 	FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
@@ -310,13 +298,9 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo
 
 		while (fgets(buf, 65535, f)) {
 
-			if (p_pipe_mutex) {
-				p_pipe_mutex->lock();
-			}
+			p_pipe_mutex->lock();
 			(*r_pipe) += String::utf8(buf);
-			if (p_pipe_mutex) {
-				p_pipe_mutex->unlock();
-			}
+			p_pipe_mutex->unlock();
 		}
 		int rv = pclose(f);
 		if (r_exitcode)

+ 0 - 102
drivers/unix/rw_lock_posix.cpp

@@ -1,102 +0,0 @@
-/*************************************************************************/
-/*  rw_lock_posix.cpp                                                    */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
-
-#include "rw_lock_posix.h"
-
-#include "core/error_macros.h"
-#include "core/os/memory.h"
-#include <stdio.h>
-
-void RWLockPosix::read_lock() {
-
-	int err = pthread_rwlock_rdlock(&rwlock);
-	if (err != 0) {
-		perror("Acquiring lock failed");
-	}
-	ERR_FAIL_COND(err != 0);
-}
-
-void RWLockPosix::read_unlock() {
-
-	pthread_rwlock_unlock(&rwlock);
-}
-
-Error RWLockPosix::read_try_lock() {
-
-	if (pthread_rwlock_tryrdlock(&rwlock) != 0) {
-		return ERR_BUSY;
-	} else {
-		return OK;
-	}
-}
-
-void RWLockPosix::write_lock() {
-
-	int err = pthread_rwlock_wrlock(&rwlock);
-	ERR_FAIL_COND(err != 0);
-}
-
-void RWLockPosix::write_unlock() {
-
-	pthread_rwlock_unlock(&rwlock);
-}
-
-Error RWLockPosix::write_try_lock() {
-	if (pthread_rwlock_trywrlock(&rwlock) != 0) {
-		return ERR_BUSY;
-	} else {
-		return OK;
-	}
-}
-
-RWLock *RWLockPosix::create_func_posix() {
-
-	return memnew(RWLockPosix);
-}
-
-void RWLockPosix::make_default() {
-
-	create_func = create_func_posix;
-}
-
-RWLockPosix::RWLockPosix() {
-
-	//rwlock=PTHREAD_RWLOCK_INITIALIZER; fails on OSX
-	pthread_rwlock_init(&rwlock, NULL);
-}
-
-RWLockPosix::~RWLockPosix() {
-
-	pthread_rwlock_destroy(&rwlock);
-}
-
-#endif

+ 0 - 63
drivers/unix/rw_lock_posix.h

@@ -1,63 +0,0 @@
-/*************************************************************************/
-/*  rw_lock_posix.h                                                      */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef RWLOCKPOSIX_H
-#define RWLOCKPOSIX_H
-
-#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
-
-#include "core/os/rw_lock.h"
-#include <pthread.h>
-
-class RWLockPosix : public RWLock {
-
-	pthread_rwlock_t rwlock;
-
-	static RWLock *create_func_posix();
-
-public:
-	virtual void read_lock();
-	virtual void read_unlock();
-	virtual Error read_try_lock();
-
-	virtual void write_lock();
-	virtual void write_unlock();
-	virtual Error write_try_lock();
-
-	static void make_default();
-
-	RWLockPosix();
-
-	~RWLockPosix();
-};
-
-#endif
-
-#endif // RWLOCKPOSIX_H

+ 0 - 87
drivers/unix/semaphore_posix.cpp

@@ -1,87 +0,0 @@
-/*************************************************************************/
-/*  semaphore_posix.cpp                                                  */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "semaphore_posix.h"
-
-#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(OSX_ENABLED) && !defined(IPHONE_ENABLED)
-
-#include "core/os/memory.h"
-#include <errno.h>
-#include <stdio.h>
-
-Error SemaphorePosix::wait() {
-
-	while (sem_wait(&sem)) {
-		if (errno == EINTR) {
-			errno = 0;
-			continue;
-		} else {
-			perror("sem waiting");
-			return ERR_BUSY;
-		}
-	}
-	return OK;
-}
-
-Error SemaphorePosix::post() {
-
-	return (sem_post(&sem) == 0) ? OK : ERR_BUSY;
-}
-int SemaphorePosix::get() const {
-
-	int val;
-	sem_getvalue(&sem, &val);
-
-	return val;
-}
-
-Semaphore *SemaphorePosix::create_semaphore_posix() {
-
-	return memnew(SemaphorePosix);
-}
-
-void SemaphorePosix::make_default() {
-
-	create_func = create_semaphore_posix;
-}
-
-SemaphorePosix::SemaphorePosix() {
-
-	int r = sem_init(&sem, 0, 0);
-	if (r != 0)
-		perror("sem creating");
-}
-
-SemaphorePosix::~SemaphorePosix() {
-
-	sem_destroy(&sem);
-}
-
-#endif

+ 0 - 58
drivers/unix/semaphore_posix.h

@@ -1,58 +0,0 @@
-/*************************************************************************/
-/*  semaphore_posix.h                                                    */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef SEMAPHORE_POSIX_H
-#define SEMAPHORE_POSIX_H
-
-#include "core/os/semaphore.h"
-
-#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(OSX_ENABLED) && !defined(IPHONE_ENABLED)
-
-#include <semaphore.h>
-
-class SemaphorePosix : public Semaphore {
-
-	mutable sem_t sem;
-
-	static Semaphore *create_semaphore_posix();
-
-public:
-	virtual Error wait();
-	virtual Error post();
-	virtual int get() const;
-
-	static void make_default();
-	SemaphorePosix();
-
-	~SemaphorePosix();
-};
-
-#endif
-#endif

+ 6 - 96
drivers/unix/thread_posix.cpp

@@ -28,92 +28,14 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#include "thread_posix.h"
-
 #if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS)
 
-#include "core/os/memory.h"
-#include "core/safe_refcount.h"
-#include "core/script_language.h"
-
-#ifdef PTHREAD_BSD_SET_NAME
-#include <pthread_np.h>
-#endif
-
-static void _thread_id_key_destr_callback(void *p_value) {
-	memdelete(static_cast<Thread::ID *>(p_value));
-}
-
-static pthread_key_t _create_thread_id_key() {
-	pthread_key_t key;
-	pthread_key_create(&key, &_thread_id_key_destr_callback);
-	return key;
-}
-
-pthread_key_t ThreadPosix::thread_id_key = _create_thread_id_key();
-Thread::ID ThreadPosix::next_thread_id = 0;
-
-Thread::ID ThreadPosix::get_id() const {
-
-	return id;
-}
-
-Thread *ThreadPosix::create_thread_posix() {
-
-	return memnew(ThreadPosix);
-}
-
-void *ThreadPosix::thread_callback(void *userdata) {
-
-	ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata);
-	t->id = atomic_increment(&next_thread_id);
-	pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id)));
-
-	ScriptServer::thread_enter(); //scripts may need to attach a stack
-
-	t->callback(t->user);
-
-	ScriptServer::thread_exit();
-
-	return NULL;
-}
-
-Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
-
-	ThreadPosix *tr = memnew(ThreadPosix);
-	tr->callback = p_callback;
-	tr->user = p_user;
-	pthread_attr_init(&tr->pthread_attr);
-	pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE);
-	pthread_attr_setstacksize(&tr->pthread_attr, 256 * 1024);
-
-	pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr);
-
-	return tr;
-}
-Thread::ID ThreadPosix::get_thread_id_func_posix() {
-
-	void *value = pthread_getspecific(thread_id_key);
-
-	if (value)
-		return *static_cast<ID *>(value);
-
-	ID new_id = atomic_increment(&next_thread_id);
-	pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id)));
-	return new_id;
-}
-void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) {
-
-	ThreadPosix *tp = static_cast<ThreadPosix *>(p_thread);
-	ERR_FAIL_COND(!tp);
-	ERR_FAIL_COND(tp->pthread == 0);
-
-	pthread_join(tp->pthread, NULL);
-	tp->pthread = 0;
-}
+#include "thread_posix.h"
 
-Error ThreadPosix::set_name_func_posix(const String &p_name) {
+#include "core/os/thread.h"
+#include "core/ustring.h"
 
+static Error set_name(const String &p_name) {
 #ifdef PTHREAD_NO_RENAME
 	return ERR_UNAVAILABLE;
 
@@ -141,22 +63,10 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) {
 	return err == 0 ? OK : ERR_INVALID_PARAMETER;
 
 #endif // PTHREAD_NO_RENAME
-};
-
-void ThreadPosix::make_default() {
-
-	create_func = create_func_posix;
-	get_thread_id_func = get_thread_id_func_posix;
-	wait_to_finish_func = wait_to_finish_func_posix;
-	set_name_func = set_name_func_posix;
-}
-
-ThreadPosix::ThreadPosix() {
-
-	pthread = 0;
 }
 
-ThreadPosix::~ThreadPosix() {
+void init_thread_posix() {
+	Thread::_set_platform_funcs(&set_name, nullptr);
 }
 
 #endif

+ 2 - 37
drivers/unix/thread_posix.h

@@ -31,43 +31,8 @@
 #ifndef THREAD_POSIX_H
 #define THREAD_POSIX_H
 
-#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS)
-
-#include "core/os/thread.h"
-#include <pthread.h>
-#include <sys/types.h>
-
-class ThreadPosix : public Thread {
-
-	static pthread_key_t thread_id_key;
-	static ID next_thread_id;
-
-	pthread_t pthread;
-	pthread_attr_t pthread_attr;
-	ThreadCreateCallback callback;
-	void *user;
-	ID id;
-
-	static Thread *create_thread_posix();
-
-	static void *thread_callback(void *userdata);
-
-	static Thread *create_func_posix(ThreadCreateCallback p_callback, void *, const Settings &);
-	static ID get_thread_id_func_posix();
-	static void wait_to_finish_func_posix(Thread *p_thread);
-
-	static Error set_name_func_posix(const String &p_name);
-
-	ThreadPosix();
-
-public:
-	virtual ID get_id() const;
-
-	static void make_default();
-
-	~ThreadPosix();
-};
-
+#if !defined(NO_THREADS)
+void init_thread_posix();
 #endif
 
 #endif

+ 5 - 21
drivers/wasapi/audio_driver_wasapi.cpp

@@ -406,8 +406,7 @@ Error AudioDriverWASAPI::init() {
 	exit_thread = false;
 	thread_exited = false;
 
-	mutex = Mutex::create(true);
-	thread = Thread::create(thread_func, this);
+	thread.start(thread_func, this);
 
 	return OK;
 }
@@ -782,33 +781,21 @@ void AudioDriverWASAPI::start() {
 
 void AudioDriverWASAPI::lock() {
 
-	if (mutex)
-		mutex->lock();
+	mutex.lock();
 }
 
 void AudioDriverWASAPI::unlock() {
 
-	if (mutex)
-		mutex->unlock();
+	mutex.unlock();
 }
 
 void AudioDriverWASAPI::finish() {
 
-	if (thread) {
-		exit_thread = true;
-		Thread::wait_to_finish(thread);
-
-		memdelete(thread);
-		thread = NULL;
-	}
+	exit_thread = true;
+	thread.wait_to_finish();
 
 	finish_capture_device();
 	finish_render_device();
-
-	if (mutex) {
-		memdelete(mutex);
-		mutex = NULL;
-	}
 }
 
 Error AudioDriverWASAPI::capture_start() {
@@ -863,9 +850,6 @@ String AudioDriverWASAPI::capture_get_device() {
 
 AudioDriverWASAPI::AudioDriverWASAPI() {
 
-	mutex = NULL;
-	thread = NULL;
-
 	samples_in.clear();
 
 	channels = 0;

+ 2 - 2
drivers/wasapi/audio_driver_wasapi.h

@@ -75,8 +75,8 @@ class AudioDriverWASAPI : public AudioDriver {
 	AudioDeviceWASAPI audio_input;
 	AudioDeviceWASAPI audio_output;
 
-	Mutex *mutex;
-	Thread *thread;
+	Mutex mutex;
+	Thread thread;
 
 	Vector<int32_t> samples_in;
 

+ 0 - 101
drivers/windows/mutex_windows.cpp

@@ -1,101 +0,0 @@
-/*************************************************************************/
-/*  mutex_windows.cpp                                                    */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "mutex_windows.h"
-
-#include "core/os/memory.h"
-
-#ifdef WINDOWS_ENABLED
-
-void MutexWindows::lock() {
-
-#ifdef WINDOWS_USE_MUTEX
-	WaitForSingleObject(mutex, INFINITE);
-#else
-	EnterCriticalSection(&mutex);
-#endif
-}
-
-void MutexWindows::unlock() {
-
-#ifdef WINDOWS_USE_MUTEX
-	ReleaseMutex(mutex);
-#else
-	LeaveCriticalSection(&mutex);
-#endif
-}
-
-Error MutexWindows::try_lock() {
-
-#ifdef WINDOWS_USE_MUTEX
-	return (WaitForSingleObject(mutex, 0) == WAIT_TIMEOUT) ? ERR_BUSY : OK;
-#else
-
-	if (TryEnterCriticalSection(&mutex))
-		return OK;
-	else
-		return ERR_BUSY;
-#endif
-}
-
-Mutex *MutexWindows::create_func_windows(bool p_recursive) {
-
-	return memnew(MutexWindows);
-}
-
-void MutexWindows::make_default() {
-
-	create_func = create_func_windows;
-}
-
-MutexWindows::MutexWindows() {
-
-#ifdef WINDOWS_USE_MUTEX
-	mutex = CreateMutex(NULL, FALSE, NULL);
-#else
-#ifdef UWP_ENABLED
-	InitializeCriticalSectionEx(&mutex, 0, 0);
-#else
-	InitializeCriticalSection(&mutex);
-#endif
-#endif
-}
-
-MutexWindows::~MutexWindows() {
-
-#ifdef WINDOWS_USE_MUTEX
-	CloseHandle(mutex);
-#else
-
-	DeleteCriticalSection(&mutex);
-#endif
-}
-
-#endif

+ 0 - 63
drivers/windows/mutex_windows.h

@@ -1,63 +0,0 @@
-/*************************************************************************/
-/*  mutex_windows.h                                                      */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef MUTEX_WINDOWS_H
-#define MUTEX_WINDOWS_H
-
-#ifdef WINDOWS_ENABLED
-
-#include "core/os/mutex.h"
-
-#include <windows.h>
-
-class MutexWindows : public Mutex {
-
-#ifdef WINDOWS_USE_MUTEX
-	HANDLE mutex;
-#else
-	CRITICAL_SECTION mutex;
-#endif
-
-	static Mutex *create_func_windows(bool p_recursive);
-
-public:
-	virtual void lock();
-	virtual void unlock();
-	virtual Error try_lock();
-
-	static void make_default();
-
-	MutexWindows();
-	~MutexWindows();
-};
-
-#endif
-
-#endif

+ 0 - 95
drivers/windows/rw_lock_windows.cpp

@@ -1,95 +0,0 @@
-/*************************************************************************/
-/*  rw_lock_windows.cpp                                                  */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#if defined(WINDOWS_ENABLED)
-
-#include "rw_lock_windows.h"
-
-#include "core/error_macros.h"
-#include "core/os/memory.h"
-
-#include <stdio.h>
-
-void RWLockWindows::read_lock() {
-
-	AcquireSRWLockShared(&lock);
-}
-
-void RWLockWindows::read_unlock() {
-
-	ReleaseSRWLockShared(&lock);
-}
-
-Error RWLockWindows::read_try_lock() {
-
-	if (TryAcquireSRWLockShared(&lock) == 0) {
-		return ERR_BUSY;
-	} else {
-		return OK;
-	}
-}
-
-void RWLockWindows::write_lock() {
-
-	AcquireSRWLockExclusive(&lock);
-}
-
-void RWLockWindows::write_unlock() {
-
-	ReleaseSRWLockExclusive(&lock);
-}
-
-Error RWLockWindows::write_try_lock() {
-	if (TryAcquireSRWLockExclusive(&lock) == 0) {
-		return ERR_BUSY;
-	} else {
-		return OK;
-	}
-}
-
-RWLock *RWLockWindows::create_func_windows() {
-
-	return memnew(RWLockWindows);
-}
-
-void RWLockWindows::make_default() {
-
-	create_func = create_func_windows;
-}
-
-RWLockWindows::RWLockWindows() {
-
-	InitializeSRWLock(&lock);
-}
-
-RWLockWindows::~RWLockWindows() {
-}
-
-#endif

+ 0 - 64
drivers/windows/rw_lock_windows.h

@@ -1,64 +0,0 @@
-/*************************************************************************/
-/*  rw_lock_windows.h                                                    */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef RWLOCKWINDOWS_H
-#define RWLOCKWINDOWS_H
-
-#if defined(WINDOWS_ENABLED)
-
-#include "core/os/rw_lock.h"
-
-#include <windows.h>
-
-class RWLockWindows : public RWLock {
-
-	SRWLOCK lock;
-
-	static RWLock *create_func_windows();
-
-public:
-	virtual void read_lock();
-	virtual void read_unlock();
-	virtual Error read_try_lock();
-
-	virtual void write_lock();
-	virtual void write_unlock();
-	virtual Error write_try_lock();
-
-	static void make_default();
-
-	RWLockWindows();
-
-	~RWLockWindows();
-};
-
-#endif
-
-#endif // RWLOCKWINDOWS_H

+ 0 - 98
drivers/windows/semaphore_windows.cpp

@@ -1,98 +0,0 @@
-/*************************************************************************/
-/*  semaphore_windows.cpp                                                */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "semaphore_windows.h"
-
-#if defined(WINDOWS_ENABLED)
-
-#include "core/os/memory.h"
-
-Error SemaphoreWindows::wait() {
-
-	WaitForSingleObjectEx(semaphore, INFINITE, false);
-	return OK;
-}
-Error SemaphoreWindows::post() {
-
-	ReleaseSemaphore(semaphore, 1, NULL);
-	return OK;
-}
-int SemaphoreWindows::get() const {
-	long previous;
-	switch (WaitForSingleObjectEx(semaphore, 0, false)) {
-		case WAIT_OBJECT_0: {
-			ERR_FAIL_COND_V(!ReleaseSemaphore(semaphore, 1, &previous), -1);
-			return previous + 1;
-		} break;
-		case WAIT_TIMEOUT: {
-			return 0;
-		} break;
-		default: {
-		}
-	}
-
-	ERR_FAIL_V(-1);
-}
-
-Semaphore *SemaphoreWindows::create_semaphore_windows() {
-
-	return memnew(SemaphoreWindows);
-}
-
-void SemaphoreWindows::make_default() {
-
-	create_func = create_semaphore_windows;
-}
-
-SemaphoreWindows::SemaphoreWindows() {
-
-#ifdef UWP_ENABLED
-	semaphore = CreateSemaphoreEx(
-			NULL,
-			0,
-			0xFFFFFFF, //wathever
-			NULL,
-			0,
-			SEMAPHORE_ALL_ACCESS);
-#else
-	semaphore = CreateSemaphore(
-			NULL,
-			0,
-			0xFFFFFFF, //wathever
-			NULL);
-#endif
-}
-
-SemaphoreWindows::~SemaphoreWindows() {
-
-	CloseHandle(semaphore);
-}
-
-#endif

+ 0 - 58
drivers/windows/semaphore_windows.h

@@ -1,58 +0,0 @@
-/*************************************************************************/
-/*  semaphore_windows.h                                                  */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef SEMAPHORE_WINDOWS_H
-#define SEMAPHORE_WINDOWS_H
-
-#include "core/os/semaphore.h"
-
-#ifdef WINDOWS_ENABLED
-
-#include <windows.h>
-
-class SemaphoreWindows : public Semaphore {
-
-	mutable HANDLE semaphore;
-
-	static Semaphore *create_semaphore_windows();
-
-public:
-	virtual Error wait();
-	virtual Error post();
-	virtual int get() const;
-
-	static void make_default();
-	SemaphoreWindows();
-
-	~SemaphoreWindows();
-};
-
-#endif
-#endif

+ 0 - 100
drivers/windows/thread_windows.cpp

@@ -1,100 +0,0 @@
-/*************************************************************************/
-/*  thread_windows.cpp                                                   */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "thread_windows.h"
-
-#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED)
-
-#include "core/os/memory.h"
-
-Thread::ID ThreadWindows::get_id() const {
-
-	return id;
-}
-
-Thread *ThreadWindows::create_thread_windows() {
-
-	return memnew(ThreadWindows);
-}
-
-DWORD ThreadWindows::thread_callback(LPVOID userdata) {
-
-	ThreadWindows *t = reinterpret_cast<ThreadWindows *>(userdata);
-
-	ScriptServer::thread_enter(); //scripts may need to attach a stack
-
-	t->id = (ID)GetCurrentThreadId(); // must implement
-	t->callback(t->user);
-	SetEvent(t->handle);
-
-	ScriptServer::thread_exit();
-
-	return 0;
-}
-
-Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
-
-	ThreadWindows *tr = memnew(ThreadWindows);
-	tr->callback = p_callback;
-	tr->user = p_user;
-	tr->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-	QueueUserWorkItem(thread_callback, tr, WT_EXECUTELONGFUNCTION);
-
-	return tr;
-}
-Thread::ID ThreadWindows::get_thread_id_func_windows() {
-
-	return (ID)GetCurrentThreadId(); //must implement
-}
-void ThreadWindows::wait_to_finish_func_windows(Thread *p_thread) {
-
-	ThreadWindows *tp = static_cast<ThreadWindows *>(p_thread);
-	ERR_FAIL_COND(!tp);
-	WaitForSingleObject(tp->handle, INFINITE);
-	CloseHandle(tp->handle);
-	//`memdelete(tp);
-}
-
-void ThreadWindows::make_default() {
-
-	create_func = create_func_windows;
-	get_thread_id_func = get_thread_id_func_windows;
-	wait_to_finish_func = wait_to_finish_func_windows;
-}
-
-ThreadWindows::ThreadWindows() :
-		handle(NULL) {
-}
-
-ThreadWindows::~ThreadWindows() {
-}
-
-#endif

+ 0 - 68
drivers/windows/thread_windows.h

@@ -1,68 +0,0 @@
-/*************************************************************************/
-/*  thread_windows.h                                                     */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#ifndef THREAD_WINDOWS_H
-#define THREAD_WINDOWS_H
-
-#ifdef WINDOWS_ENABLED
-
-#include "core/os/thread.h"
-#include "core/script_language.h"
-
-#include <windows.h>
-
-class ThreadWindows : public Thread {
-
-	ThreadCreateCallback callback;
-	void *user;
-	ID id;
-	HANDLE handle;
-
-	static Thread *create_thread_windows();
-
-	static DWORD WINAPI thread_callback(LPVOID userdata);
-
-	static Thread *create_func_windows(ThreadCreateCallback p_callback, void *, const Settings &);
-	static ID get_thread_id_func_windows();
-	static void wait_to_finish_func_windows(Thread *p_thread);
-
-	ThreadWindows();
-
-public:
-	virtual ID get_id() const;
-
-	static void make_default();
-
-	~ThreadWindows();
-};
-
-#endif
-
-#endif

+ 5 - 17
drivers/xaudio2/audio_driver_xaudio2.cpp

@@ -79,8 +79,7 @@ Error AudioDriverXAudio2::init() {
 	hr = xaudio->CreateSourceVoice(&source_voice, &wave_format, 0, XAUDIO2_MAX_FREQ_RATIO, &voice_callback);
 	ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 source voice. Error code: " + itos(hr) + ".");
 
-	mutex = Mutex::create();
-	thread = Thread::create(AudioDriverXAudio2::thread_func, this);
+	thread.start(AudioDriverXAudio2::thread_func, this);
 
 	return OK;
 }
@@ -158,24 +157,20 @@ float AudioDriverXAudio2::get_latency() {
 
 void AudioDriverXAudio2::lock() {
 
-	if (!thread || !mutex)
-		return;
-	mutex->lock();
+	mutex.lock();
 }
 void AudioDriverXAudio2::unlock() {
 
-	if (!thread || !mutex)
-		return;
-	mutex->unlock();
+	mutex.unlock();
 }
 
 void AudioDriverXAudio2::finish() {
 
-	if (!thread)
+	if (!thread.is_started())
 		return;
 
 	exit_thread = true;
-	Thread::wait_to_finish(thread);
+	thread.wait_to_finish();
 
 	if (source_voice) {
 		source_voice->Stop(0);
@@ -192,16 +187,9 @@ void AudioDriverXAudio2::finish() {
 	}
 
 	mastering_voice->DestroyVoice();
-
-	memdelete(thread);
-	if (mutex)
-		memdelete(mutex);
-	thread = NULL;
 }
 
 AudioDriverXAudio2::AudioDriverXAudio2() :
-		thread(NULL),
-		mutex(NULL),
 		current_buffer(0) {
 	wave_format = { 0 };
 	for (int i = 0; i < AUDIO_BUFFERS; i++) {

+ 2 - 2
drivers/xaudio2/audio_driver_xaudio2.h

@@ -64,8 +64,8 @@ class AudioDriverXAudio2 : public AudioDriver {
 		void STDMETHODCALLTYPE OnVoiceError(void *pBufferContext, HRESULT Error) {}
 	};
 
-	Thread *thread;
-	Mutex *mutex;
+	Thread thread;
+	Mutex mutex;
 
 	int32_t *samples_in;
 	int16_t *samples_out[AUDIO_BUFFERS];

+ 9 - 6
editor/audio_stream_preview.cpp

@@ -158,7 +158,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) {
 
 	preview->playback->stop();
 
-	preview->generating = false;
+	preview->generating.clear();
 }
 
 Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<AudioStream> &p_stream) {
@@ -175,7 +175,7 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
 	Preview *preview = &previews[p_stream->get_instance_id()];
 	preview->base_stream = p_stream;
 	preview->playback = preview->base_stream->instance_playback();
-	preview->generating = true;
+	preview->generating.set();
 	preview->id = p_stream->get_instance_id();
 
 	float len_s = preview->base_stream->get_length();
@@ -199,8 +199,10 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
 	preview->preview->preview = maxmin;
 	preview->preview->length = len_s;
 
-	if (preview->playback.is_valid())
-		preview->thread = Thread::create(_preview_thread, preview);
+	if (preview->playback.is_valid()) {
+		preview->thread = memnew(Thread);
+		preview->thread->start(_preview_thread, preview);
+	}
 
 	return preview->preview;
 }
@@ -218,9 +220,10 @@ void AudioStreamPreviewGenerator::_notification(int p_what) {
 	if (p_what == NOTIFICATION_PROCESS) {
 		List<ObjectID> to_erase;
 		for (Map<ObjectID, Preview>::Element *E = previews.front(); E; E = E->next()) {
-			if (!E->get().generating) {
+			if (!E->get().generating.is_set()) {
 				if (E->get().thread) {
-					Thread::wait_to_finish(E->get().thread);
+					E->get().thread->wait_to_finish();
+					memdelete(E->get().thread);
 					E->get().thread = NULL;
 				}
 				if (!ObjectDB::get_instance(E->key())) { //no longer in use, get rid of preview

+ 13 - 1
editor/audio_stream_preview.h

@@ -32,6 +32,7 @@
 #define AUDIO_STREAM_PREVIEW_H
 
 #include "core/os/thread.h"
+#include "core/safe_refcount.h"
 #include "scene/main/node.h"
 #include "servers/audio/audio_stream.h"
 
@@ -60,9 +61,20 @@ class AudioStreamPreviewGenerator : public Node {
 		Ref<AudioStreamPreview> preview;
 		Ref<AudioStream> base_stream;
 		Ref<AudioStreamPlayback> playback;
-		volatile bool generating;
+		SafeFlag generating;
 		ObjectID id;
 		Thread *thread;
+
+		// Needed for the bookkeeping of the Map
+		Preview &operator=(const Preview &p_rhs) {
+			preview = p_rhs.preview;
+			base_stream = p_rhs.base_stream;
+			playback = p_rhs.playback;
+			generating.set_to(generating.is_set());
+			id = p_rhs.id;
+			thread = p_rhs.thread;
+			return *this;
+		}
 	};
 
 	Map<ObjectID, Preview> previews;

+ 16 - 25
editor/editor_file_system.cpp

@@ -609,7 +609,7 @@ void EditorFileSystem::scan() {
 	if (false /*&& bool(Globals::get_singleton()->get("debug/disable_scan"))*/)
 		return;
 
-	if (scanning || scanning_changes || thread)
+	if (scanning || scanning_changes || thread.is_started())
 		return;
 
 	_update_extensions();
@@ -632,13 +632,13 @@ void EditorFileSystem::scan() {
 		first_scan = false;
 	} else {
 
-		ERR_FAIL_COND(thread);
+		ERR_FAIL_COND(thread.is_started());
 		set_process(true);
 		Thread::Settings s;
 		scanning = true;
 		scan_total = 0;
 		s.priority = Thread::PRIORITY_LOW;
-		thread = Thread::create(_thread_func, this, s);
+		thread.start(_thread_func, this, s);
 		//tree->hide();
 		//progress->show();
 	}
@@ -1067,7 +1067,7 @@ void EditorFileSystem::get_changed_sources(List<String> *r_changed) {
 void EditorFileSystem::scan_changes() {
 
 	if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan
-			scanning || scanning_changes || thread) {
+			scanning || scanning_changes || thread.is_started()) {
 		scan_changes_pending = true;
 		set_process(true);
 		return;
@@ -1097,12 +1097,12 @@ void EditorFileSystem::scan_changes() {
 		emit_signal("sources_changed", sources_changed.size() > 0);
 	} else {
 
-		ERR_FAIL_COND(thread_sources);
+		ERR_FAIL_COND(thread_sources.is_started());
 		set_process(true);
 		scan_total = 0;
 		Thread::Settings s;
 		s.priority = Thread::PRIORITY_LOW;
-		thread_sources = Thread::create(_thread_func_sources, this, s);
+		thread_sources.start(_thread_func_sources, this, s);
 	}
 }
 
@@ -1116,17 +1116,14 @@ void EditorFileSystem::_notification(int p_what) {
 
 		} break;
 		case NOTIFICATION_EXIT_TREE: {
-			Thread *active_thread = thread ? thread : thread_sources;
-			if (use_threads && active_thread) {
+			Thread &active_thread = thread.is_started() ? thread : thread_sources;
+			if (use_threads && active_thread.is_started()) {
 				//abort thread if in progress
 				abort_scan = true;
 				while (scanning) {
 					OS::get_singleton()->delay_usec(1000);
 				}
-				Thread::wait_to_finish(active_thread);
-				memdelete(active_thread);
-				thread = NULL;
-				thread_sources = NULL;
+				active_thread.wait_to_finish();
 				WARN_PRINT("Scan thread aborted...");
 				set_process(false);
 			}
@@ -1151,9 +1148,7 @@ void EditorFileSystem::_notification(int p_what) {
 
 						set_process(false);
 
-						Thread::wait_to_finish(thread_sources);
-						memdelete(thread_sources);
-						thread_sources = NULL;
+						thread_sources.wait_to_finish();
 						if (_update_scan_actions())
 							emit_signal("filesystem_changed");
 						emit_signal("sources_changed", sources_changed.size() > 0);
@@ -1168,9 +1163,7 @@ void EditorFileSystem::_notification(int p_what) {
 						memdelete(filesystem);
 					filesystem = new_filesystem;
 					new_filesystem = NULL;
-					Thread::wait_to_finish(thread);
-					memdelete(thread);
-					thread = NULL;
+					thread.wait_to_finish();
 					_update_scan_actions();
 					emit_signal("filesystem_changed");
 					emit_signal("sources_changed", sources_changed.size() > 0);
@@ -1452,10 +1445,10 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
 
 void EditorFileSystem::update_script_classes() {
 
-	if (!update_script_classes_queued)
+	if (!update_script_classes_queued.is_set())
 		return;
 
-	update_script_classes_queued = false;
+	update_script_classes_queued.clear();
 	ScriptServer::global_classes_clear();
 	if (get_filesystem()) {
 		_scan_script_classes(get_filesystem());
@@ -1474,11 +1467,11 @@ void EditorFileSystem::update_script_classes() {
 }
 
 void EditorFileSystem::_queue_update_script_classes() {
-	if (update_script_classes_queued) {
+	if (update_script_classes_queued.is_set()) {
 		return;
 	}
 
-	update_script_classes_queued = true;
+	update_script_classes_queued.set();
 	call_deferred("update_script_classes");
 }
 
@@ -2135,11 +2128,9 @@ EditorFileSystem::EditorFileSystem() {
 	filesystem = memnew(EditorFileSystemDirectory); //like, empty
 	filesystem->parent = NULL;
 
-	thread = NULL;
 	scanning = false;
 	importing = false;
 	use_threads = true;
-	thread_sources = NULL;
 	new_filesystem = NULL;
 
 	abort_scan = false;
@@ -2155,7 +2146,7 @@ EditorFileSystem::EditorFileSystem() {
 	memdelete(da);
 
 	scan_total = 0;
-	update_script_classes_queued = false;
+	update_script_classes_queued.clear();
 	first_scan = true;
 	scan_changes_pending = false;
 	revalidate_import_files = false;

+ 5 - 3
editor/editor_file_system.h

@@ -34,8 +34,10 @@
 #include "core/os/dir_access.h"
 #include "core/os/thread.h"
 #include "core/os/thread_safe.h"
+#include "core/safe_refcount.h"
 #include "core/set.h"
 #include "scene/main/node.h"
+
 class FileAccess;
 
 struct EditorProgressBG;
@@ -136,7 +138,7 @@ class EditorFileSystem : public Node {
 	};
 
 	bool use_threads;
-	Thread *thread;
+	Thread thread;
 	static void _thread_func(void *_userdata);
 
 	EditorFileSystemDirectory *new_filesystem;
@@ -200,7 +202,7 @@ class EditorFileSystem : public Node {
 
 	void _scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess *da, const ScanProgress &p_progress);
 
-	Thread *thread_sources;
+	Thread thread_sources;
 	bool scanning_changes;
 	bool scanning_changes_done;
 
@@ -231,7 +233,7 @@ class EditorFileSystem : public Node {
 	};
 
 	void _scan_script_classes(EditorFileSystemDirectory *p_dir);
-	volatile bool update_script_classes_queued;
+	SafeFlag update_script_classes_queued;
 	void _queue_update_script_classes();
 
 	String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;

+ 7 - 13
editor/editor_node.cpp

@@ -5735,13 +5735,13 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err
 static void _execute_thread(void *p_ud) {
 
 	EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud;
-	Error err = OS::get_singleton()->execute(eta->path, eta->args, true, NULL, &eta->output, &eta->exitcode, true, eta->execute_output_mutex);
+	Error err = OS::get_singleton()->execute(eta->path, eta->args, true, NULL, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
 	print_verbose("Thread exit status: " + itos(eta->exitcode));
 	if (err != OK) {
 		eta->exitcode = err;
 	}
 
-	eta->done = true;
+	eta->done.set();
 }
 
 int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
@@ -5755,31 +5755,25 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
 	ExecuteThreadArgs eta;
 	eta.path = p_path;
 	eta.args = p_arguments;
-	eta.execute_output_mutex = Mutex::create();
 	eta.exitcode = 255;
-	eta.done = false;
 
 	int prev_len = 0;
 
-	eta.execute_output_thread = Thread::create(_execute_thread, &eta);
+	eta.execute_output_thread.start(_execute_thread, &eta);
 
-	ERR_FAIL_COND_V(!eta.execute_output_thread, 0);
-
-	while (!eta.done) {
-		eta.execute_output_mutex->lock();
+	while (!eta.done.is_set()) {
+		eta.execute_output_mutex.lock();
 		if (prev_len != eta.output.length()) {
 			String to_add = eta.output.substr(prev_len, eta.output.length());
 			prev_len = eta.output.length();
 			execute_outputs->add_text(to_add);
 			Main::iteration();
 		}
-		eta.execute_output_mutex->unlock();
+		eta.execute_output_mutex.unlock();
 		OS::get_singleton()->delay_usec(1000);
 	}
 
-	Thread::wait_to_finish(eta.execute_output_thread);
-	memdelete(eta.execute_output_thread);
-	memdelete(eta.execute_output_mutex);
+	eta.execute_output_thread.wait_to_finish();
 	execute_outputs->add_text("\nExit Code: " + itos(eta.exitcode));
 
 	if (p_close_on_errors && eta.exitcode != 0) {

+ 4 - 3
editor/editor_node.h

@@ -31,6 +31,7 @@
 #ifndef EDITOR_NODE_H
 #define EDITOR_NODE_H
 
+#include "core/safe_refcount.h"
 #include "editor/editor_data.h"
 #include "editor/editor_folding.h"
 #include "editor/editor_run.h"
@@ -106,10 +107,10 @@ public:
 		String path;
 		List<String> args;
 		String output;
-		Thread *execute_output_thread;
-		Mutex *execute_output_mutex;
+		Thread execute_output_thread;
+		Mutex execute_output_mutex;
 		int exitcode;
-		volatile bool done;
+		SafeFlag done;
 	};
 
 private:

+ 27 - 36
editor/editor_resource_preview.cpp

@@ -109,7 +109,7 @@ void EditorResourcePreview::_thread_func(void *ud) {
 
 void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture> &p_texture, const Ref<Texture> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
 
-	preview_mutex->lock();
+	preview_mutex.lock();
 
 	String path = p_str;
 	uint32_t hash = 0;
@@ -131,7 +131,7 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur
 
 	cache[path] = item;
 
-	preview_mutex->unlock();
+	preview_mutex.unlock();
 
 	MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_small_texture, p_ud);
 }
@@ -217,11 +217,11 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
 
 void EditorResourcePreview::_thread() {
 
-	exited = false;
-	while (!exit) {
+	exited.clear();
+	while (!exit.is_set()) {
 
-		preview_sem->wait();
-		preview_mutex->lock();
+		preview_sem.wait();
+		preview_mutex.lock();
 
 		if (queue.size()) {
 
@@ -237,10 +237,10 @@ void EditorResourcePreview::_thread() {
 
 				_preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
 
-				preview_mutex->unlock();
+				preview_mutex.unlock();
 			} else {
 
-				preview_mutex->unlock();
+				preview_mutex.unlock();
 
 				Ref<ImageTexture> texture;
 				Ref<ImageTexture> small_texture;
@@ -347,10 +347,10 @@ void EditorResourcePreview::_thread() {
 			}
 
 		} else {
-			preview_mutex->unlock();
+			preview_mutex.unlock();
 		}
 	}
-	exited = true;
+	exited.set();
 }
 
 void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
@@ -358,7 +358,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
 	ERR_FAIL_NULL(p_receiver);
 	ERR_FAIL_COND(!p_res.is_valid());
 
-	preview_mutex->lock();
+	preview_mutex.lock();
 
 	String path_id = "ID:" + itos(p_res->get_instance_id());
 
@@ -366,7 +366,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
 
 		cache[path_id].order = order++;
 		p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
-		preview_mutex->unlock();
+		preview_mutex.unlock();
 		return;
 	}
 
@@ -380,18 +380,18 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
 	item.userdata = p_userdata;
 
 	queue.push_back(item);
-	preview_mutex->unlock();
-	preview_sem->post();
+	preview_mutex.unlock();
+	preview_sem.post();
 }
 
 void EditorResourcePreview::queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
 
 	ERR_FAIL_NULL(p_receiver);
-	preview_mutex->lock();
+	preview_mutex.lock();
 	if (cache.has(p_path)) {
 		cache[p_path].order = order++;
 		p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
-		preview_mutex->unlock();
+		preview_mutex.unlock();
 		return;
 	}
 
@@ -402,8 +402,8 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
 	item.userdata = p_userdata;
 
 	queue.push_back(item);
-	preview_mutex->unlock();
-	preview_sem->post();
+	preview_mutex.unlock();
+	preview_sem.post();
 }
 
 void EditorResourcePreview::add_preview_generator(const Ref<EditorResourcePreviewGenerator> &p_generator) {
@@ -436,7 +436,7 @@ void EditorResourcePreview::_bind_methods() {
 
 void EditorResourcePreview::check_for_invalidation(const String &p_path) {
 
-	preview_mutex->lock();
+	preview_mutex.lock();
 
 	bool call_invalidated = false;
 	if (cache.has(p_path)) {
@@ -448,7 +448,7 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
 		}
 	}
 
-	preview_mutex->unlock();
+	preview_mutex.unlock();
 
 	if (call_invalidated) { //do outside mutex
 		call_deferred("emit_signal", "preview_invalidated", p_path);
@@ -456,37 +456,28 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
 }
 
 void EditorResourcePreview::start() {
-	ERR_FAIL_COND_MSG(thread, "Thread already started.");
-	thread = Thread::create(_thread_func, this);
+	ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
+	thread.start(_thread_func, this);
 }
 
 void EditorResourcePreview::stop() {
-	if (thread) {
-		exit = true;
-		preview_sem->post();
-		while (!exited) {
+	if (thread.is_started()) {
+		exit.set();
+		preview_sem.post();
+		while (!exited.is_set()) {
 			OS::get_singleton()->delay_usec(10000);
 			VisualServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
 		}
-		Thread::wait_to_finish(thread);
-		memdelete(thread);
-		thread = NULL;
+		thread.wait_to_finish();
 	}
 }
 
 EditorResourcePreview::EditorResourcePreview() {
-	thread = NULL;
 	singleton = this;
-	preview_mutex = Mutex::create();
-	preview_sem = Semaphore::create();
 	order = 0;
-	exit = false;
-	exited = false;
 }
 
 EditorResourcePreview::~EditorResourcePreview() {
 
 	stop();
-	memdelete(preview_mutex);
-	memdelete(preview_sem);
 }

+ 6 - 5
editor/editor_resource_preview.h

@@ -33,6 +33,7 @@
 
 #include "core/os/semaphore.h"
 #include "core/os/thread.h"
+#include "core/safe_refcount.h"
 #include "scene/main/node.h"
 #include "scene/resources/texture.h"
 
@@ -70,11 +71,11 @@ class EditorResourcePreview : public Node {
 
 	List<QueueItem> queue;
 
-	Mutex *preview_mutex;
-	Semaphore *preview_sem;
-	Thread *thread;
-	volatile bool exit;
-	volatile bool exited;
+	Mutex preview_mutex;
+	Semaphore preview_sem;
+	Thread thread;
+	SafeFlag exit;
+	SafeFlag exited;
 
 	struct Item {
 		Ref<Texture> preview;

+ 11 - 15
editor/fileserver/editor_file_server.cpp

@@ -42,9 +42,9 @@
 void EditorFileServer::_close_client(ClientData *cd) {
 
 	cd->connection->disconnect_from_host();
-	cd->efs->wait_mutex->lock();
-	cd->efs->to_wait.insert(cd->thread);
-	cd->efs->wait_mutex->unlock();
+	cd->efs->wait_mutex.lock();
+	cd->efs->to_wait.insert(&cd->thread);
+	cd->efs->wait_mutex.unlock();
 	while (cd->files.size()) {
 		memdelete(cd->files.front()->get());
 		cd->files.erase(cd->files.front());
@@ -291,20 +291,19 @@ void EditorFileServer::_thread_start(void *s) {
 				cd->connection = self->server->take_connection();
 				cd->efs = self;
 				cd->quit = false;
-				cd->thread = Thread::create(_subthread_start, cd);
+				cd->thread.start(_subthread_start, cd);
 			}
 		}
 
-		self->wait_mutex->lock();
+		self->wait_mutex.lock();
 		while (self->to_wait.size()) {
 			Thread *w = self->to_wait.front()->get();
 			self->to_wait.erase(w);
-			self->wait_mutex->unlock();
-			Thread::wait_to_finish(w);
-			memdelete(w);
-			self->wait_mutex->lock();
+			self->wait_mutex.unlock();
+			w->wait_to_finish();
+			self->wait_mutex.lock();
 		}
-		self->wait_mutex->unlock();
+		self->wait_mutex.unlock();
 
 		OS::get_singleton()->delay_usec(100000);
 	}
@@ -331,11 +330,10 @@ void EditorFileServer::stop() {
 EditorFileServer::EditorFileServer() {
 
 	server.instance();
-	wait_mutex = Mutex::create();
 	quit = false;
 	active = false;
 	cmd = CMD_NONE;
-	thread = Thread::create(_thread_start, this);
+	thread.start(_thread_start, this);
 
 	EDITOR_DEF("filesystem/file_server/port", 6010);
 	EDITOR_DEF("filesystem/file_server/password", "");
@@ -344,7 +342,5 @@ EditorFileServer::EditorFileServer() {
 EditorFileServer::~EditorFileServer() {
 
 	quit = true;
-	Thread::wait_to_finish(thread);
-	memdelete(thread);
-	memdelete(wait_mutex);
+	thread.wait_to_finish();
 }

+ 3 - 3
editor/fileserver/editor_file_server.h

@@ -49,7 +49,7 @@ class EditorFileServer : public Object {
 
 	struct ClientData {
 
-		Thread *thread;
+		Thread thread;
 		Ref<StreamPeerTCP> connection;
 		Map<int, FileAccess *> files;
 		EditorFileServer *efs;
@@ -62,8 +62,8 @@ class EditorFileServer : public Object {
 	static void _close_client(ClientData *cd);
 	static void _subthread_start(void *s);
 
-	Mutex *wait_mutex;
-	Thread *thread;
+	Mutex wait_mutex;
+	Thread thread;
 	static void _thread_start(void *);
 	bool quit;
 	Command cmd;

+ 9 - 15
editor/import/resource_importer_texture.cpp

@@ -38,7 +38,7 @@
 
 void ResourceImporterTexture::_texture_reimport_srgb(const Ref<StreamTexture> &p_tex) {
 
-	singleton->mutex->lock();
+	singleton->mutex.lock();
 	StringName path = p_tex->get_path();
 
 	if (!singleton->make_flags.has(path)) {
@@ -47,12 +47,12 @@ void ResourceImporterTexture::_texture_reimport_srgb(const Ref<StreamTexture> &p
 
 	singleton->make_flags[path] |= MAKE_SRGB_FLAG;
 
-	singleton->mutex->unlock();
+	singleton->mutex.unlock();
 }
 
 void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture> &p_tex) {
 
-	singleton->mutex->lock();
+	singleton->mutex.lock();
 	StringName path = p_tex->get_path();
 
 	if (!singleton->make_flags.has(path)) {
@@ -61,12 +61,12 @@ void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture> &p_t
 
 	singleton->make_flags[path] |= MAKE_3D_FLAG;
 
-	singleton->mutex->unlock();
+	singleton->mutex.unlock();
 }
 
 void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture> &p_tex) {
 
-	singleton->mutex->lock();
+	singleton->mutex.lock();
 	StringName path = p_tex->get_path();
 
 	if (!singleton->make_flags.has(path)) {
@@ -75,7 +75,7 @@ void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture>
 
 	singleton->make_flags[path] |= MAKE_NORMAL_FLAG;
 
-	singleton->mutex->unlock();
+	singleton->mutex.unlock();
 }
 
 void ResourceImporterTexture::update_imports() {
@@ -83,10 +83,10 @@ void ResourceImporterTexture::update_imports() {
 	if (EditorFileSystem::get_singleton()->is_scanning() || EditorFileSystem::get_singleton()->is_importing()) {
 		return; // do nothing for now
 	}
-	mutex->lock();
+	mutex.lock();
 
 	if (make_flags.empty()) {
-		mutex->unlock();
+		mutex.unlock();
 		return;
 	}
 
@@ -128,7 +128,7 @@ void ResourceImporterTexture::update_imports() {
 
 	make_flags.clear();
 
-	mutex->unlock();
+	mutex.unlock();
 
 	if (to_reimport.size()) {
 		EditorFileSystem::get_singleton()->reimport_files(to_reimport);
@@ -611,10 +611,4 @@ ResourceImporterTexture::ResourceImporterTexture() {
 	StreamTexture::request_3d_callback = _texture_reimport_3d;
 	StreamTexture::request_srgb_callback = _texture_reimport_srgb;
 	StreamTexture::request_normal_callback = _texture_reimport_normal;
-	mutex = Mutex::create();
-}
-
-ResourceImporterTexture::~ResourceImporterTexture() {
-
-	memdelete(mutex);
 }

+ 1 - 2
editor/import/resource_importer_texture.h

@@ -46,7 +46,7 @@ protected:
 		MAKE_NORMAL_FLAG = 4
 	};
 
-	Mutex *mutex;
+	Mutex mutex;
 	Map<StringName, int> make_flags;
 
 	static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex);
@@ -94,7 +94,6 @@ public:
 	virtual String get_import_settings_string() const;
 
 	ResourceImporterTexture();
-	~ResourceImporterTexture();
 };
 
 #endif // RESOURCEIMPORTTEXTURE_H

+ 9 - 9
editor/plugins/editor_preview_plugins.cpp

@@ -308,7 +308,7 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
 
 void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) {
 
-	preview_done = true;
+	preview_done.set();
 }
 
 void EditorMaterialPreviewPlugin::_bind_methods() {
@@ -336,10 +336,10 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size
 
 		VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
 
-		preview_done = false;
+		preview_done.clear();
 		VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
 
-		while (!preview_done) {
+		while (!preview_done.is_set()) {
 			OS::get_singleton()->delay_usec(10);
 		}
 
@@ -699,7 +699,7 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
 
 void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) {
 
-	preview_done = true;
+	preview_done.set();
 }
 
 void EditorMeshPreviewPlugin::_bind_methods() {
@@ -737,10 +737,10 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p
 
 	VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
 
-	preview_done = false;
+	preview_done.clear();
 	VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
 
-	while (!preview_done) {
+	while (!preview_done.is_set()) {
 		OS::get_singleton()->delay_usec(10);
 	}
 
@@ -819,7 +819,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
 
 void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) {
 
-	preview_done = true;
+	preview_done.set();
 }
 
 void EditorFontPreviewPlugin::_bind_methods() {
@@ -861,11 +861,11 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c
 
 	font->draw(canvas_item, pos, sampled_text);
 
-	preview_done = false;
+	preview_done.clear();
 	VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
 	VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
 
-	while (!preview_done) {
+	while (!preview_done.is_set()) {
 		OS::get_singleton()->delay_usec(10);
 	}
 

+ 5 - 3
editor/plugins/editor_preview_plugins.h

@@ -33,6 +33,8 @@
 
 #include "editor/editor_resource_preview.h"
 
+#include "core/safe_refcount.h"
+
 void post_process_preview(Ref<Image> p_image);
 
 class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
@@ -92,7 +94,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
 	RID light2;
 	RID light_instance2;
 	RID camera;
-	mutable volatile bool preview_done;
+	mutable SafeFlag preview_done;
 
 	void _preview_done(const Variant &p_udata);
 
@@ -137,7 +139,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
 	RID light2;
 	RID light_instance2;
 	RID camera;
-	mutable volatile bool preview_done;
+	mutable SafeFlag preview_done;
 
 	void _preview_done(const Variant &p_udata);
 
@@ -160,7 +162,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator {
 	RID viewport_texture;
 	RID canvas;
 	RID canvas_item;
-	mutable volatile bool preview_done;
+	mutable SafeFlag preview_done;
 
 	void _preview_done(const Variant &p_udata);
 

+ 3 - 5
main/main.cpp

@@ -352,8 +352,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 
 	engine = memnew(Engine);
 
-	ClassDB::init();
-
 	MAIN_PRINT("Main: Initialize CORE");
 
 	register_core_types();
@@ -361,8 +359,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 
 	MAIN_PRINT("Main: Initialize Globals");
 
-	Thread::_main_thread_id = Thread::get_caller_id();
-
 	globals = memnew(ProjectSettings);
 	input_map = memnew(InputMap);
 
@@ -1277,9 +1273,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 	// Print engine name and version
 	print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
 
+#if !defined(NO_THREADS)
 	if (p_main_tid_override) {
-		Thread::_main_thread_id = p_main_tid_override;
+		Thread::main_thread_id = p_main_tid_override;
 	}
+#endif
 
 	Error err = OS::get_singleton()->initialize(video_mode, video_driver_idx, audio_driver_idx);
 	if (err != OK) {

+ 7 - 5
modules/cvtt/image_compress_cvtt.cpp

@@ -33,6 +33,7 @@
 #include "core/os/os.h"
 #include "core/os/thread.h"
 #include "core/print_string.h"
+#include "core/safe_refcount.h"
 
 #include <ConvectionKernels.h>
 
@@ -56,7 +57,7 @@ struct CVTTCompressionJobQueue {
 	CVTTCompressionJobParams job_params;
 	const CVTTCompressionRowTask *job_tasks;
 	uint32_t num_tasks;
-	uint32_t current_task;
+	SafeNumeric<uint32_t> current_task;
 };
 
 static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) {
@@ -131,7 +132,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const
 static void _digest_job_queue(void *p_job_queue) {
 	CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue);
 
-	for (uint32_t next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) {
+	for (uint32_t next_task = job_queue->current_task.increment(); next_task <= job_queue->num_tasks; next_task = job_queue->current_task.increment()) {
 		_digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]);
 	}
 }
@@ -263,16 +264,17 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS
 		PoolVector<CVTTCompressionRowTask>::Read tasks_rb = tasks.read();
 
 		job_queue.job_tasks = &tasks_rb[0];
-		job_queue.current_task = 0;
+		job_queue.current_task.set(0);
 		job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
 
 		for (int i = 0; i < num_job_threads; i++) {
-			threads_wb[i] = Thread::create(_digest_job_queue, &job_queue);
+			threads_wb[i] = memnew(Thread);
+			threads_wb[i]->start(_digest_job_queue, &job_queue);
 		}
 		_digest_job_queue(&job_queue);
 
 		for (int i = 0; i < num_job_threads; i++) {
-			Thread::wait_to_finish(threads_wb[i]);
+			threads_wb[i]->wait_to_finish();
 			memdelete(threads_wb[i]);
 		}
 	}

+ 1 - 1
modules/gdnative/android/android_gdn.cpp

@@ -48,7 +48,7 @@ extern "C" {
 
 JNIEnv *GDAPI godot_android_get_env() {
 #ifdef __ANDROID__
-	return ThreadAndroid::get_env();
+	return get_jni_env();
 #else
 	return NULL;
 #endif

+ 7 - 34
modules/gdnative/nativescript/nativescript.cpp

@@ -220,15 +220,9 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) {
 	nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
 #endif
 
-#ifndef NO_THREADS
-	owners_lock->lock();
-#endif
-
+	owners_lock.lock();
 	instance_owners.insert(p_this);
-
-#ifndef NO_THREADS
-	owners_lock->unlock();
-#endif
+	owners_lock.unlock();
 
 	return nsi;
 }
@@ -524,17 +518,10 @@ NativeScript::NativeScript() {
 	library = Ref<GDNative>();
 	lib_path = "";
 	class_name = "";
-#ifndef NO_THREADS
-	owners_lock = Mutex::create();
-#endif
 }
 
 NativeScript::~NativeScript() {
 	NSL->unregister_script(this);
-
-#ifndef NO_THREADS
-	memdelete(owners_lock);
-#endif
 }
 
 #define GET_SCRIPT_DESC() script->get_script_desc()
@@ -911,15 +898,9 @@ NativeScriptInstance::~NativeScriptInstance() {
 
 	if (owner) {
 
-#ifndef NO_THREADS
-		script->owners_lock->lock();
-#endif
-
+		script->owners_lock.lock();
 		script->instance_owners.erase(owner);
-
-#ifndef NO_THREADS
-		script->owners_lock->unlock();
-#endif
+		script->owners_lock.unlock();
 	}
 }
 
@@ -1014,10 +995,6 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) {
 
 NativeScriptLanguage::NativeScriptLanguage() {
 	NativeScriptLanguage::singleton = this;
-#ifndef NO_THREADS
-	has_objects_to_register = false;
-	mutex = Mutex::create();
-#endif
 
 #ifdef DEBUG_ENABLED
 	profiling = false;
@@ -1053,10 +1030,6 @@ NativeScriptLanguage::~NativeScriptLanguage() {
 	NSL->library_classes.clear();
 	NSL->library_gdnatives.clear();
 	NSL->library_script_users.clear();
-
-#ifndef NO_THREADS
-	memdelete(mutex);
-#endif
 }
 
 String NativeScriptLanguage::get_name() const {
@@ -1470,7 +1443,7 @@ void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeSc
 	MutexLock lock(mutex);
 	libs_to_init.insert(lib);
 	scripts_to_register.insert(script);
-	has_objects_to_register = true;
+	has_objects_to_register.set();
 }
 #endif
 
@@ -1563,7 +1536,7 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
 
 void NativeScriptLanguage::frame() {
 #ifndef NO_THREADS
-	if (has_objects_to_register) {
+	if (has_objects_to_register.is_set()) {
 		MutexLock lock(mutex);
 		for (Set<Ref<GDNativeLibrary> >::Element *L = libs_to_init.front(); L; L = L->next()) {
 			init_library(L->get());
@@ -1573,7 +1546,7 @@ void NativeScriptLanguage::frame() {
 			register_script(S->get());
 		}
 		scripts_to_register.clear();
-		has_objects_to_register = false;
+		has_objects_to_register.clear();
 	}
 #endif
 

+ 4 - 5
modules/gdnative/nativescript/nativescript.h

@@ -37,6 +37,7 @@
 #include "core/ordered_hash_map.h"
 #include "core/os/thread_safe.h"
 #include "core/resource.h"
+#include "core/safe_refcount.h"
 #include "core/script_language.h"
 #include "core/self_list.h"
 #include "scene/main/node.h"
@@ -121,9 +122,7 @@ class NativeScript : public Script {
 	String script_class_name;
 	String script_class_icon_path;
 
-#ifndef NO_THREADS
-	Mutex *owners_lock;
-#endif
+	Mutex owners_lock;
 	Set<Object *> instance_owners;
 
 protected:
@@ -238,11 +237,11 @@ private:
 	void _unload_stuff(bool p_reload = false);
 
 #ifndef NO_THREADS
-	Mutex *mutex;
+	Mutex mutex;
 
 	Set<Ref<GDNativeLibrary> > libs_to_init;
 	Set<NativeScript *> scripts_to_register;
-	volatile bool has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed
+	SafeFlag has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed
 	void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script);
 #endif
 

+ 2 - 26
modules/gdnative/pluginscript/pluginscript_language.cpp

@@ -400,39 +400,15 @@ void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool
 }
 
 void PluginScriptLanguage::lock() {
-#ifndef NO_THREADS
-	if (_lock) {
-		_lock->lock();
-	}
-#endif
+	_lock.lock();
 }
 
 void PluginScriptLanguage::unlock() {
-#ifndef NO_THREADS
-	if (_lock) {
-		_lock->unlock();
-	}
-#endif
+	_lock.unlock();
 }
 
 PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_desc *desc) :
 		_desc(*desc) {
 	_resource_loader = Ref<ResourceFormatLoaderPluginScript>(memnew(ResourceFormatLoaderPluginScript(this)));
 	_resource_saver = Ref<ResourceFormatSaverPluginScript>(memnew(ResourceFormatSaverPluginScript(this)));
-
-// TODO: totally remove _lock attribute if NO_THREADS is set
-#ifdef NO_THREADS
-	_lock = NULL;
-#else
-	_lock = Mutex::create();
-#endif
-}
-
-PluginScriptLanguage::~PluginScriptLanguage() {
-#ifndef NO_THREADS
-	if (_lock) {
-		memdelete(_lock);
-		_lock = NULL;
-	}
-#endif
 }

+ 2 - 2
modules/gdnative/pluginscript/pluginscript_language.h

@@ -53,7 +53,7 @@ class PluginScriptLanguage : public ScriptLanguage {
 	const godot_pluginscript_language_desc _desc;
 	godot_pluginscript_language_data *_data;
 
-	Mutex *_lock;
+	Mutex _lock;
 	SelfList<PluginScript>::List _script_list;
 
 public:
@@ -126,7 +126,7 @@ public:
 	void unlock();
 
 	PluginScriptLanguage(const godot_pluginscript_language_desc *desc);
-	virtual ~PluginScriptLanguage();
+	virtual ~PluginScriptLanguage() {}
 };
 
 #endif // PLUGINSCRIPT_LANGUAGE_H

+ 30 - 106
modules/gdscript/gdscript.cpp

@@ -101,15 +101,9 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
 
 	/* STEP 2, INITIALIZE AND CONSTRUCT */
 
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->lock();
-#endif
-
+	GDScriptLanguage::singleton->lock.lock();
 	instances.insert(instance->owner);
-
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->unlock();
-#endif
+	GDScriptLanguage::singleton->lock.unlock();
 
 	initializer->call(instance, p_args, p_argcount, r_error);
 
@@ -117,11 +111,11 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
 		instance->script = Ref<GDScript>();
 		instance->owner->set_script_instance(NULL);
 #ifndef NO_THREADS
-		GDScriptLanguage::singleton->lock->lock();
+		GDScriptLanguage::singleton->lock.lock();
 #endif
 		instances.erase(p_owner);
 #ifndef NO_THREADS
-		GDScriptLanguage::singleton->lock->unlock();
+		GDScriptLanguage::singleton->lock.unlock();
 #endif
 
 		ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing
@@ -343,14 +337,9 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this)
 
 bool GDScript::instance_has(const Object *p_this) const {
 
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->lock();
-#endif
+	GDScriptLanguage::singleton->lock.lock();
 	bool hasit = instances.has((Object *)p_this);
-
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->unlock();
-#endif
+	GDScriptLanguage::singleton->lock.unlock();
 
 	return hasit;
 }
@@ -564,14 +553,9 @@ void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
 
 Error GDScript::reload(bool p_keep_state) {
 
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->lock();
-#endif
+	GDScriptLanguage::singleton->lock.lock();
 	bool has_instances = instances.size();
-
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->unlock();
-#endif
+	GDScriptLanguage::singleton->lock.unlock();
 
 	ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
 
@@ -926,14 +910,9 @@ GDScript::GDScript() :
 #endif
 
 #ifdef DEBUG_ENABLED
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->lock();
-	}
+	GDScriptLanguage::get_singleton()->lock.lock();
 	GDScriptLanguage::get_singleton()->script_list.add(&script_list);
-
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->unlock();
-	}
+	GDScriptLanguage::get_singleton()->lock.unlock();
 #endif
 }
 
@@ -970,18 +949,14 @@ void GDScript::_save_orphaned_subclasses() {
 
 GDScript::~GDScript() {
 
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->lock();
-	}
+	GDScriptLanguage::get_singleton()->lock.lock();
 	while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
 		// Order matters since clearing the stack may already cause
 		// the GDSCriptFunctionState to be destroyed and thus removed from the list.
 		pending_func_states.remove(E);
 		E->self()->_clear_stack();
 	}
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->unlock();
-	}
+	GDScriptLanguage::get_singleton()->lock.unlock();
 
 	for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
 		memdelete(E->get());
@@ -990,14 +965,9 @@ GDScript::~GDScript() {
 	_save_orphaned_subclasses();
 
 #ifdef DEBUG_ENABLED
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->lock();
-	}
+	GDScriptLanguage::get_singleton()->lock.lock();
 	GDScriptLanguage::get_singleton()->script_list.remove(&script_list);
-
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->unlock();
-	}
+	GDScriptLanguage::get_singleton()->lock.unlock();
 #endif
 }
 
@@ -1400,9 +1370,7 @@ GDScriptInstance::GDScriptInstance() {
 }
 
 GDScriptInstance::~GDScriptInstance() {
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->lock();
-#endif
+	GDScriptLanguage::singleton->lock.lock();
 
 	while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
 		// Order matters since clearing the stack may already cause
@@ -1415,9 +1383,7 @@ GDScriptInstance::~GDScriptInstance() {
 		script->instances.erase(owner);
 	}
 
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->unlock();
-#endif
+	GDScriptLanguage::singleton->lock.unlock();
 }
 
 /************* SCRIPT LANGUAGE **************/
@@ -1517,9 +1483,7 @@ void GDScriptLanguage::finish() {
 void GDScriptLanguage::profiling_start() {
 
 #ifdef DEBUG_ENABLED
-	if (lock) {
-		lock->lock();
-	}
+	lock.lock();
 
 	SelfList<GDScriptFunction> *elem = function_list.first();
 	while (elem) {
@@ -1536,25 +1500,16 @@ void GDScriptLanguage::profiling_start() {
 	}
 
 	profiling = true;
-	if (lock) {
-		lock->unlock();
-	}
-
+	lock.unlock();
 #endif
 }
 
 void GDScriptLanguage::profiling_stop() {
 
 #ifdef DEBUG_ENABLED
-	if (lock) {
-		lock->lock();
-	}
-
+	lock.lock();
 	profiling = false;
-	if (lock) {
-		lock->unlock();
-	}
-
+	lock.unlock();
 #endif
 }
 
@@ -1562,9 +1517,7 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
 
 	int current = 0;
 #ifdef DEBUG_ENABLED
-	if (lock) {
-		lock->lock();
-	}
+	lock.lock();
 
 	SelfList<GDScriptFunction> *elem = function_list.first();
 	while (elem) {
@@ -1578,10 +1531,7 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
 		current++;
 	}
 
-	if (lock) {
-		lock->unlock();
-	}
-
+	lock.unlock();
 #endif
 
 	return current;
@@ -1592,9 +1542,7 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
 	int current = 0;
 
 #ifdef DEBUG_ENABLED
-	if (lock) {
-		lock->lock();
-	}
+	lock.lock();
 
 	SelfList<GDScriptFunction> *elem = function_list.first();
 	while (elem) {
@@ -1610,10 +1558,7 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
 		elem = elem->next();
 	}
 
-	if (lock) {
-		lock->unlock();
-	}
-
+	lock.unlock();
 #endif
 
 	return current;
@@ -1644,9 +1589,7 @@ void GDScriptLanguage::reload_all_scripts() {
 
 #ifdef DEBUG_ENABLED
 	print_verbose("GDScript: Reloading all scripts");
-	if (lock) {
-		lock->lock();
-	}
+	lock.lock();
 
 	List<Ref<GDScript> > scripts;
 
@@ -1659,9 +1602,7 @@ void GDScriptLanguage::reload_all_scripts() {
 		elem = elem->next();
 	}
 
-	if (lock) {
-		lock->unlock();
-	}
+	lock.unlock();
 
 	//as scripts are going to be reloaded, must proceed without locking here
 
@@ -1680,9 +1621,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
 
 #ifdef DEBUG_ENABLED
 
-	if (lock) {
-		lock->lock();
-	}
+	lock.lock();
 
 	List<Ref<GDScript> > scripts;
 
@@ -1695,9 +1634,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
 		elem = elem->next();
 	}
 
-	if (lock) {
-		lock->unlock();
-	}
+	lock.unlock();
 
 	//when someone asks you why dynamically typed languages are easier to write....
 
@@ -1816,9 +1753,7 @@ void GDScriptLanguage::frame() {
 
 #ifdef DEBUG_ENABLED
 	if (profiling) {
-		if (lock) {
-			lock->lock();
-		}
+		lock.lock();
 
 		SelfList<GDScriptFunction> *elem = function_list.first();
 		while (elem) {
@@ -1831,9 +1766,7 @@ void GDScriptLanguage::frame() {
 			elem = elem->next();
 		}
 
-		if (lock) {
-			lock->unlock();
-		}
+		lock.unlock();
 	}
 
 #endif
@@ -2202,11 +2135,6 @@ GDScriptLanguage::GDScriptLanguage() {
 	_debug_parse_err_line = -1;
 	_debug_parse_err_file = "";
 
-#ifdef NO_THREADS
-	lock = NULL;
-#else
-	lock = Mutex::create();
-#endif
 	profiling = false;
 	script_frame_time = 0;
 
@@ -2240,10 +2168,6 @@ GDScriptLanguage::GDScriptLanguage() {
 
 GDScriptLanguage::~GDScriptLanguage() {
 
-	if (lock) {
-		memdelete(lock);
-		lock = NULL;
-	}
 	if (_call_stack) {
 		memdelete_arr(_call_stack);
 	}

+ 1 - 1
modules/gdscript/gdscript.h

@@ -351,7 +351,7 @@ class GDScriptLanguage : public ScriptLanguage {
 
 	friend class GDScriptInstance;
 
-	Mutex *lock;
+	Mutex lock;
 
 	friend class GDScript;
 

+ 8 - 26
modules/gdscript/gdscript_function.cpp

@@ -1279,9 +1279,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 				gdfs->state.ip = ip + ipofs;
 				gdfs->state.line = line;
 				gdfs->state.script = _script;
-#ifndef NO_THREADS
-				GDScriptLanguage::singleton->lock->lock();
-#endif
+				GDScriptLanguage::singleton->lock.lock();
 
 				_script->pending_func_states.add(&gdfs->scripts_list);
 				if (p_instance) {
@@ -1290,9 +1288,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 				} else {
 					gdfs->state.instance = NULL;
 				}
-#ifndef NO_THREADS
-				GDScriptLanguage::singleton->lock->unlock();
-#endif
+				GDScriptLanguage::singleton->lock.unlock();
 #ifdef DEBUG_ENABLED
 				gdfs->state.function_name = name;
 				gdfs->state.script_path = _script->get_path();
@@ -1776,14 +1772,9 @@ GDScriptFunction::GDScriptFunction() :
 #ifdef DEBUG_ENABLED
 	_func_cname = NULL;
 
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->lock();
-	}
+	GDScriptLanguage::get_singleton()->lock.lock();
 	GDScriptLanguage::get_singleton()->function_list.add(&function_list);
-
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->unlock();
-	}
+	GDScriptLanguage::get_singleton()->lock.unlock();
 
 	profile.call_count = 0;
 	profile.self_time = 0;
@@ -1800,14 +1791,9 @@ GDScriptFunction::GDScriptFunction() :
 
 GDScriptFunction::~GDScriptFunction() {
 #ifdef DEBUG_ENABLED
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->lock();
-	}
+	GDScriptLanguage::get_singleton()->lock.lock();
 	GDScriptLanguage::get_singleton()->function_list.remove(&function_list);
-
-	if (GDScriptLanguage::get_singleton()->lock) {
-		GDScriptLanguage::get_singleton()->lock->unlock();
-	}
+	GDScriptLanguage::get_singleton()->lock.unlock();
 #endif
 }
 
@@ -1958,12 +1944,8 @@ GDScriptFunctionState::GDScriptFunctionState() :
 GDScriptFunctionState::~GDScriptFunctionState() {
 
 	_clear_stack();
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->lock();
-#endif
+	GDScriptLanguage::singleton->lock.lock();
 	scripts_list.remove_from_list();
 	instances_list.remove_from_list();
-#ifndef NO_THREADS
-	GDScriptLanguage::singleton->lock->unlock();
-#endif
+	GDScriptLanguage::singleton->lock.unlock();
 }

+ 3 - 7
modules/gdscript/language_server/gdscript_language_server.cpp

@@ -36,7 +36,6 @@
 #include "editor/editor_node.h"
 
 GDScriptLanguageServer::GDScriptLanguageServer() {
-	thread = NULL;
 	thread_running = false;
 	started = false;
 
@@ -88,9 +87,8 @@ void GDScriptLanguageServer::start() {
 	if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
 		EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
 		if (use_thread) {
-			ERR_FAIL_COND(thread != NULL);
 			thread_running = true;
-			thread = Thread::create(GDScriptLanguageServer::thread_main, this);
+			thread.start(GDScriptLanguageServer::thread_main, this);
 		}
 		set_process_internal(!use_thread);
 		started = true;
@@ -99,11 +97,9 @@ void GDScriptLanguageServer::start() {
 
 void GDScriptLanguageServer::stop() {
 	if (use_thread) {
-		ERR_FAIL_COND(NULL == thread);
+		ERR_FAIL_COND(!thread.is_started());
 		thread_running = false;
-		Thread::wait_to_finish(thread);
-		memdelete(thread);
-		thread = NULL;
+		thread.wait_to_finish();
 	}
 	protocol.stop();
 	started = false;

+ 1 - 1
modules/gdscript/language_server/gdscript_language_server.h

@@ -40,7 +40,7 @@ class GDScriptLanguageServer : public EditorPlugin {
 
 	GDScriptLanguageProtocol protocol;
 
-	Thread *thread;
+	Thread thread;
 	bool thread_running;
 	bool started;
 	bool use_thread;

+ 3 - 3
modules/lightmapper_cpu/lightmapper_cpu.cpp

@@ -251,7 +251,8 @@ bool LightmapperCPU::_parallel_run(int p_count, const String &p_description, Bak
 	td.count = p_count;
 	td.thread_func = p_thread_func;
 	td.userdata = p_userdata;
-	Thread *runner_thread = Thread::create(_thread_func_callback, &td);
+	Thread runner_thread;
+	runner_thread.start(_thread_func_callback, &td);
 
 	int progress = thread_progress;
 
@@ -263,8 +264,7 @@ bool LightmapperCPU::_parallel_run(int p_count, const String &p_description, Bak
 		progress = thread_progress;
 	}
 	thread_cancelled = cancelled;
-	Thread::wait_to_finish(runner_thread);
-	memdelete(runner_thread);
+	runner_thread.wait_to_finish();
 #endif
 
 	thread_cancelled = false;

+ 14 - 56
modules/mono/csharp_script.cpp

@@ -57,7 +57,6 @@
 #include "mono_gd/gd_mono_utils.h"
 #include "signal_awaiter_utils.h"
 #include "utils/macros.h"
-#include "utils/mutex_utils.h"
 #include "utils/string_utils.h"
 #include "utils/thread_local.h"
 
@@ -638,7 +637,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
 
 void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
 #ifdef DEBUG_ENABLED
-	SCOPED_MUTEX_LOCK(unsafe_object_references_lock);
+	MutexLock lock(unsafe_object_references_lock);
 	ObjectID id = p_obj->get_instance_id();
 	unsafe_object_references[id]++;
 #endif
@@ -646,7 +645,7 @@ void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
 
 void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
 #ifdef DEBUG_ENABLED
-	SCOPED_MUTEX_LOCK(unsafe_object_references_lock);
+	MutexLock lock(unsafe_object_references_lock);
 	ObjectID id = p_obj->get_instance_id();
 	Map<ObjectID, int>::Element *elem = unsafe_object_references.find(id);
 	ERR_FAIL_NULL(elem);
@@ -769,7 +768,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
 	List<Ref<CSharpScript> > scripts;
 
 	{
-		SCOPED_MUTEX_LOCK(script_instances_mutex);
+		MutexLock lock(script_instances_mutex);
 
 		for (SelfList<CSharpScript> *elem = script_list.first(); elem; elem = elem->next()) {
 			// Cast to CSharpScript to avoid being erased by accident
@@ -1209,7 +1208,7 @@ void CSharpLanguage::set_language_index(int p_idx) {
 void CSharpLanguage::release_script_gchandle(Ref<MonoGCHandle> &p_gchandle) {
 
 	if (!p_gchandle->is_released()) { // Do not lock unnecessarily
-		SCOPED_MUTEX_LOCK(get_singleton()->script_gchandle_release_mutex);
+		MutexLock lock(get_singleton()->script_gchandle_release_mutex);
 		p_gchandle->release();
 	}
 }
@@ -1219,7 +1218,7 @@ void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, Ref<Mon
 	uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(p_expected_obj); // We might lock after this, so pin it
 
 	if (!p_gchandle->is_released()) { // Do not lock unnecessarily
-		SCOPED_MUTEX_LOCK(get_singleton()->script_gchandle_release_mutex);
+		MutexLock lock(get_singleton()->script_gchandle_release_mutex);
 
 		MonoObject *target = p_gchandle->get_target();
 
@@ -1244,24 +1243,6 @@ CSharpLanguage::CSharpLanguage() {
 
 	gdmono = NULL;
 
-#ifdef NO_THREADS
-	script_instances_mutex = NULL;
-	script_gchandle_release_mutex = NULL;
-	language_bind_mutex = NULL;
-#else
-	script_instances_mutex = Mutex::create();
-	script_gchandle_release_mutex = Mutex::create();
-	language_bind_mutex = Mutex::create();
-#endif
-
-#ifdef DEBUG_ENABLED
-#ifdef NO_THREADS
-	unsafe_object_references_lock = NULL;
-#else
-	unsafe_object_references_lock = Mutex::create();
-#endif
-#endif
-
 	lang_idx = -1;
 
 	scripts_metadata_invalidated = true;
@@ -1274,29 +1255,6 @@ CSharpLanguage::CSharpLanguage() {
 CSharpLanguage::~CSharpLanguage() {
 
 	finish();
-
-	if (script_instances_mutex) {
-		memdelete(script_instances_mutex);
-		script_instances_mutex = NULL;
-	}
-
-	if (language_bind_mutex) {
-		memdelete(language_bind_mutex);
-		language_bind_mutex = NULL;
-	}
-
-	if (script_gchandle_release_mutex) {
-		memdelete(script_gchandle_release_mutex);
-		script_gchandle_release_mutex = NULL;
-	}
-
-#ifdef DEBUG_ENABLED
-	if (unsafe_object_references_lock) {
-		memdelete(unsafe_object_references_lock);
-		unsafe_object_references_lock = NULL;
-	}
-#endif
-
 	singleton = NULL;
 }
 
@@ -1351,7 +1309,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
 
 void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
 
-	SCOPED_MUTEX_LOCK(language_bind_mutex);
+	MutexLock lock(language_bind_mutex);
 
 	Map<Object *, CSharpScriptBinding>::Element *match = script_bindings.find(p_object);
 	if (match)
@@ -1386,7 +1344,7 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
 	GD_MONO_ASSERT_THREAD_ATTACHED;
 
 	{
-		SCOPED_MUTEX_LOCK(language_bind_mutex);
+		MutexLock lock(language_bind_mutex);
 
 		Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
 
@@ -2216,7 +2174,7 @@ CSharpInstance::~CSharpInstance() {
 		CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
 
 		if (!script_binding.inited) {
-			SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->get_language_bind_mutex());
+			MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
 
 			if (!script_binding.inited) { // Other thread may have set it up
 				// Already had a binding that needs to be setup
@@ -2232,7 +2190,7 @@ CSharpInstance::~CSharpInstance() {
 	}
 
 	if (script.is_valid() && owner) {
-		SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+		MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
 
 #ifdef DEBUG_ENABLED
 		// CSharpInstance must not be created unless it's going to be added to the list for sure
@@ -3034,7 +2992,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
 		instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
 
 	{
-		SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+		MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
 		instances.insert(instance->owner);
 	}
 
@@ -3122,7 +3080,7 @@ PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_t
 
 bool CSharpScript::instance_has(const Object *p_this) const {
 
-	SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+	MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
 	return instances.has((Object *)p_this);
 }
 
@@ -3195,7 +3153,7 @@ Error CSharpScript::reload(bool p_keep_state) {
 
 	bool has_instances;
 	{
-		SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+		MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
 		has_instances = instances.size();
 	}
 
@@ -3394,7 +3352,7 @@ CSharpScript::CSharpScript() :
 
 #ifdef DEBUG_ENABLED
 	{
-		SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+		MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
 		CSharpLanguage::get_singleton()->script_list.add(&this->script_list);
 	}
 #endif
@@ -3403,7 +3361,7 @@ CSharpScript::CSharpScript() :
 CSharpScript::~CSharpScript() {
 
 #ifdef DEBUG_ENABLED
-	SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+	MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
 	CSharpLanguage::get_singleton()->script_list.remove(&this->script_list);
 #endif
 }

+ 5 - 5
modules/mono/csharp_script.h

@@ -307,16 +307,16 @@ class CSharpLanguage : public ScriptLanguage {
 	GDMono *gdmono;
 	SelfList<CSharpScript>::List script_list;
 
-	Mutex *script_instances_mutex;
-	Mutex *script_gchandle_release_mutex;
-	Mutex *language_bind_mutex;
+	Mutex script_instances_mutex;
+	Mutex script_gchandle_release_mutex;
+	Mutex language_bind_mutex;
 
 	Map<Object *, CSharpScriptBinding> script_bindings;
 
 #ifdef DEBUG_ENABLED
 	// List of unsafe object references
 	Map<ObjectID, int> unsafe_object_references;
-	Mutex *unsafe_object_references_lock;
+	Mutex unsafe_object_references_lock;
 #endif
 
 	struct StringNameCache {
@@ -358,7 +358,7 @@ class CSharpLanguage : public ScriptLanguage {
 public:
 	StringNameCache string_names;
 
-	Mutex *get_language_bind_mutex() { return language_bind_mutex; }
+	Mutex &get_language_bind_mutex() { return language_bind_mutex; }
 
 	_FORCE_INLINE_ int get_language_index() { return lang_idx; }
 	void set_language_index(int p_idx);

+ 1 - 2
modules/mono/mono_gd/gd_mono_utils.cpp

@@ -44,7 +44,6 @@
 
 #include "../csharp_script.h"
 #include "../utils/macros.h"
-#include "../utils/mutex_utils.h"
 #include "gd_mono.h"
 #include "gd_mono_cache.h"
 #include "gd_mono_class.h"
@@ -75,7 +74,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
 	CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
 
 	if (!script_binding.inited) {
-		SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->get_language_bind_mutex());
+		MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
 
 		if (!script_binding.inited) { // Other thread may have set it up
 			// Already had a binding that needs to be setup

Some files were not shown because too many files changed in this diff