diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 5750a6ef13f..04e668049c4 100644 --- a/core/bind/core_bind.cpp +++ b/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..."); } ///////////////////////////////////// diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index db0a9798d0c..fb7a276e934 100644 --- a/core/bind/core_bind.h +++ b/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); diff --git a/core/class_db.cpp b/core/class_db.cpp index 08c4d4b80b4..12ca85991fd 100644 --- a/core/class_db.cpp +++ b/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); } // diff --git a/core/class_db.h b/core/class_db.h index 0fed9110bbd..136af723765 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -143,7 +143,7 @@ public: return memnew(T); } - static RWLock *lock; + static RWLock lock; static HashMap classes; static HashMap resource_base_extensions; static HashMap compat_classes; @@ -393,7 +393,6 @@ public: static void get_extensions_for_type(const StringName &p_class, List *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(); diff --git a/core/command_queue_mt.cpp b/core/command_queue_mt.cpp index e4154423c79..316c6ce1c4f 100644 --- a/core/command_queue_mt.cpp +++ b/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); } diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h index 9a8a920f9d1..d71ef61cce6 100644 --- a/core/command_queue_mt.h +++ b/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 diff --git a/core/cowdata.h b/core/cowdata.h index 8739e5b57ef..d43688512ab 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -44,6 +44,9 @@ class CharString; template class VMap; +// CowData is relying on this to be true +static_assert(sizeof(SafeNumeric) == sizeof(uint32_t), ""); + template class CowData { template @@ -58,12 +61,12 @@ private: // internal helpers - _FORCE_INLINE_ uint32_t *_get_refcount() const { + _FORCE_INLINE_ SafeNumeric *_get_refcount() const { if (!_ptr) return NULL; - return reinterpret_cast(_ptr) - 2; + return reinterpret_cast *>(_ptr) - 2; } _FORCE_INLINE_ uint32_t *_get_size() const { @@ -193,9 +196,9 @@ void CowData::_unref(void *p_data) { if (!p_data) return; - uint32_t *refc = _get_refcount(); + SafeNumeric *refc = _get_refcount(); - if (atomic_decrement(refc) > 0) + if (refc->decrement() > 0) return; // still in use // clean up @@ -219,15 +222,15 @@ void CowData::_copy_on_write() { if (!_ptr) return; - uint32_t *refc = _get_refcount(); + SafeNumeric *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 *>(mem_new - 2)->set(1); //refcount *(mem_new - 1) = current_size; //size T *_data = (T *)(mem_new); @@ -279,7 +282,7 @@ Error CowData::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 *>(ptr - 2)->set(1); //refcount _ptr = (T *)ptr; @@ -360,7 +363,7 @@ void CowData::_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; } } diff --git a/core/error_macros.h b/core/error_macros.h index 27d48c26b55..c9ab2d58039 100644 --- a/core/error_macros.h +++ b/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(); \ } \ } diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index c110b4facfc..b3d37561c6a 100644 --- a/core/io/file_access_network.cpp +++ b/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 &p_block) { @@ -259,14 +248,14 @@ void FileAccessNetwork::_set_block(int p_offset, const Vector &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(); diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index ad407199957..c8edeaa1198 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -49,11 +49,11 @@ class FileAccessNetworkClient { List block_requests; - Semaphore *sem; - Thread *thread; + Semaphore sem; + Thread thread; bool quit; - Mutex *mutex; - Mutex *blockrequest_mutex; + Mutex mutex; + Mutex blockrequest_mutex; Map accesses; Ref 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; diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 6e8389d05e5..3c755be451d 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -42,13 +42,13 @@ struct _IP_ResolverPrivate { struct QueueItem { - volatile IP::ResolverStatus status; + SafeNumeric 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); - } + resolver->thread_abort = true; + resolver->sem.post(); + resolver->thread.wait_to_finish(); -#endif - - memdelete(resolver->mutex); memdelete(resolver); } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index e65a4fdc6fe..19cd36d2a95 100644 --- a/core/io/resource_loader.cpp +++ b/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 to_reload; SelfList *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::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 } diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index a071dfba561..9b4e824df88 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -120,7 +120,7 @@ class ResourceLoader { static ResourceLoadedCallback _loaded_callback; static Ref _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(); }; diff --git a/core/object.cpp b/core/object.cpp index 3604ca8843d..27d95dcf252 100644 --- a/core/object.cpp +++ b/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 *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(); } diff --git a/core/object.h b/core/object.h index b0d1e9505b8..8e20eea74dd 100644 --- a/core/object.h +++ b/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 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; } diff --git a/core/os/memory.cpp b/core/os/memory.cpp index 9a37e2194d3..5c47efc7628 100644 --- a/core/os/memory.cpp +++ b/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 Memory::mem_usage; +SafeNumeric Memory::max_usage; #endif -uint64_t Memory::alloc_count = 0; +SafeNumeric 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 diff --git a/core/os/memory.h b/core/os/memory.h index 1541464b869..84ff44c3a21 100644 --- a/core/os/memory.h +++ b/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 mem_usage; + static SafeNumeric max_usage; #endif - static uint64_t alloc_count; + static SafeNumeric alloc_count; public: static void *alloc_static(size_t p_bytes, bool p_pad_align = false); diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp index 6a87a095a3f..d0582a4ee28 100644 --- a/core/os/mutex.cpp +++ b/core/os/mutex.cpp @@ -30,31 +30,19 @@ #include "mutex.h" -#include "core/error_macros.h" - -#include - -Mutex *(*Mutex::create_func)(bool) = 0; - -Mutex *Mutex::create(bool p_recursive) { - - ERR_FAIL_COND_V(!create_func, 0); - - return create_func(p_recursive); -} - -Mutex::~Mutex() { -} - -Mutex *_global_mutex = NULL; +static Mutex _global_mutex; void _global_lock() { - - if (_global_mutex) - _global_mutex->lock(); + _global_mutex.lock(); } + void _global_unlock() { - - if (_global_mutex) - _global_mutex->unlock(); + _global_mutex.unlock(); } + +#ifndef NO_THREADS + +template class MutexImpl; +template class MutexImpl; + +#endif diff --git a/core/os/mutex.h b/core/os/mutex.h index 53c171bd156..f282bb30cea 100644 --- a/core/os/mutex.h +++ b/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 + +template +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 lock; +class MutexLock { + union { + std::recursive_mutex *recursive_mutex; + std::mutex *mutex; + }; + bool recursive; + +public: + _ALWAYS_INLINE_ explicit MutexLock(const MutexImpl &p_mutex) : + recursive_mutex(&p_mutex.mutex), + recursive(true) { + recursive_mutex->lock(); + } + _ALWAYS_INLINE_ explicit MutexLock(const MutexImpl &p_mutex) : + mutex(&p_mutex.mutex), + recursive(false) { + mutex->lock(); + } + + _ALWAYS_INLINE_ ~MutexLock() { + if (recursive) { + recursive_mutex->unlock(); + } else { + mutex->unlock(); + } + } +}; + +using Mutex = MutexImpl; // Recursive, for general use +using BinaryMutex = MutexImpl; // Non-recursive, handle with care + +extern template class MutexImpl; +extern template class MutexImpl; + +#else + +class FakeMutex { + FakeMutex() {} +}; + +template +class MutexImpl { +public: + _ALWAYS_INLINE_ void lock() const {} + _ALWAYS_INLINE_ void unlock() const {} + _ALWAYS_INLINE_ Error try_lock() const { return OK; } }; class MutexLock { - - Mutex *mutex; - public: - MutexLock(Mutex *p_mutex) { - mutex = p_mutex; - if (mutex) mutex->lock(); - } - ~MutexLock() { - if (mutex) mutex->unlock(); - } + explicit MutexLock(const MutexImpl &p_mutex) {} }; -#endif +using Mutex = MutexImpl; +using BinaryMutex = MutexImpl; // Non-recursive, handle with care + +#endif // !NO_THREADS + +#endif // MUTEX_H diff --git a/core/os/os.h b/core/os/os.h index 227d1e73c16..29582991953 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -41,8 +41,6 @@ #include -class Mutex; - class OS { static OS *singleton; diff --git a/core/os/rw_lock.cpp b/core/os/rw_lock.cpp deleted file mode 100644 index 681845efe47..00000000000 --- a/core/os/rw_lock.cpp +++ /dev/null @@ -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 - -RWLock *(*RWLock::create_func)() = 0; - -RWLock *RWLock::create() { - - ERR_FAIL_COND_V(!create_func, 0); - - return create_func(); -} - -RWLock::~RWLock() { -} diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h index 6fecc1fed86..2e61ddd685e 100644 --- a/core/os/rw_lock.h +++ b/core/os/rw_lock.h @@ -33,49 +33,85 @@ #include "core/error_list.h" +#if !defined(NO_THREADS) + +#include + 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; + } - virtual ~RWLock(); + // 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(); + } + + // 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(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(); } }; diff --git a/core/os/semaphore.cpp b/core/os/semaphore.cpp deleted file mode 100644 index 32bbeceb34d..00000000000 --- a/core/os/semaphore.cpp +++ /dev/null @@ -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() { -} diff --git a/core/os/semaphore.h b/core/os/semaphore.h index 6ddb36879e9..8efd6425ad5 100644 --- a/core/os/semaphore.h +++ b/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 +#include 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 lock(mutex_); + ++count_; + condition_.notify_one(); + } - static Semaphore *create(); ///< Create a mutex + _ALWAYS_INLINE_ void wait() const { + std::unique_lock lock(mutex_); + while (!count_) { // Handle spurious wake-ups. + condition_.wait(lock); + } + --count_; + } - virtual ~Semaphore(); + _ALWAYS_INLINE_ bool try_wait() const { + std::lock_guard lock(mutex_); + if (count_) { + --count_; + return true; + } + return false; + } + + _ALWAYS_INLINE_ int get() const { + std::lock_guard 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 diff --git a/core/os/thread.cpp b/core/os/thread.cpp index 187c409e30b..ff1c03ca8e7 100644 --- a/core/os/thread.cpp +++ b/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::ID Thread::main_thread_id = 1; +SafeNumeric Thread::last_thread_id{ 1 }; +thread_local Thread::ID Thread::caller_id = 1; + +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; } -Thread *Thread::create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings) { - - if (create_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; +} + +void Thread::wait_to_finish() { + if (id != 0) { + thread.join(); + std::thread empty_thread; + thread.swap(empty_thread); + id = 0; + } } Error Thread::set_name(const String &p_name) { - - if (set_name_func) + 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 diff --git a/core/os/thread.h b/core/os/thread.h index a0e9b109a46..837f9323c37 100644 --- a/core/os/thread.h +++ b/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 +#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; - -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 &); - +private: +#if !defined(NO_THREADS) friend class Main; - static ID _main_thread_id; + static ID main_thread_id; + static SafeNumeric last_thread_id; - Thread(); + ID id; + static thread_local ID caller_id; + std::thread thread; + + static void callback(Thread *p_self, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata); + + 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 +#endif // THREAD_H diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp deleted file mode 100644 index 0e6a59a11ac..00000000000 --- a/core/os/thread_dummy.cpp +++ /dev/null @@ -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; -}; diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h deleted file mode 100644 index 6f3837a9116..00000000000 --- a/core/os/thread_dummy.h +++ /dev/null @@ -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 diff --git a/core/os/thread_safe.cpp b/core/os/thread_safe.cpp deleted file mode 100644 index 8c15636229e..00000000000 --- a/core/os/thread_safe.cpp +++ /dev/null @@ -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); -} diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h index b799e219014..ae2110cb481 100644 --- a/core/os/thread_safe.h +++ b/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 diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h index 850cddb7dfb..94783ddb660 100644 --- a/core/os/threaded_array_processor.h +++ b/core/os/threaded_array_processor.h @@ -40,7 +40,7 @@ template struct ThreadArrayProcessData { uint32_t elements; - uint32_t index; + SafeNumeric 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 + data.process(0); //process first, let threads increment for next - Vector threads; + int thread_count = OS::get_singleton()->get_processor_count(); + Thread *threads = memnew_arr(Thread, thread_count); - threads.resize(OS::get_singleton()->get_processor_count()); - - for (int i = 0; i < threads.size(); i++) { - threads.write[i] = Thread::create(process_array_thread >, &data); + for (int i = 0; i < thread_count; i++) { + threads[i].start(process_array_thread >, &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 diff --git a/core/pool_vector.cpp b/core/pool_vector.cpp index 263d9e9f3b0..98c5cfe2d66 100644 --- a/core/pool_vector.cpp +++ b/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!"); } diff --git a/core/pool_vector.h b/core/pool_vector.h index f142fafdc7e..dc7a5fe81c3 100644 --- a/core/pool_vector.h +++ b/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 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::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::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::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::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); diff --git a/core/reference.cpp b/core/reference.cpp index 1ba9e6151aa..9fd732e4ba4 100644 --- a/core/reference.cpp +++ b/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); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index b1cdab53085..3fa881e36c4 100644 --- a/core/register_core_types.cpp +++ b/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(); } diff --git a/core/resource.cpp b/core/resource.cpp index 0ba5ee3734e..f0c30928dc5 100644 --- a/core/resource.cpp +++ b/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 ResourceCache::resources; HashMap > 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 > *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(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 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 } diff --git a/core/resource.h b/core/resource.h index 74b6a00e11e..d94e1b54314 100644 --- a/core/resource.h +++ b/core/resource.h @@ -148,16 +148,15 @@ typedef Ref RES; class ResourceCache { friend class Resource; friend class ResourceLoader; //need the lock - static RWLock *lock; + static RWLock lock; static HashMap resources; #ifdef TOOLS_ENABLED static HashMap > 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(); diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp deleted file mode 100644 index 376d9a99e4d..00000000000 --- a/core/safe_refcount.cpp +++ /dev/null @@ -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 - -#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_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_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 diff --git a/core/safe_refcount.h b/core/safe_refcount.h index f37d9d7d0d5..4840d90dd06 100644 --- a/core/safe_refcount.h +++ b/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 -/* 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 -static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) { - - if (*pw == 0) - return 0; - - (*pw)++; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) { - - (*pw)--; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) { - - (*pw)++; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) { - - (*pw) -= val; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) { - - (*pw) += val; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) { - - if (val > *pw) - *pw = val; - - return *pw; -} - -#elif defined(__GNUC__) - -/* Implementation for GCC & Clang */ - -// GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes. -// Clang states it supports GCC atomic builtins. - -template -static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) { - - while (true) { - T tmp = static_cast(*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; - } -} - -template -static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) { - - return __sync_sub_and_fetch(pw, 1); -} - -template -static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) { - - return __sync_add_and_fetch(pw, 1); -} - -template -static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) { - - return __sync_sub_and_fetch(pw, val); -} - -template -static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) { - - return __sync_add_and_fetch(pw, val); -} - -template -static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) { - - while (true) { - T tmp = static_cast(*pw); - if (tmp >= val) - return tmp; // already greater, or equal - if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) - return val; - } -} - -#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); - -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); - -#else -//no threads supported? -#error Must provide atomic functions for this platform or compiler! -#endif - -struct SafeRefCount { - - uint32_t count; +class SafeNumeric { + std::atomic value; public: - // destroy() is called when weak_count_ drops to zero. + _ALWAYS_INLINE_ void set(T p_value) { + value.store(p_value, std::memory_order_release); + } + _ALWAYS_INLINE_ T get() const { + return value.load(std::memory_order_acquire); + } + + _ALWAYS_INLINE_ T increment() { + return value.fetch_add(1, std::memory_order_acq_rel) + 1; + } + + // Returns the original value instead of the new one + _ALWAYS_INLINE_ T postincrement() { + return value.fetch_add(1, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T decrement() { + return value.fetch_sub(1, std::memory_order_acq_rel) - 1; + } + + // Returns the original value instead of the new one + _ALWAYS_INLINE_ T postdecrement() { + return value.fetch_sub(1, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T add(T p_value) { + return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value; + } + + // 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); + } + + _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; + } + } + } + + _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; + } + } + } + + _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) { + set(p_value); + } +}; + +class SafeFlag { + std::atomic_bool flag; + +public: + _ALWAYS_INLINE_ bool is_set() const { + return flag.load(std::memory_order_acquire); + } + + _ALWAYS_INLINE_ void set() { + flag.store(true, std::memory_order_release); + } + + _ALWAYS_INLINE_ void clear() { + flag.store(false, std::memory_order_release); + } + + _ALWAYS_INLINE_ void set_to(bool p_value) { + flag.store(p_value, std::memory_order_release); + } + + _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) { + set_to(p_value); + } +}; + +class SafeRefCount { + SafeNumeric count; + +public: _ALWAYS_INLINE_ bool ref() { // true on success - - return atomic_conditional_increment(&count) != 0; + return count.conditional_increment() != 0; } _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success - - return atomic_conditional_increment(&count); + return count.conditional_increment(); } _ALWAYS_INLINE_ bool unref() { // true if must be disposed of - - return atomic_decrement(&count) == 0; + return count.decrement() == 0; } _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of - - return atomic_decrement(&count); + return count.decrement(); } - _ALWAYS_INLINE_ uint32_t get() const { // nothrow + _ALWAYS_INLINE_ uint32_t get() const { + return count.get(); + } + _ALWAYS_INLINE_ void init(uint32_t p_value = 1) { + count.set(p_value); + } +}; + +#else + +template +class SafeNumeric { +protected: + T value; + +public: + _ALWAYS_INLINE_ void set(T p_value) { + value = p_value; + } + + _ALWAYS_INLINE_ T get() const { + return value; + } + + _ALWAYS_INLINE_ T increment() { + return ++value; + } + + _ALWAYS_INLINE_ T postincrement() { + return value++; + } + + _ALWAYS_INLINE_ T decrement() { + return --value; + } + + _ALWAYS_INLINE_ T postdecrement() { + return value--; + } + + _ALWAYS_INLINE_ T add(T p_value) { + return value += p_value; + } + + _ALWAYS_INLINE_ T postadd(T p_value) { + T old = value; + value += p_value; + return old; + } + + _ALWAYS_INLINE_ T sub(T p_value) { + return value -= p_value; + } + + _ALWAYS_INLINE_ T postsub(T p_value) { + T old = value; + value -= p_value; + return old; + } + + _ALWAYS_INLINE_ T exchange_if_greater(T p_value) { + if (value < p_value) { + value = p_value; + } + return value; + } + + _ALWAYS_INLINE_ T conditional_increment() { + if (value != 0) { + return 0; + } else { + return ++value; + } + } + + _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) : + value(p_value) { + } +}; + +class SafeFlag { +protected: + bool flag; + +public: + _ALWAYS_INLINE_ bool is_set() const { + return flag; + } + + _ALWAYS_INLINE_ void set() { + flag = true; + } + + _ALWAYS_INLINE_ void clear() { + flag = false; + } + + _ALWAYS_INLINE_ void set_to(bool p_value) { + flag = p_value; + } + + _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 refval() { // none-zero on success + if (count != 0) { + return ++count; + } else { + return 0; + } + } + + _ALWAYS_INLINE_ bool unref() { // true if must be disposed of + return --count == 0; + } + + _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 diff --git a/core/string_name.cpp b/core/string_name.cpp index ac2d467c9fe..d2e5ca26bef 100644 --- a/core/string_name.cpp +++ b/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 } diff --git a/core/string_name.h b/core/string_name.h index 73ced5c456e..bb77be9450a 100644 --- a/core/string_name.h +++ b/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; diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 83ed02e1a30..ea561bc6a73 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/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") { diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index 0e8ff2228b5..23012fe331d 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/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; diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index 95a44664941..43c333ecdc3 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/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; } diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index ca2d8c040b9..60f3dc56780 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -43,8 +43,8 @@ class MIDIDriverALSAMidi : public MIDIDriver { - Thread *thread; - Mutex *mutex; + Thread thread; + Mutex mutex; Vector connected_inputs; diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index fd8d637782a..eab4ea99e61 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/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), diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index 0719e923072..40f93950247 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/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; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 5de874301e6..39ca601c5e1 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/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), diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index cf5090730b5..20c4e6cd6ca 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/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; diff --git a/drivers/unix/mutex_posix.cpp b/drivers/unix/mutex_posix.cpp deleted file mode 100644 index c731ecf683f..00000000000 --- a/drivers/unix/mutex_posix.cpp +++ /dev/null @@ -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 diff --git a/drivers/unix/mutex_posix.h b/drivers/unix/mutex_posix.h deleted file mode 100644 index c3ef6e1cf62..00000000000 --- a/drivers/unix/mutex_posix.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 4bb56ab931c..ac233889028 100644 --- a/drivers/unix/os_unix.cpp +++ b/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 #include #include +#include #include /// 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(FileAccess::ACCESS_RESOURCES); FileAccess::make_default(FileAccess::ACCESS_USERDATA); FileAccess::make_default(FileAccess::ACCESS_FILESYSTEM); @@ -310,13 +298,9 @@ Error OS_Unix::execute(const String &p_path, const List &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) diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp deleted file mode 100644 index 58cefabe3a9..00000000000 --- a/drivers/unix/rw_lock_posix.cpp +++ /dev/null @@ -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 - -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 diff --git a/drivers/unix/rw_lock_posix.h b/drivers/unix/rw_lock_posix.h deleted file mode 100644 index 513d84a9c8b..00000000000 --- a/drivers/unix/rw_lock_posix.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp deleted file mode 100644 index 32055401a51..00000000000 --- a/drivers/unix/semaphore_posix.cpp +++ /dev/null @@ -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 -#include - -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 diff --git a/drivers/unix/semaphore_posix.h b/drivers/unix/semaphore_posix.h deleted file mode 100644 index 53c27dc9fe3..00000000000 --- a/drivers/unix/semaphore_posix.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index 1854778d2d6..ff340480020 100644 --- a/drivers/unix/thread_posix.cpp +++ b/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" +#include "thread_posix.h" -#ifdef PTHREAD_BSD_SET_NAME -#include -#endif - -static void _thread_id_key_destr_callback(void *p_value) { - memdelete(static_cast(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(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(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(p_thread); - ERR_FAIL_COND(!tp); - ERR_FAIL_COND(tp->pthread == 0); - - pthread_join(tp->pthread, NULL); - tp->pthread = 0; -} - -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 diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h index d97e5629755..8b8a736bf01 100644 --- a/drivers/unix/thread_posix.h +++ b/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 -#include - -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 diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 0fa5565dbb5..6cd474e1a7e 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/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; diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 59387c7474d..9fd731dcf86 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/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 samples_in; diff --git a/drivers/windows/mutex_windows.cpp b/drivers/windows/mutex_windows.cpp deleted file mode 100644 index 847f625f952..00000000000 --- a/drivers/windows/mutex_windows.cpp +++ /dev/null @@ -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 diff --git a/drivers/windows/mutex_windows.h b/drivers/windows/mutex_windows.h deleted file mode 100644 index 0fb994773ac..00000000000 --- a/drivers/windows/mutex_windows.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/windows/rw_lock_windows.cpp b/drivers/windows/rw_lock_windows.cpp deleted file mode 100644 index db29d0d1c5b..00000000000 --- a/drivers/windows/rw_lock_windows.cpp +++ /dev/null @@ -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 - -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 diff --git a/drivers/windows/rw_lock_windows.h b/drivers/windows/rw_lock_windows.h deleted file mode 100644 index b91495f4ec0..00000000000 --- a/drivers/windows/rw_lock_windows.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/windows/semaphore_windows.cpp b/drivers/windows/semaphore_windows.cpp deleted file mode 100644 index 9f39bda3e69..00000000000 --- a/drivers/windows/semaphore_windows.cpp +++ /dev/null @@ -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 diff --git a/drivers/windows/semaphore_windows.h b/drivers/windows/semaphore_windows.h deleted file mode 100644 index 56499689f52..00000000000 --- a/drivers/windows/semaphore_windows.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp deleted file mode 100644 index ec5ccbd3b5c..00000000000 --- a/drivers/windows/thread_windows.cpp +++ /dev/null @@ -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(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(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 diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h deleted file mode 100644 index 0018bb4bde2..00000000000 --- a/drivers/windows/thread_windows.h +++ /dev/null @@ -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 - -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 diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 871b13de0e1..7da2d04f18a 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/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++) { diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index e9002ca12ce..0b5a9dca08a 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/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]; diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp index ffd2336a640..7f5cfb3a8c9 100644 --- a/editor/audio_stream_preview.cpp +++ b/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 AudioStreamPreviewGenerator::generate_preview(const Ref &p_stream) { @@ -175,7 +175,7 @@ Ref 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 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 to_erase; for (Map::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 diff --git a/editor/audio_stream_preview.h b/editor/audio_stream_preview.h index a2fa5c63c21..4725fb727c8 100644 --- a/editor/audio_stream_preview.h +++ b/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 preview; Ref base_stream; Ref 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 previews; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 0bc53d6e7ce..2c037594ebd 100644 --- a/editor/editor_file_system.cpp +++ b/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 *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; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 5d10d306a9f..d768b919c64 100644 --- a/editor/editor_file_system.h +++ b/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; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 129a9c2fd26..1db054c26ff 100644 --- a/editor/editor_node.cpp +++ b/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 &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) { diff --git a/editor/editor_node.h b/editor/editor_node.h index 6356b217297..cddc0c84e49 100644 --- a/editor/editor_node.h +++ b/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 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: diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 71c340a93aa..18ddd05c398 100644 --- a/editor/editor_resource_preview.cpp +++ b/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 &p_texture, const Ref &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 Refunlock(); + 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 &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 texture; Ref 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 &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 &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 &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 &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 &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); } diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 243f8b423ff..1283fabe118 100644 --- a/editor/editor_resource_preview.h +++ b/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 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 preview; diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index 7af3f71d58d..4e723dd1ddf 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/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(); } diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h index f0394753db1..1ba7803fab9 100644 --- a/editor/fileserver/editor_file_server.h +++ b/editor/fileserver/editor_file_server.h @@ -49,7 +49,7 @@ class EditorFileServer : public Object { struct ClientData { - Thread *thread; + Thread thread; Ref connection; Map 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; diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index e830b4e027d..5f01c0352d1 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -38,7 +38,7 @@ void ResourceImporterTexture::_texture_reimport_srgb(const Ref &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 &p singleton->make_flags[path] |= MAKE_SRGB_FLAG; - singleton->mutex->unlock(); + singleton->mutex.unlock(); } void ResourceImporterTexture::_texture_reimport_3d(const Ref &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 &p_t singleton->make_flags[path] |= MAKE_3D_FLAG; - singleton->mutex->unlock(); + singleton->mutex.unlock(); } void ResourceImporterTexture::_texture_reimport_normal(const Ref &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 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); } diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index be9a88ac600..9a2c3a37a1b 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -46,7 +46,7 @@ protected: MAKE_NORMAL_FLAG = 4 }; - Mutex *mutex; + Mutex mutex; Map make_flags; static void _texture_reimport_srgb(const Ref &p_tex); @@ -94,7 +94,6 @@ public: virtual String get_import_settings_string() const; ResourceImporterTexture(); - ~ResourceImporterTexture(); }; #endif // RESOURCEIMPORTTEXTURE_H diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 96a0cba4855..f24feae7e70 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/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 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(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 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(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 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(this), "_preview_done", Variant()); - while (!preview_done) { + while (!preview_done.is_set()) { OS::get_singleton()->delay_usec(10); } diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index dce3754e8f1..8d2b8d6d13f 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/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 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); diff --git a/main/main.cpp b/main/main.cpp index 985ebdbb26b..4e10566a99a 100644 --- a/main/main.cpp +++ b/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) { diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 37620790a30..7f9a90828a9 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/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 @@ -56,7 +57,7 @@ struct CVTTCompressionJobQueue { CVTTCompressionJobParams job_params; const CVTTCompressionRowTask *job_tasks; uint32_t num_tasks; - uint32_t current_task; + SafeNumeric 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(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::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(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]); } } diff --git a/modules/gdnative/android/android_gdn.cpp b/modules/gdnative/android/android_gdn.cpp index aec2ea0cbfd..198e5302a1d 100644 --- a/modules/gdnative/android/android_gdn.cpp +++ b/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 diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 5c0f8a74a0b..43e8228ca45 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/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(); 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 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 >::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 diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index de0dfe56fdc..45ebe950e32 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/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 instance_owners; protected: @@ -238,11 +237,11 @@ private: void _unload_stuff(bool p_reload = false); #ifndef NO_THREADS - Mutex *mutex; + Mutex mutex; Set > libs_to_init; Set 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 lib, NativeScript *script); #endif diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 35fe2c2fe2c..46e621fba72 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -400,39 +400,15 @@ void PluginScriptLanguage::reload_tool_script(const Ref