mirror of
https://github.com/tiennm99/godot.git
synced 2026-08-05 22:24:56 +00:00
Merge pull request #45618 from RandomShaper/modernize_mt_3.2
Backport of all the multi-threading modernization (3.2)
This commit is contained in:
+16
-50
@@ -2689,12 +2689,14 @@ void _Marshalls::_bind_methods() {
|
||||
|
||||
Error _Semaphore::wait() {
|
||||
|
||||
return semaphore->wait();
|
||||
semaphore.wait();
|
||||
return OK; // Can't fail anymore; keep compat
|
||||
}
|
||||
|
||||
Error _Semaphore::post() {
|
||||
|
||||
return semaphore->post();
|
||||
semaphore.post();
|
||||
return OK; // Can't fail anymore; keep compat
|
||||
}
|
||||
|
||||
void _Semaphore::_bind_methods() {
|
||||
@@ -2703,31 +2705,21 @@ void _Semaphore::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("post"), &_Semaphore::post);
|
||||
}
|
||||
|
||||
_Semaphore::_Semaphore() {
|
||||
|
||||
semaphore = Semaphore::create();
|
||||
}
|
||||
|
||||
_Semaphore::~_Semaphore() {
|
||||
|
||||
memdelete(semaphore);
|
||||
}
|
||||
|
||||
///////////////
|
||||
|
||||
void _Mutex::lock() {
|
||||
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
Error _Mutex::try_lock() {
|
||||
|
||||
return mutex->try_lock();
|
||||
return mutex.try_lock();
|
||||
}
|
||||
|
||||
void _Mutex::unlock() {
|
||||
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void _Mutex::_bind_methods() {
|
||||
@@ -2737,16 +2729,6 @@ void _Mutex::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("unlock"), &_Mutex::unlock);
|
||||
}
|
||||
|
||||
_Mutex::_Mutex() {
|
||||
|
||||
mutex = Mutex::create();
|
||||
}
|
||||
|
||||
_Mutex::~_Mutex() {
|
||||
|
||||
memdelete(mutex);
|
||||
}
|
||||
|
||||
///////////////
|
||||
|
||||
void _Thread::_start_func(void *ud) {
|
||||
@@ -2790,7 +2772,7 @@ void _Thread::_start_func(void *ud) {
|
||||
|
||||
Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
|
||||
|
||||
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "Thread already started.");
|
||||
ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started.");
|
||||
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
|
||||
@@ -2799,49 +2781,35 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia
|
||||
target_method = p_method;
|
||||
target_instance = p_instance;
|
||||
userdata = p_userdata;
|
||||
active = true;
|
||||
active.set();
|
||||
|
||||
Ref<_Thread> *ud = memnew(Ref<_Thread>(this));
|
||||
|
||||
Thread::Settings s;
|
||||
s.priority = (Thread::Priority)p_priority;
|
||||
thread = Thread::create(_start_func, ud, s);
|
||||
if (!thread) {
|
||||
active = false;
|
||||
target_method = StringName();
|
||||
target_instance = NULL;
|
||||
userdata = Variant();
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
thread.start(_start_func, ud, s);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String _Thread::get_id() const {
|
||||
|
||||
if (!thread)
|
||||
return String();
|
||||
|
||||
return itos(thread->get_id());
|
||||
return itos(thread.get_id());
|
||||
}
|
||||
|
||||
bool _Thread::is_active() const {
|
||||
|
||||
return active;
|
||||
return active.is_set();
|
||||
}
|
||||
Variant _Thread::wait_to_finish() {
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!thread, Variant(), "Thread must exist to wait for its completion.");
|
||||
ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion.");
|
||||
Thread::wait_to_finish(thread);
|
||||
ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion.");
|
||||
thread.wait_to_finish();
|
||||
Variant r = ret;
|
||||
active = false;
|
||||
target_method = StringName();
|
||||
target_instance = NULL;
|
||||
userdata = Variant();
|
||||
if (thread)
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
active.clear();
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -2859,14 +2827,12 @@ void _Thread::_bind_methods() {
|
||||
}
|
||||
_Thread::_Thread() {
|
||||
|
||||
active = false;
|
||||
thread = NULL;
|
||||
target_instance = NULL;
|
||||
}
|
||||
|
||||
_Thread::~_Thread() {
|
||||
|
||||
ERR_FAIL_COND_MSG(active, "Reference to a Thread object was lost while the thread is still running...");
|
||||
ERR_FAIL_COND_MSG(active.is_set(), "Reference to a Thread object was lost while the thread is still running...");
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
+5
-10
@@ -40,6 +40,7 @@
|
||||
#include "core/os/os.h"
|
||||
#include "core/os/semaphore.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/safe_refcount.h"
|
||||
|
||||
class _ResourceLoader : public Object {
|
||||
GDCLASS(_ResourceLoader, Object);
|
||||
@@ -652,7 +653,7 @@ public:
|
||||
class _Mutex : public Reference {
|
||||
|
||||
GDCLASS(_Mutex, Reference);
|
||||
Mutex *mutex;
|
||||
Mutex mutex;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
@@ -660,24 +661,18 @@ public:
|
||||
void lock();
|
||||
Error try_lock();
|
||||
void unlock();
|
||||
|
||||
_Mutex();
|
||||
~_Mutex();
|
||||
};
|
||||
|
||||
class _Semaphore : public Reference {
|
||||
|
||||
GDCLASS(_Semaphore, Reference);
|
||||
Semaphore *semaphore;
|
||||
Semaphore semaphore;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
Error wait();
|
||||
Error post();
|
||||
|
||||
_Semaphore();
|
||||
~_Semaphore();
|
||||
};
|
||||
|
||||
class _Thread : public Reference {
|
||||
@@ -687,10 +682,10 @@ class _Thread : public Reference {
|
||||
protected:
|
||||
Variant ret;
|
||||
Variant userdata;
|
||||
volatile bool active;
|
||||
SafeFlag active;
|
||||
Object *target_instance;
|
||||
StringName target_method;
|
||||
Thread *thread;
|
||||
Thread thread;
|
||||
static void _bind_methods();
|
||||
static void _start_func(void *ud);
|
||||
|
||||
|
||||
+3
-10
@@ -929,9 +929,9 @@ void ClassDB::add_property_group(StringName p_class, const String &p_name, const
|
||||
|
||||
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
|
||||
|
||||
lock->read_lock();
|
||||
lock.read_lock();
|
||||
ClassInfo *type = classes.getptr(p_class);
|
||||
lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
|
||||
ERR_FAIL_COND(!type);
|
||||
|
||||
@@ -1447,12 +1447,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
|
||||
return default_values[p_class][p_property];
|
||||
}
|
||||
|
||||
RWLock *ClassDB::lock = NULL;
|
||||
|
||||
void ClassDB::init() {
|
||||
|
||||
lock = RWLock::create();
|
||||
}
|
||||
RWLock ClassDB::lock;
|
||||
|
||||
void ClassDB::cleanup_defaults() {
|
||||
|
||||
@@ -1479,8 +1474,6 @@ void ClassDB::cleanup() {
|
||||
classes.clear();
|
||||
resource_base_extensions.clear();
|
||||
compat_classes.clear();
|
||||
|
||||
memdelete(lock);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
+1
-2
@@ -143,7 +143,7 @@ public:
|
||||
return memnew(T);
|
||||
}
|
||||
|
||||
static RWLock *lock;
|
||||
static RWLock lock;
|
||||
static HashMap<StringName, ClassInfo> classes;
|
||||
static HashMap<StringName, StringName> resource_base_extensions;
|
||||
static HashMap<StringName, StringName> compat_classes;
|
||||
@@ -393,7 +393,6 @@ public:
|
||||
static void get_extensions_for_type(const StringName &p_class, List<String> *p_extensions);
|
||||
|
||||
static void add_compatibility_class(const StringName &p_class, const StringName &p_fallback);
|
||||
static void init();
|
||||
|
||||
static void set_current_api(APIType p_api);
|
||||
static APIType get_current_api();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
cmd->sync_sem = ss; \
|
||||
unlock(); \
|
||||
if (sync) sync->post(); \
|
||||
ss->sem->wait(); \
|
||||
ss->sem.wait(); \
|
||||
ss->in_use = false; \
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
cmd->sync_sem = ss; \
|
||||
unlock(); \
|
||||
if (sync) sync->post(); \
|
||||
ss->sem->wait(); \
|
||||
ss->sem.wait(); \
|
||||
ss->in_use = false; \
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ class CommandQueueMT {
|
||||
|
||||
struct SyncSemaphore {
|
||||
|
||||
Semaphore *sem;
|
||||
Semaphore sem;
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
@@ -293,7 +293,7 @@ class CommandQueueMT {
|
||||
SyncSemaphore *sync_sem;
|
||||
|
||||
virtual void post() {
|
||||
sync_sem->sem->post();
|
||||
sync_sem->sem.post();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -321,7 +321,7 @@ class CommandQueueMT {
|
||||
uint32_t dealloc_ptr;
|
||||
uint32_t command_mem_size;
|
||||
SyncSemaphore sync_sems[SYNC_SEMAPHORES];
|
||||
Mutex *mutex;
|
||||
Mutex mutex;
|
||||
Semaphore *sync;
|
||||
|
||||
template <class T>
|
||||
|
||||
+12
-9
@@ -44,6 +44,9 @@ class CharString;
|
||||
template <class T, class V>
|
||||
class VMap;
|
||||
|
||||
// CowData is relying on this to be true
|
||||
static_assert(sizeof(SafeNumeric<uint32_t>) == sizeof(uint32_t), "");
|
||||
|
||||
template <class T>
|
||||
class CowData {
|
||||
template <class TV>
|
||||
@@ -58,12 +61,12 @@ private:
|
||||
|
||||
// internal helpers
|
||||
|
||||
_FORCE_INLINE_ uint32_t *_get_refcount() const {
|
||||
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
|
||||
|
||||
if (!_ptr)
|
||||
return NULL;
|
||||
|
||||
return reinterpret_cast<uint32_t *>(_ptr) - 2;
|
||||
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t *_get_size() const {
|
||||
@@ -193,9 +196,9 @@ void CowData<T>::_unref(void *p_data) {
|
||||
if (!p_data)
|
||||
return;
|
||||
|
||||
uint32_t *refc = _get_refcount();
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
|
||||
if (atomic_decrement(refc) > 0)
|
||||
if (refc->decrement() > 0)
|
||||
return; // still in use
|
||||
// clean up
|
||||
|
||||
@@ -219,15 +222,15 @@ void CowData<T>::_copy_on_write() {
|
||||
if (!_ptr)
|
||||
return;
|
||||
|
||||
uint32_t *refc = _get_refcount();
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
|
||||
if (unlikely(*refc > 1)) {
|
||||
if (unlikely(refc->get() > 1)) {
|
||||
/* in use by more than me */
|
||||
uint32_t current_size = *_get_size();
|
||||
|
||||
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
|
||||
|
||||
*(mem_new - 2) = 1; //refcount
|
||||
reinterpret_cast<SafeNumeric<uint32_t> *>(mem_new - 2)->set(1); //refcount
|
||||
*(mem_new - 1) = current_size; //size
|
||||
|
||||
T *_data = (T *)(mem_new);
|
||||
@@ -279,7 +282,7 @@ Error CowData<T>::resize(int p_size) {
|
||||
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
|
||||
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
|
||||
*(ptr - 1) = 0; //size, currently none
|
||||
*(ptr - 2) = 1; //refcount
|
||||
reinterpret_cast<SafeNumeric<uint32_t> *>(ptr - 2)->set(1); //refcount
|
||||
|
||||
_ptr = (T *)ptr;
|
||||
|
||||
@@ -360,7 +363,7 @@ void CowData<T>::_ref(const CowData &p_from) {
|
||||
if (!p_from._ptr)
|
||||
return; //nothing to do
|
||||
|
||||
if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference
|
||||
if (p_from._get_refcount()->increment() > 0) { // could reference
|
||||
_ptr = p_from._ptr;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-6
@@ -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(); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
|
||||
void FileAccessNetworkClient::lock_mutex() {
|
||||
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
lockcount++;
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::unlock_mutex() {
|
||||
|
||||
lockcount--;
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void FileAccessNetworkClient::put_32(int p_32) {
|
||||
@@ -88,16 +88,14 @@ void FileAccessNetworkClient::_thread_func() {
|
||||
while (!quit) {
|
||||
|
||||
DEBUG_PRINT("SEM WAIT - " + itos(sem->get()));
|
||||
Error err = sem->wait();
|
||||
if (err != OK)
|
||||
ERR_PRINT("sem->wait() failed");
|
||||
sem.wait();
|
||||
DEBUG_TIME("sem_unlock");
|
||||
//DEBUG_PRINT("semwait returned "+itos(werr));
|
||||
DEBUG_PRINT("MUTEX LOCK " + itos(lockcount));
|
||||
lock_mutex();
|
||||
DEBUG_PRINT("MUTEX PASS");
|
||||
|
||||
blockrequest_mutex->lock();
|
||||
blockrequest_mutex.lock();
|
||||
while (block_requests.size()) {
|
||||
put_32(block_requests.front()->get().id);
|
||||
put_32(FileAccessNetwork::COMMAND_READ_BLOCK);
|
||||
@@ -105,7 +103,7 @@ void FileAccessNetworkClient::_thread_func() {
|
||||
put_32(block_requests.front()->get().size);
|
||||
block_requests.pop_front();
|
||||
}
|
||||
blockrequest_mutex->unlock();
|
||||
blockrequest_mutex.unlock();
|
||||
|
||||
DEBUG_PRINT("THREAD ITER");
|
||||
|
||||
@@ -140,7 +138,7 @@ void FileAccessNetworkClient::_thread_func() {
|
||||
fa->_respond(len, Error(status));
|
||||
}
|
||||
|
||||
fa->sem->post();
|
||||
fa->sem.post();
|
||||
|
||||
} break;
|
||||
case FileAccessNetwork::RESPONSE_DATA: {
|
||||
@@ -160,14 +158,14 @@ void FileAccessNetworkClient::_thread_func() {
|
||||
|
||||
int status = get_32();
|
||||
fa->exists_modtime = status != 0;
|
||||
fa->sem->post();
|
||||
fa->sem.post();
|
||||
|
||||
} break;
|
||||
case FileAccessNetwork::RESPONSE_GET_MODTIME: {
|
||||
|
||||
uint64_t status = get_64();
|
||||
fa->exists_modtime = status;
|
||||
fa->sem->post();
|
||||
fa->sem.post();
|
||||
|
||||
} break;
|
||||
}
|
||||
@@ -215,7 +213,7 @@ Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const S
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
thread = Thread::create(_thread_func, this);
|
||||
thread.start(_thread_func, this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -224,29 +222,20 @@ FileAccessNetworkClient *FileAccessNetworkClient::singleton = NULL;
|
||||
|
||||
FileAccessNetworkClient::FileAccessNetworkClient() {
|
||||
|
||||
thread = NULL;
|
||||
mutex = Mutex::create();
|
||||
blockrequest_mutex = Mutex::create();
|
||||
quit = false;
|
||||
singleton = this;
|
||||
last_id = 0;
|
||||
client.instance();
|
||||
sem = Semaphore::create();
|
||||
lockcount = 0;
|
||||
}
|
||||
|
||||
FileAccessNetworkClient::~FileAccessNetworkClient() {
|
||||
|
||||
if (thread) {
|
||||
if (thread.is_started()) {
|
||||
quit = true;
|
||||
sem->post();
|
||||
Thread::wait_to_finish(thread);
|
||||
memdelete(thread);
|
||||
sem.post();
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
|
||||
memdelete(blockrequest_mutex);
|
||||
memdelete(mutex);
|
||||
memdelete(sem);
|
||||
}
|
||||
|
||||
void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) {
|
||||
@@ -259,14 +248,14 @@ void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block)
|
||||
ERR_FAIL_COND((p_block.size() != (int)(total_size % page_size)));
|
||||
}
|
||||
|
||||
buffer_mutex->lock();
|
||||
buffer_mutex.lock();
|
||||
pages.write[page].buffer = p_block;
|
||||
pages.write[page].queued = false;
|
||||
buffer_mutex->unlock();
|
||||
buffer_mutex.unlock();
|
||||
|
||||
if (waiting_on_page == page) {
|
||||
waiting_on_page = -1;
|
||||
page_sem->post();
|
||||
page_sem.post();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,9 +297,9 @@ Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
|
||||
nc->unlock_mutex();
|
||||
DEBUG_PRINT("OPEN POST");
|
||||
DEBUG_TIME("open_post");
|
||||
nc->sem->post(); //awaiting answer
|
||||
nc->sem.post(); //awaiting answer
|
||||
DEBUG_PRINT("WAIT...");
|
||||
sem->wait();
|
||||
sem.wait();
|
||||
DEBUG_TIME("open_end");
|
||||
DEBUG_PRINT("WAIT ENDED...");
|
||||
|
||||
@@ -385,16 +374,16 @@ void FileAccessNetwork::_queue_page(int p_page) const {
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
|
||||
nc->blockrequest_mutex->lock();
|
||||
nc->blockrequest_mutex.lock();
|
||||
FileAccessNetworkClient::BlockRequest br;
|
||||
br.id = id;
|
||||
br.offset = size_t(p_page) * page_size;
|
||||
br.size = page_size;
|
||||
nc->block_requests.push_back(br);
|
||||
pages.write[p_page].queued = true;
|
||||
nc->blockrequest_mutex->unlock();
|
||||
nc->blockrequest_mutex.unlock();
|
||||
DEBUG_PRINT("QUEUE PAGE POST");
|
||||
nc->sem->post();
|
||||
nc->sem.post();
|
||||
DEBUG_PRINT("queued " + itos(p_page));
|
||||
}
|
||||
}
|
||||
@@ -418,16 +407,16 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
|
||||
int page = pos / page_size;
|
||||
|
||||
if (page != last_page) {
|
||||
buffer_mutex->lock();
|
||||
buffer_mutex.lock();
|
||||
if (pages[page].buffer.empty()) {
|
||||
waiting_on_page = page;
|
||||
for (int j = 0; j < read_ahead; j++) {
|
||||
|
||||
_queue_page(page + j);
|
||||
}
|
||||
buffer_mutex->unlock();
|
||||
buffer_mutex.unlock();
|
||||
DEBUG_PRINT("wait");
|
||||
page_sem->wait();
|
||||
page_sem.wait();
|
||||
DEBUG_PRINT("done");
|
||||
} else {
|
||||
|
||||
@@ -436,7 +425,7 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
|
||||
_queue_page(page + j);
|
||||
}
|
||||
//queue pages
|
||||
buffer_mutex->unlock();
|
||||
buffer_mutex.unlock();
|
||||
}
|
||||
|
||||
buff = pages.write[page].buffer.ptrw();
|
||||
@@ -476,8 +465,8 @@ bool FileAccessNetwork::file_exists(const String &p_path) {
|
||||
nc->client->put_data((const uint8_t *)cs.ptr(), cs.length());
|
||||
nc->unlock_mutex();
|
||||
DEBUG_PRINT("FILE EXISTS POST");
|
||||
nc->sem->post();
|
||||
sem->wait();
|
||||
nc->sem.post();
|
||||
sem.wait();
|
||||
|
||||
return exists_modtime != 0;
|
||||
}
|
||||
@@ -493,8 +482,8 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
|
||||
nc->client->put_data((const uint8_t *)cs.ptr(), cs.length());
|
||||
nc->unlock_mutex();
|
||||
DEBUG_PRINT("MODTIME POST");
|
||||
nc->sem->post();
|
||||
sem->wait();
|
||||
nc->sem.post();
|
||||
sem.wait();
|
||||
|
||||
return exists_modtime;
|
||||
}
|
||||
@@ -522,9 +511,6 @@ FileAccessNetwork::FileAccessNetwork() {
|
||||
eof_flag = false;
|
||||
opened = false;
|
||||
pos = 0;
|
||||
sem = Semaphore::create();
|
||||
page_sem = Semaphore::create();
|
||||
buffer_mutex = Mutex::create();
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
nc->lock_mutex();
|
||||
id = nc->last_id++;
|
||||
@@ -540,9 +526,6 @@ FileAccessNetwork::FileAccessNetwork() {
|
||||
FileAccessNetwork::~FileAccessNetwork() {
|
||||
|
||||
close();
|
||||
memdelete(sem);
|
||||
memdelete(page_sem);
|
||||
memdelete(buffer_mutex);
|
||||
|
||||
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
|
||||
nc->lock_mutex();
|
||||
|
||||
@@ -49,11 +49,11 @@ class FileAccessNetworkClient {
|
||||
|
||||
List<BlockRequest> block_requests;
|
||||
|
||||
Semaphore *sem;
|
||||
Thread *thread;
|
||||
Semaphore sem;
|
||||
Thread thread;
|
||||
bool quit;
|
||||
Mutex *mutex;
|
||||
Mutex *blockrequest_mutex;
|
||||
Mutex mutex;
|
||||
Mutex blockrequest_mutex;
|
||||
Map<int, FileAccessNetwork *> accesses;
|
||||
Ref<StreamPeerTCP> client;
|
||||
int last_id;
|
||||
@@ -85,9 +85,9 @@ public:
|
||||
|
||||
class FileAccessNetwork : public FileAccess {
|
||||
|
||||
Semaphore *sem;
|
||||
Semaphore *page_sem;
|
||||
Mutex *buffer_mutex;
|
||||
Semaphore sem;
|
||||
Semaphore page_sem;
|
||||
Mutex buffer_mutex;
|
||||
bool opened;
|
||||
size_t total_size;
|
||||
mutable size_t pos;
|
||||
|
||||
+41
-66
@@ -42,13 +42,13 @@ struct _IP_ResolverPrivate {
|
||||
|
||||
struct QueueItem {
|
||||
|
||||
volatile IP::ResolverStatus status;
|
||||
SafeNumeric<IP::ResolverStatus> status;
|
||||
IP_Address response;
|
||||
String hostname;
|
||||
IP::Type type;
|
||||
|
||||
void clear() {
|
||||
status = IP::RESOLVER_STATUS_NONE;
|
||||
status.set(IP::RESOLVER_STATUS_NONE);
|
||||
response = IP_Address();
|
||||
type = IP::TYPE_NONE;
|
||||
hostname = "";
|
||||
@@ -64,16 +64,16 @@ struct _IP_ResolverPrivate {
|
||||
IP::ResolverID find_empty_id() const {
|
||||
|
||||
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
|
||||
if (queue[i].status == IP::RESOLVER_STATUS_NONE)
|
||||
if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE)
|
||||
return i;
|
||||
}
|
||||
return IP::RESOLVER_INVALID_ID;
|
||||
}
|
||||
|
||||
Mutex *mutex;
|
||||
Semaphore *sem;
|
||||
Mutex mutex;
|
||||
Semaphore sem;
|
||||
|
||||
Thread *thread;
|
||||
Thread thread;
|
||||
//Semaphore* semaphore;
|
||||
bool thread_abort;
|
||||
|
||||
@@ -81,14 +81,14 @@ struct _IP_ResolverPrivate {
|
||||
|
||||
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
|
||||
|
||||
if (queue[i].status != IP::RESOLVER_STATUS_WAITING)
|
||||
if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING)
|
||||
continue;
|
||||
queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
|
||||
|
||||
if (!queue[i].response.is_valid())
|
||||
queue[i].status = IP::RESOLVER_STATUS_ERROR;
|
||||
queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
|
||||
else
|
||||
queue[i].status = IP::RESOLVER_STATUS_DONE;
|
||||
queue[i].status.set(IP::RESOLVER_STATUS_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,11 +98,11 @@ struct _IP_ResolverPrivate {
|
||||
|
||||
while (!ipr->thread_abort) {
|
||||
|
||||
ipr->sem->wait();
|
||||
ipr->sem.wait();
|
||||
|
||||
ipr->mutex->lock();
|
||||
ipr->mutex.lock();
|
||||
ipr->resolve_queues();
|
||||
ipr->mutex->unlock();
|
||||
ipr->mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,30 +115,30 @@ struct _IP_ResolverPrivate {
|
||||
|
||||
IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
|
||||
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
|
||||
IP_Address res = resolver->cache[key];
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
IP_Address res = _resolve_hostname(p_hostname, p_type);
|
||||
resolver->cache[key] = res;
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Type p_type) {
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
ResolverID id = resolver->find_empty_id();
|
||||
|
||||
if (id == RESOLVER_INVALID_ID) {
|
||||
WARN_PRINT("Out of resolver queries");
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -147,17 +147,17 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
|
||||
resolver->queue[id].type = p_type;
|
||||
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
|
||||
resolver->queue[id].response = resolver->cache[key];
|
||||
resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
|
||||
resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
|
||||
} else {
|
||||
resolver->queue[id].response = IP_Address();
|
||||
resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
|
||||
if (resolver->thread)
|
||||
resolver->sem->post();
|
||||
resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
|
||||
if (resolver->thread.is_started())
|
||||
resolver->sem.post();
|
||||
else
|
||||
resolver->resolve_queues();
|
||||
}
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -165,15 +165,15 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP::RESOLVER_STATUS_NONE);
|
||||
|
||||
resolver->mutex->lock();
|
||||
if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) {
|
||||
resolver->mutex.lock();
|
||||
if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
|
||||
ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return IP::RESOLVER_STATUS_NONE;
|
||||
}
|
||||
IP::ResolverStatus res = resolver->queue[p_id].status;
|
||||
IP::ResolverStatus res = resolver->queue[p_id].status.get();
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -181,17 +181,17 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP_Address());
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
|
||||
if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
|
||||
ERR_PRINTS("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return IP_Address();
|
||||
}
|
||||
|
||||
IP_Address res = resolver->queue[p_id].response;
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -199,16 +199,16 @@ void IP::erase_resolve_item(ResolverID p_id) {
|
||||
|
||||
ERR_FAIL_INDEX(p_id, IP::RESOLVER_MAX_QUERIES);
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE;
|
||||
resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
}
|
||||
|
||||
void IP::clear_cache(const String &p_hostname) {
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
if (p_hostname.empty()) {
|
||||
resolver->cache.clear();
|
||||
@@ -219,7 +219,7 @@ void IP::clear_cache(const String &p_hostname) {
|
||||
resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_ANY));
|
||||
}
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
}
|
||||
|
||||
Array IP::_get_local_addresses() const {
|
||||
@@ -314,41 +314,16 @@ IP::IP() {
|
||||
|
||||
singleton = this;
|
||||
resolver = memnew(_IP_ResolverPrivate);
|
||||
resolver->sem = NULL;
|
||||
resolver->mutex = Mutex::create();
|
||||
|
||||
#ifndef NO_THREADS
|
||||
|
||||
resolver->sem = Semaphore::create();
|
||||
if (resolver->sem) {
|
||||
resolver->thread_abort = false;
|
||||
|
||||
resolver->thread = Thread::create(_IP_ResolverPrivate::_thread_function, resolver);
|
||||
|
||||
if (!resolver->thread)
|
||||
memdelete(resolver->sem); //wtf
|
||||
} else {
|
||||
resolver->thread = NULL;
|
||||
}
|
||||
#else
|
||||
resolver->sem = NULL;
|
||||
resolver->thread = NULL;
|
||||
#endif
|
||||
resolver->thread_abort = false;
|
||||
resolver->thread.start(_IP_ResolverPrivate::_thread_function, resolver);
|
||||
}
|
||||
|
||||
IP::~IP() {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
if (resolver->thread) {
|
||||
resolver->thread_abort = true;
|
||||
resolver->sem->post();
|
||||
Thread::wait_to_finish(resolver->thread);
|
||||
memdelete(resolver->thread);
|
||||
memdelete(resolver->sem);
|
||||
}
|
||||
resolver->thread_abort = true;
|
||||
resolver->sem.post();
|
||||
resolver->thread.wait_to_finish();
|
||||
|
||||
#endif
|
||||
|
||||
memdelete(resolver->mutex);
|
||||
memdelete(resolver);
|
||||
}
|
||||
|
||||
+12
-42
@@ -289,9 +289,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
|
||||
bool ResourceLoader::_add_to_loading_map(const String &p_path) {
|
||||
|
||||
bool success;
|
||||
if (loading_map_mutex) {
|
||||
loading_map_mutex->lock();
|
||||
}
|
||||
loading_map_mutex.lock();
|
||||
|
||||
LoadingMapKey key;
|
||||
key.path = p_path;
|
||||
@@ -304,17 +302,13 @@ bool ResourceLoader::_add_to_loading_map(const String &p_path) {
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (loading_map_mutex) {
|
||||
loading_map_mutex->unlock();
|
||||
}
|
||||
loading_map_mutex.unlock();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void ResourceLoader::_remove_from_loading_map(const String &p_path) {
|
||||
if (loading_map_mutex) {
|
||||
loading_map_mutex->lock();
|
||||
}
|
||||
loading_map_mutex.lock();
|
||||
|
||||
LoadingMapKey key;
|
||||
key.path = p_path;
|
||||
@@ -322,15 +316,11 @@ void ResourceLoader::_remove_from_loading_map(const String &p_path) {
|
||||
|
||||
loading_map.erase(key);
|
||||
|
||||
if (loading_map_mutex) {
|
||||
loading_map_mutex->unlock();
|
||||
}
|
||||
loading_map_mutex.unlock();
|
||||
}
|
||||
|
||||
void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread) {
|
||||
if (loading_map_mutex) {
|
||||
loading_map_mutex->lock();
|
||||
}
|
||||
loading_map_mutex.lock();
|
||||
|
||||
LoadingMapKey key;
|
||||
key.path = p_path;
|
||||
@@ -338,9 +328,7 @@ void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, T
|
||||
|
||||
loading_map.erase(key);
|
||||
|
||||
if (loading_map_mutex) {
|
||||
loading_map_mutex->unlock();
|
||||
}
|
||||
loading_map_mutex.unlock();
|
||||
}
|
||||
|
||||
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
|
||||
@@ -362,9 +350,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
|
||||
}
|
||||
|
||||
//lock first if possible
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->read_lock();
|
||||
}
|
||||
ResourceCache::lock.read_lock();
|
||||
|
||||
//get ptr
|
||||
Resource **rptr = ResourceCache::resources.getptr(local_path);
|
||||
@@ -376,16 +362,12 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
|
||||
//referencing is fine
|
||||
if (r_error)
|
||||
*r_error = OK;
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->read_unlock();
|
||||
}
|
||||
ResourceCache::lock.read_unlock();
|
||||
_remove_from_loading_map(local_path);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->read_unlock();
|
||||
}
|
||||
ResourceCache::lock.read_unlock();
|
||||
}
|
||||
|
||||
bool xl_remapped = false;
|
||||
@@ -851,9 +833,7 @@ String ResourceLoader::path_remap(const String &p_path) {
|
||||
|
||||
void ResourceLoader::reload_translation_remaps() {
|
||||
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->read_lock();
|
||||
}
|
||||
ResourceCache::lock.read_lock();
|
||||
|
||||
List<Resource *> to_reload;
|
||||
SelfList<Resource> *E = remapped_list.first();
|
||||
@@ -863,9 +843,7 @@ void ResourceLoader::reload_translation_remaps() {
|
||||
E = E->next();
|
||||
}
|
||||
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->read_unlock();
|
||||
}
|
||||
ResourceCache::lock.read_unlock();
|
||||
|
||||
//now just make sure to not delete any of these resources while changing locale..
|
||||
while (to_reload.front()) {
|
||||
@@ -1004,15 +982,9 @@ void ResourceLoader::remove_custom_loaders() {
|
||||
}
|
||||
}
|
||||
|
||||
Mutex *ResourceLoader::loading_map_mutex = NULL;
|
||||
Mutex ResourceLoader::loading_map_mutex;
|
||||
HashMap<ResourceLoader::LoadingMapKey, int, ResourceLoader::LoadingMapKeyHasher> ResourceLoader::loading_map;
|
||||
|
||||
void ResourceLoader::initialize() {
|
||||
#ifndef NO_THREADS
|
||||
loading_map_mutex = Mutex::create();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ResourceLoader::finalize() {
|
||||
#ifndef NO_THREADS
|
||||
const LoadingMapKey *K = NULL;
|
||||
@@ -1020,8 +992,6 @@ void ResourceLoader::finalize() {
|
||||
ERR_PRINTS("Exited while resource is being loaded: " + K->path);
|
||||
}
|
||||
loading_map.clear();
|
||||
memdelete(loading_map_mutex);
|
||||
loading_map_mutex = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ class ResourceLoader {
|
||||
static ResourceLoadedCallback _loaded_callback;
|
||||
|
||||
static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path);
|
||||
static Mutex *loading_map_mutex;
|
||||
static Mutex loading_map_mutex;
|
||||
|
||||
//used to track paths being loaded in a thread, avoids cyclic recursion
|
||||
struct LoadingMapKey {
|
||||
@@ -197,7 +197,6 @@ public:
|
||||
static void add_custom_loaders();
|
||||
static void remove_custom_loaders();
|
||||
|
||||
static void initialize();
|
||||
static void finalize();
|
||||
};
|
||||
|
||||
|
||||
+14
-21
@@ -1946,7 +1946,7 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
|
||||
if (!_script_instance_bindings[p_script_language_index]) {
|
||||
void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
|
||||
if (script_data) {
|
||||
atomic_increment(&instance_binding_count);
|
||||
instance_binding_count.increment();
|
||||
_script_instance_bindings[p_script_language_index] = script_data;
|
||||
}
|
||||
}
|
||||
@@ -1976,7 +1976,6 @@ Object::Object() {
|
||||
_can_translate = true;
|
||||
_is_queued_for_deletion = false;
|
||||
_emitting = false;
|
||||
instance_binding_count = 0;
|
||||
memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
|
||||
script_instance = NULL;
|
||||
#ifdef DEBUG_ENABLED
|
||||
@@ -2068,30 +2067,30 @@ ObjectID ObjectDB::add_instance(Object *p_object) {
|
||||
|
||||
ERR_FAIL_COND_V(p_object->get_instance_id() != 0, 0);
|
||||
|
||||
rw_lock->write_lock();
|
||||
rw_lock.write_lock();
|
||||
ObjectID instance_id = ++instance_counter;
|
||||
instances[instance_id] = p_object;
|
||||
instance_checks[p_object] = instance_id;
|
||||
|
||||
rw_lock->write_unlock();
|
||||
rw_lock.write_unlock();
|
||||
|
||||
return instance_id;
|
||||
}
|
||||
|
||||
void ObjectDB::remove_instance(Object *p_object) {
|
||||
|
||||
rw_lock->write_lock();
|
||||
rw_lock.write_lock();
|
||||
|
||||
instances.erase(p_object->get_instance_id());
|
||||
instance_checks.erase(p_object);
|
||||
|
||||
rw_lock->write_unlock();
|
||||
rw_lock.write_unlock();
|
||||
}
|
||||
Object *ObjectDB::get_instance(ObjectID p_instance_id) {
|
||||
|
||||
rw_lock->read_lock();
|
||||
rw_lock.read_lock();
|
||||
Object **obj = instances.getptr(p_instance_id);
|
||||
rw_lock->read_unlock();
|
||||
rw_lock.read_unlock();
|
||||
|
||||
if (!obj)
|
||||
return NULL;
|
||||
@@ -2100,7 +2099,7 @@ Object *ObjectDB::get_instance(ObjectID p_instance_id) {
|
||||
|
||||
void ObjectDB::debug_objects(DebugFunc p_func) {
|
||||
|
||||
rw_lock->read_lock();
|
||||
rw_lock.read_lock();
|
||||
|
||||
const ObjectID *K = NULL;
|
||||
while ((K = instances.next(K))) {
|
||||
@@ -2108,7 +2107,7 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
|
||||
p_func(instances[*K]);
|
||||
}
|
||||
|
||||
rw_lock->read_unlock();
|
||||
rw_lock.read_unlock();
|
||||
}
|
||||
|
||||
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
|
||||
@@ -2116,23 +2115,18 @@ void Object::get_argument_options(const StringName &p_function, int p_idx, List<
|
||||
|
||||
int ObjectDB::get_object_count() {
|
||||
|
||||
rw_lock->read_lock();
|
||||
rw_lock.read_lock();
|
||||
int count = instances.size();
|
||||
rw_lock->read_unlock();
|
||||
rw_lock.read_unlock();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
RWLock *ObjectDB::rw_lock = NULL;
|
||||
|
||||
void ObjectDB::setup() {
|
||||
|
||||
rw_lock = RWLock::create();
|
||||
}
|
||||
RWLock ObjectDB::rw_lock;
|
||||
|
||||
void ObjectDB::cleanup() {
|
||||
|
||||
rw_lock->write_lock();
|
||||
rw_lock.write_lock();
|
||||
if (instances.size()) {
|
||||
|
||||
WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
|
||||
@@ -2159,6 +2153,5 @@ void ObjectDB::cleanup() {
|
||||
}
|
||||
instances.clear();
|
||||
instance_checks.clear();
|
||||
rw_lock->write_unlock();
|
||||
memdelete(rw_lock);
|
||||
rw_lock.write_unlock();
|
||||
}
|
||||
|
||||
+5
-5
@@ -36,6 +36,7 @@
|
||||
#include "core/map.h"
|
||||
#include "core/object_id.h"
|
||||
#include "core/os/rw_lock.h"
|
||||
#include "core/safe_refcount.h"
|
||||
#include "core/set.h"
|
||||
#include "core/variant.h"
|
||||
#include "core/vmap.h"
|
||||
@@ -512,7 +513,7 @@ private:
|
||||
Variant _get_indexed_bind(const NodePath &p_name) const;
|
||||
|
||||
friend class Reference;
|
||||
uint32_t instance_binding_count;
|
||||
SafeNumeric<uint32_t> instance_binding_count;
|
||||
void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
|
||||
|
||||
protected:
|
||||
@@ -791,12 +792,11 @@ class ObjectDB {
|
||||
friend class Object;
|
||||
friend void unregister_core_types();
|
||||
|
||||
static RWLock *rw_lock;
|
||||
static RWLock rw_lock;
|
||||
static void cleanup();
|
||||
static ObjectID add_instance(Object *p_object);
|
||||
static void remove_instance(Object *p_object);
|
||||
friend void register_core_types();
|
||||
static void setup();
|
||||
|
||||
public:
|
||||
typedef void (*DebugFunc)(Object *p_obj);
|
||||
@@ -806,11 +806,11 @@ public:
|
||||
static int get_object_count();
|
||||
|
||||
_FORCE_INLINE_ static bool instance_validate(Object *p_ptr) {
|
||||
rw_lock->read_lock();
|
||||
rw_lock.read_lock();
|
||||
|
||||
bool exists = instance_checks.has(p_ptr);
|
||||
|
||||
rw_lock->read_unlock();
|
||||
rw_lock.read_unlock();
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
+13
-13
@@ -65,11 +65,11 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t Memory::mem_usage = 0;
|
||||
uint64_t Memory::max_usage = 0;
|
||||
SafeNumeric<uint64_t> Memory::mem_usage;
|
||||
SafeNumeric<uint64_t> Memory::max_usage;
|
||||
#endif
|
||||
|
||||
uint64_t Memory::alloc_count = 0;
|
||||
SafeNumeric<uint64_t> Memory::alloc_count;
|
||||
|
||||
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
||||
|
||||
@@ -83,7 +83,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
||||
|
||||
ERR_FAIL_COND_V(!mem, NULL);
|
||||
|
||||
atomic_increment(&alloc_count);
|
||||
alloc_count.increment();
|
||||
|
||||
if (prepad) {
|
||||
uint64_t *s = (uint64_t *)mem;
|
||||
@@ -92,8 +92,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
||||
uint8_t *s8 = (uint8_t *)mem;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
atomic_add(&mem_usage, p_bytes);
|
||||
atomic_exchange_if_greater(&max_usage, mem_usage);
|
||||
uint64_t new_mem_usage = mem_usage.add(p_bytes);
|
||||
max_usage.exchange_if_greater(new_mem_usage);
|
||||
#endif
|
||||
return s8 + PAD_ALIGN;
|
||||
} else {
|
||||
@@ -121,10 +121,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (p_bytes > *s) {
|
||||
atomic_add(&mem_usage, p_bytes - *s);
|
||||
atomic_exchange_if_greater(&max_usage, mem_usage);
|
||||
uint64_t new_mem_usage = mem_usage.add(p_bytes - *s);
|
||||
max_usage.exchange_if_greater(new_mem_usage);
|
||||
} else {
|
||||
atomic_sub(&mem_usage, *s - p_bytes);
|
||||
mem_usage.sub(*s - p_bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -165,14 +165,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
|
||||
bool prepad = p_pad_align;
|
||||
#endif
|
||||
|
||||
atomic_decrement(&alloc_count);
|
||||
alloc_count.decrement();
|
||||
|
||||
if (prepad) {
|
||||
mem -= PAD_ALIGN;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint64_t *s = (uint64_t *)mem;
|
||||
atomic_sub(&mem_usage, *s);
|
||||
mem_usage.sub(*s);
|
||||
#endif
|
||||
|
||||
free(mem);
|
||||
@@ -189,7 +189,7 @@ uint64_t Memory::get_mem_available() {
|
||||
|
||||
uint64_t Memory::get_mem_usage() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
return mem_usage;
|
||||
return mem_usage.get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
@@ -197,7 +197,7 @@ uint64_t Memory::get_mem_usage() {
|
||||
|
||||
uint64_t Memory::get_mem_max_usage() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
return max_usage;
|
||||
return max_usage.get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -44,11 +44,11 @@ class Memory {
|
||||
|
||||
Memory();
|
||||
#ifdef DEBUG_ENABLED
|
||||
static uint64_t mem_usage;
|
||||
static uint64_t max_usage;
|
||||
static SafeNumeric<uint64_t> mem_usage;
|
||||
static SafeNumeric<uint64_t> max_usage;
|
||||
#endif
|
||||
|
||||
static uint64_t alloc_count;
|
||||
static SafeNumeric<uint64_t> alloc_count;
|
||||
|
||||
public:
|
||||
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
|
||||
|
||||
+11
-23
@@ -30,31 +30,19 @@
|
||||
|
||||
#include "mutex.h"
|
||||
|
||||
#include "core/error_macros.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
Mutex *(*Mutex::create_func)(bool) = 0;
|
||||
|
||||
Mutex *Mutex::create(bool p_recursive) {
|
||||
|
||||
ERR_FAIL_COND_V(!create_func, 0);
|
||||
|
||||
return create_func(p_recursive);
|
||||
}
|
||||
|
||||
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<std::recursive_mutex>;
|
||||
template class MutexImpl<std::mutex>;
|
||||
|
||||
#endif
|
||||
|
||||
+74
-27
@@ -32,42 +32,89 @@
|
||||
#define MUTEX_H
|
||||
|
||||
#include "core/error_list.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
/**
|
||||
* @class Mutex
|
||||
* @author Juan Linietsky
|
||||
* Portable Mutex (thread-safe locking) implementation.
|
||||
* Mutexes are always recursive ( they don't self-lock in a single thread ).
|
||||
* Mutexes can be used with a Lockp object like this, to avoid having to worry about unlocking:
|
||||
* Lockp( mutex );
|
||||
*/
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
class Mutex {
|
||||
protected:
|
||||
static Mutex *(*create_func)(bool);
|
||||
#include <mutex>
|
||||
|
||||
template <class StdMutexT>
|
||||
class MutexImpl {
|
||||
mutable StdMutexT mutex;
|
||||
friend class MutexLock;
|
||||
|
||||
public:
|
||||
virtual void lock() = 0; ///< Lock the mutex, block if locked by someone else
|
||||
virtual void unlock() = 0; ///< Unlock the mutex, let other threads continue
|
||||
virtual Error try_lock() = 0; ///< Attempt to lock the mutex, OK on success, ERROR means it can't lock.
|
||||
_ALWAYS_INLINE_ void lock() const {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
static Mutex *create(bool p_recursive = true); ///< Create a mutex
|
||||
_ALWAYS_INLINE_ void unlock() const {
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
virtual ~Mutex();
|
||||
_ALWAYS_INLINE_ Error try_lock() const {
|
||||
return mutex.try_lock() ? OK : ERR_BUSY;
|
||||
}
|
||||
};
|
||||
|
||||
// This is written this way instead of being a template to overcome a limitation of C++ pre-17
|
||||
// that would require MutexLock to be used like this: MutexLock<Mutex> lock;
|
||||
class MutexLock {
|
||||
union {
|
||||
std::recursive_mutex *recursive_mutex;
|
||||
std::mutex *mutex;
|
||||
};
|
||||
bool recursive;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ explicit MutexLock(const MutexImpl<std::recursive_mutex> &p_mutex) :
|
||||
recursive_mutex(&p_mutex.mutex),
|
||||
recursive(true) {
|
||||
recursive_mutex->lock();
|
||||
}
|
||||
_ALWAYS_INLINE_ explicit MutexLock(const MutexImpl<std::mutex> &p_mutex) :
|
||||
mutex(&p_mutex.mutex),
|
||||
recursive(false) {
|
||||
mutex->lock();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ ~MutexLock() {
|
||||
if (recursive) {
|
||||
recursive_mutex->unlock();
|
||||
} else {
|
||||
mutex->unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using Mutex = MutexImpl<std::recursive_mutex>; // Recursive, for general use
|
||||
using BinaryMutex = MutexImpl<std::mutex>; // Non-recursive, handle with care
|
||||
|
||||
extern template class MutexImpl<std::recursive_mutex>;
|
||||
extern template class MutexImpl<std::mutex>;
|
||||
|
||||
#else
|
||||
|
||||
class FakeMutex {
|
||||
FakeMutex() {}
|
||||
};
|
||||
|
||||
template <class MutexT>
|
||||
class MutexImpl {
|
||||
public:
|
||||
_ALWAYS_INLINE_ void lock() const {}
|
||||
_ALWAYS_INLINE_ void unlock() const {}
|
||||
_ALWAYS_INLINE_ Error try_lock() const { return OK; }
|
||||
};
|
||||
|
||||
class MutexLock {
|
||||
|
||||
Mutex *mutex;
|
||||
|
||||
public:
|
||||
MutexLock(Mutex *p_mutex) {
|
||||
mutex = p_mutex;
|
||||
if (mutex) mutex->lock();
|
||||
}
|
||||
~MutexLock() {
|
||||
if (mutex) mutex->unlock();
|
||||
}
|
||||
explicit MutexLock(const MutexImpl<FakeMutex> &p_mutex) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
using Mutex = MutexImpl<FakeMutex>;
|
||||
using BinaryMutex = MutexImpl<FakeMutex>; // Non-recursive, handle with care
|
||||
|
||||
#endif // !NO_THREADS
|
||||
|
||||
#endif // MUTEX_H
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
class Mutex;
|
||||
|
||||
class OS {
|
||||
|
||||
static OS *singleton;
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* rw_lock.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "rw_lock.h"
|
||||
|
||||
#include "core/error_macros.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
RWLock *(*RWLock::create_func)() = 0;
|
||||
|
||||
RWLock *RWLock::create() {
|
||||
|
||||
ERR_FAIL_COND_V(!create_func, 0);
|
||||
|
||||
return create_func();
|
||||
}
|
||||
|
||||
RWLock::~RWLock() {
|
||||
}
|
||||
+56
-20
@@ -33,49 +33,85 @@
|
||||
|
||||
#include "core/error_list.h"
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
class RWLock {
|
||||
protected:
|
||||
static RWLock *(*create_func)();
|
||||
mutable std::shared_timed_mutex mutex;
|
||||
|
||||
public:
|
||||
virtual void read_lock() = 0; ///< Lock the rwlock, block if locked by someone else
|
||||
virtual void read_unlock() = 0; ///< Unlock the rwlock, let other threads continue
|
||||
virtual Error read_try_lock() = 0; ///< Attempt to lock the rwlock, OK on success, ERROR means it can't lock.
|
||||
// Lock the rwlock, block if locked by someone else
|
||||
void read_lock() const {
|
||||
mutex.lock_shared();
|
||||
}
|
||||
|
||||
virtual void write_lock() = 0; ///< Lock the rwlock, block if locked by someone else
|
||||
virtual void write_unlock() = 0; ///< Unlock the rwlock, let other thwrites continue
|
||||
virtual Error write_try_lock() = 0; ///< Attempt to lock the rwlock, OK on success, ERROR means it can't lock.
|
||||
// Unlock the rwlock, let other threads continue
|
||||
void read_unlock() const {
|
||||
mutex.unlock_shared();
|
||||
}
|
||||
|
||||
static RWLock *create(); ///< Create a rwlock
|
||||
// Attempt to lock the rwlock, OK on success, ERR_BUSY means it can't lock.
|
||||
Error read_try_lock() const {
|
||||
return mutex.try_lock_shared() ? OK : ERR_BUSY;
|
||||
}
|
||||
|
||||
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<RWLock *>(p_lock);
|
||||
if (lock) lock->read_lock();
|
||||
RWLockRead(const RWLock &p_lock) :
|
||||
lock(p_lock) {
|
||||
lock.read_lock();
|
||||
}
|
||||
~RWLockRead() {
|
||||
if (lock) lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
}
|
||||
};
|
||||
|
||||
class RWLockWrite {
|
||||
|
||||
RWLock *lock;
|
||||
RWLock &lock;
|
||||
|
||||
public:
|
||||
RWLockWrite(RWLock *p_lock) {
|
||||
lock = p_lock;
|
||||
if (lock) lock->write_lock();
|
||||
RWLockWrite(RWLock &p_lock) :
|
||||
lock(p_lock) {
|
||||
lock.write_lock();
|
||||
}
|
||||
~RWLockWrite() {
|
||||
if (lock) lock->write_unlock();
|
||||
lock.write_unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* semaphore.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "semaphore.h"
|
||||
|
||||
#include "core/error_macros.h"
|
||||
|
||||
Semaphore *(*Semaphore::create_func)() = 0;
|
||||
|
||||
Semaphore *Semaphore::create() {
|
||||
|
||||
ERR_FAIL_COND_V(!create_func, 0);
|
||||
|
||||
return create_func();
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore() {
|
||||
}
|
||||
+47
-7
@@ -32,19 +32,59 @@
|
||||
#define SEMAPHORE_H
|
||||
|
||||
#include "core/error_list.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
class Semaphore {
|
||||
protected:
|
||||
static Semaphore *(*create_func)();
|
||||
private:
|
||||
mutable std::mutex mutex_;
|
||||
mutable std::condition_variable condition_;
|
||||
mutable unsigned long count_ = 0; // Initialized as locked.
|
||||
|
||||
public:
|
||||
virtual Error wait() = 0; ///< wait until semaphore has positive value, then decrement and pass
|
||||
virtual Error post() = 0; ///< unlock the semaphore, incrementing the value
|
||||
virtual int get() const = 0; ///< get semaphore value
|
||||
_ALWAYS_INLINE_ void post() const {
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
++count_;
|
||||
condition_.notify_one();
|
||||
}
|
||||
|
||||
static Semaphore *create(); ///< Create a mutex
|
||||
_ALWAYS_INLINE_ void wait() const {
|
||||
std::unique_lock<decltype(mutex_)> lock(mutex_);
|
||||
while (!count_) { // Handle spurious wake-ups.
|
||||
condition_.wait(lock);
|
||||
}
|
||||
--count_;
|
||||
}
|
||||
|
||||
virtual ~Semaphore();
|
||||
_ALWAYS_INLINE_ bool try_wait() const {
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
if (count_) {
|
||||
--count_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ int get() const {
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
return count_;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class Semaphore {
|
||||
public:
|
||||
_ALWAYS_INLINE_ void post() const {}
|
||||
_ALWAYS_INLINE_ void wait() const {}
|
||||
_ALWAYS_INLINE_ bool try_wait() const { return true; }
|
||||
_ALWAYS_INLINE_ int get() const { return 1; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SEMAPHORE_H
|
||||
|
||||
+71
-23
@@ -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::ID> 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
|
||||
|
||||
+58
-21
@@ -32,49 +32,86 @@
|
||||
#define THREAD_H
|
||||
|
||||
#include "core/typedefs.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
typedef void (*ThreadCreateCallback)(void *p_userdata);
|
||||
#if !defined(NO_THREADS)
|
||||
#include "core/safe_refcount.h"
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
class String;
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
enum Priority {
|
||||
typedef void (*Callback)(void *p_userdata);
|
||||
|
||||
typedef uint64_t ID;
|
||||
|
||||
enum Priority {
|
||||
PRIORITY_LOW,
|
||||
PRIORITY_NORMAL,
|
||||
PRIORITY_HIGH
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
|
||||
Priority priority;
|
||||
Settings() { priority = PRIORITY_NORMAL; }
|
||||
};
|
||||
|
||||
typedef uint64_t ID;
|
||||
|
||||
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<ID> 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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -1,49 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* thread_safe.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "thread_safe.h"
|
||||
|
||||
#include "core/error_macros.h"
|
||||
#include "core/os/memory.h"
|
||||
|
||||
ThreadSafe::ThreadSafe() {
|
||||
|
||||
mutex = Mutex::create();
|
||||
if (!mutex) {
|
||||
|
||||
WARN_PRINT("THREAD_SAFE defined, but no default mutex type");
|
||||
}
|
||||
}
|
||||
|
||||
ThreadSafe::~ThreadSafe() {
|
||||
|
||||
if (mutex)
|
||||
memdelete(mutex);
|
||||
}
|
||||
+4
-45
@@ -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
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
template <class C, class U>
|
||||
struct ThreadArrayProcessData {
|
||||
uint32_t elements;
|
||||
uint32_t index;
|
||||
SafeNumeric<uint32_t> index;
|
||||
C *instance;
|
||||
U userdata;
|
||||
void (C::*method)(uint32_t, U);
|
||||
@@ -57,7 +57,7 @@ void process_array_thread(void *ud) {
|
||||
|
||||
T &data = *(T *)ud;
|
||||
while (true) {
|
||||
uint32_t index = atomic_increment(&data.index);
|
||||
uint32_t index = data.index.increment();
|
||||
if (index >= data.elements)
|
||||
break;
|
||||
data.process(index);
|
||||
@@ -71,22 +71,21 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
|
||||
data.method = p_method;
|
||||
data.instance = p_instance;
|
||||
data.userdata = p_userdata;
|
||||
data.index = 0;
|
||||
data.index.set(0);
|
||||
data.elements = p_elements;
|
||||
data.process(data.index); //process first, let threads increment for next
|
||||
data.process(0); //process first, let threads increment for next
|
||||
|
||||
Vector<Thread *> 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<ThreadArrayProcessData<C, U> >, &data);
|
||||
for (int i = 0; i < thread_count; i++) {
|
||||
threads[i].start(process_array_thread<ThreadArrayProcessData<C, U> >, &data);
|
||||
}
|
||||
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
Thread::wait_to_finish(threads[i]);
|
||||
memdelete(threads[i]);
|
||||
for (int i = 0; i < thread_count; i++) {
|
||||
threads[i].wait_to_finish();
|
||||
}
|
||||
memdelete_arr(threads);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "pool_vector.h"
|
||||
|
||||
Mutex *pool_vector_lock = NULL;
|
||||
Mutex pool_vector_lock;
|
||||
|
||||
PoolAllocator *MemoryPool::memory_pool = NULL;
|
||||
uint8_t *MemoryPool::pool_memory = NULL;
|
||||
@@ -40,7 +40,7 @@ MemoryPool::Alloc *MemoryPool::allocs = NULL;
|
||||
MemoryPool::Alloc *MemoryPool::free_list = NULL;
|
||||
uint32_t MemoryPool::alloc_count = 0;
|
||||
uint32_t MemoryPool::allocs_used = 0;
|
||||
Mutex *MemoryPool::alloc_mutex = NULL;
|
||||
Mutex MemoryPool::alloc_mutex;
|
||||
|
||||
size_t MemoryPool::total_memory = 0;
|
||||
size_t MemoryPool::max_memory = 0;
|
||||
@@ -57,14 +57,11 @@ void MemoryPool::setup(uint32_t p_max_allocs) {
|
||||
}
|
||||
|
||||
free_list = &allocs[0];
|
||||
|
||||
alloc_mutex = Mutex::create();
|
||||
}
|
||||
|
||||
void MemoryPool::cleanup() {
|
||||
|
||||
memdelete_arr(allocs);
|
||||
memdelete(alloc_mutex);
|
||||
|
||||
ERR_FAIL_COND_MSG(allocs_used > 0, "There are still MemoryPool allocs in use at exit!");
|
||||
}
|
||||
|
||||
+26
-25
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "core/os/copymem.h"
|
||||
#include "core/os/memory.h"
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/os/rw_lock.h"
|
||||
#include "core/pool_allocator.h"
|
||||
#include "core/safe_refcount.h"
|
||||
@@ -49,7 +50,7 @@ struct MemoryPool {
|
||||
struct Alloc {
|
||||
|
||||
SafeRefCount refcount;
|
||||
uint32_t lock;
|
||||
SafeNumeric<uint32_t> lock;
|
||||
void *mem;
|
||||
PoolAllocator::ID pool_id;
|
||||
size_t size;
|
||||
@@ -69,7 +70,7 @@ struct MemoryPool {
|
||||
static Alloc *free_list;
|
||||
static uint32_t alloc_count;
|
||||
static uint32_t allocs_used;
|
||||
static Mutex *alloc_mutex;
|
||||
static Mutex alloc_mutex;
|
||||
static size_t total_memory;
|
||||
static size_t max_memory;
|
||||
|
||||
@@ -95,9 +96,9 @@ class PoolVector {
|
||||
|
||||
//must allocate something
|
||||
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
if (MemoryPool::allocs_used == MemoryPool::alloc_count) {
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
ERR_FAIL_MSG("All memory pool allocations are in use, can't COW.");
|
||||
}
|
||||
|
||||
@@ -113,7 +114,7 @@ class PoolVector {
|
||||
alloc->size = old_alloc->size;
|
||||
alloc->refcount.init();
|
||||
alloc->pool_id = POOL_ALLOCATOR_INVALID_ID;
|
||||
alloc->lock = 0;
|
||||
alloc->lock.set(0);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
MemoryPool::total_memory += alloc->size;
|
||||
@@ -122,7 +123,7 @@ class PoolVector {
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
|
||||
if (MemoryPool::memory_pool) {
|
||||
|
||||
@@ -148,9 +149,9 @@ class PoolVector {
|
||||
//this should never happen but..
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
MemoryPool::total_memory -= old_alloc->size;
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
#endif
|
||||
|
||||
{
|
||||
@@ -174,11 +175,11 @@ class PoolVector {
|
||||
old_alloc->mem = NULL;
|
||||
old_alloc->size = 0;
|
||||
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
old_alloc->free_list = MemoryPool::free_list;
|
||||
MemoryPool::free_list = old_alloc;
|
||||
MemoryPool::allocs_used--;
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,9 +228,9 @@ class PoolVector {
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
MemoryPool::total_memory -= alloc->size;
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
#endif
|
||||
|
||||
if (MemoryPool::memory_pool) {
|
||||
@@ -242,11 +243,11 @@ class PoolVector {
|
||||
alloc->mem = NULL;
|
||||
alloc->size = 0;
|
||||
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
alloc->free_list = MemoryPool::free_list;
|
||||
MemoryPool::free_list = alloc;
|
||||
MemoryPool::allocs_used--;
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
}
|
||||
|
||||
alloc = NULL;
|
||||
@@ -263,7 +264,7 @@ public:
|
||||
_FORCE_INLINE_ void _ref(MemoryPool::Alloc *p_alloc) {
|
||||
alloc = p_alloc;
|
||||
if (alloc) {
|
||||
if (atomic_increment(&alloc->lock) == 1) {
|
||||
if (alloc->lock.increment() == 1) {
|
||||
if (MemoryPool::memory_pool) {
|
||||
//lock it and get mem
|
||||
}
|
||||
@@ -276,7 +277,7 @@ public:
|
||||
_FORCE_INLINE_ void _unref() {
|
||||
|
||||
if (alloc) {
|
||||
if (atomic_decrement(&alloc->lock) == 0) {
|
||||
if (alloc->lock.decrement() == 0) {
|
||||
if (MemoryPool::memory_pool) {
|
||||
//put mem back
|
||||
}
|
||||
@@ -452,7 +453,7 @@ public:
|
||||
return rs;
|
||||
}
|
||||
|
||||
bool is_locked() const { return alloc && alloc->lock > 0; }
|
||||
bool is_locked() const { return alloc && alloc->lock.get() > 0; }
|
||||
|
||||
inline T operator[](int p_index) const;
|
||||
|
||||
@@ -523,9 +524,9 @@ Error PoolVector<T>::resize(int p_size) {
|
||||
return OK; //nothing to do here
|
||||
|
||||
//must allocate something
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
if (MemoryPool::allocs_used == MemoryPool::alloc_count) {
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "All memory pool allocations are in use.");
|
||||
}
|
||||
|
||||
@@ -539,11 +540,11 @@ Error PoolVector<T>::resize(int p_size) {
|
||||
alloc->size = 0;
|
||||
alloc->refcount.init();
|
||||
alloc->pool_id = POOL_ALLOCATOR_INVALID_ID;
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
|
||||
} else {
|
||||
|
||||
ERR_FAIL_COND_V_MSG(alloc->lock > 0, ERR_LOCKED, "Can't resize PoolVector if locked."); //can't resize if locked!
|
||||
ERR_FAIL_COND_V_MSG(alloc->lock.get() > 0, ERR_LOCKED, "Can't resize PoolVector if locked."); //can't resize if locked!
|
||||
}
|
||||
|
||||
size_t new_size = sizeof(T) * p_size;
|
||||
@@ -559,13 +560,13 @@ Error PoolVector<T>::resize(int p_size) {
|
||||
_copy_on_write(); // make it unique
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
MemoryPool::total_memory -= alloc->size;
|
||||
MemoryPool::total_memory += new_size;
|
||||
if (MemoryPool::total_memory > MemoryPool::max_memory) {
|
||||
MemoryPool::max_memory = MemoryPool::total_memory;
|
||||
}
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
#endif
|
||||
|
||||
int cur_elements = alloc->size / sizeof(T);
|
||||
@@ -615,11 +616,11 @@ Error PoolVector<T>::resize(int p_size) {
|
||||
alloc->mem = NULL;
|
||||
alloc->size = 0;
|
||||
|
||||
MemoryPool::alloc_mutex->lock();
|
||||
MemoryPool::alloc_mutex.lock();
|
||||
alloc->free_list = MemoryPool::free_list;
|
||||
MemoryPool::free_list = alloc;
|
||||
MemoryPool::allocs_used--;
|
||||
MemoryPool::alloc_mutex->unlock();
|
||||
MemoryPool::alloc_mutex.unlock();
|
||||
|
||||
} else {
|
||||
alloc->mem = memrealloc(alloc->mem, new_size);
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
@@ -90,7 +90,7 @@ static IP *ip = NULL;
|
||||
|
||||
static _Geometry *_geometry = NULL;
|
||||
|
||||
extern Mutex *_global_mutex;
|
||||
extern Mutex _global_mutex;
|
||||
|
||||
extern void register_global_constants();
|
||||
extern void unregister_global_constants();
|
||||
@@ -99,14 +99,9 @@ extern void unregister_variant_methods();
|
||||
|
||||
void register_core_types() {
|
||||
|
||||
ObjectDB::setup();
|
||||
ResourceCache::setup();
|
||||
MemoryPool::setup();
|
||||
|
||||
_global_mutex = Mutex::create();
|
||||
|
||||
StringName::setup();
|
||||
ResourceLoader::initialize();
|
||||
|
||||
register_global_constants();
|
||||
register_variant_methods();
|
||||
@@ -318,10 +313,5 @@ void unregister_core_types() {
|
||||
CoreStringNames::free();
|
||||
StringName::cleanup();
|
||||
|
||||
if (_global_mutex) {
|
||||
memdelete(_global_mutex);
|
||||
_global_mutex = NULL; //still needed at a few places
|
||||
};
|
||||
|
||||
MemoryPool::cleanup();
|
||||
}
|
||||
|
||||
+33
-60
@@ -54,30 +54,30 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
|
||||
|
||||
if (path_cache != "") {
|
||||
|
||||
ResourceCache::lock->write_lock();
|
||||
ResourceCache::lock.write_lock();
|
||||
ResourceCache::resources.erase(path_cache);
|
||||
ResourceCache::lock->write_unlock();
|
||||
ResourceCache::lock.write_unlock();
|
||||
}
|
||||
|
||||
path_cache = "";
|
||||
|
||||
ResourceCache::lock->read_lock();
|
||||
ResourceCache::lock.read_lock();
|
||||
bool has_path = ResourceCache::resources.has(p_path);
|
||||
ResourceCache::lock->read_unlock();
|
||||
ResourceCache::lock.read_unlock();
|
||||
|
||||
if (has_path) {
|
||||
if (p_take_over) {
|
||||
|
||||
ResourceCache::lock->write_lock();
|
||||
ResourceCache::lock.write_lock();
|
||||
Resource **res = ResourceCache::resources.getptr(p_path);
|
||||
if (res) {
|
||||
(*res)->set_name("");
|
||||
}
|
||||
ResourceCache::lock->write_unlock();
|
||||
ResourceCache::lock.write_unlock();
|
||||
} else {
|
||||
ResourceCache::lock->read_lock();
|
||||
ResourceCache::lock.read_lock();
|
||||
bool exists = ResourceCache::resources.has(p_path);
|
||||
ResourceCache::lock->read_unlock();
|
||||
ResourceCache::lock.read_unlock();
|
||||
|
||||
ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
|
||||
}
|
||||
@@ -86,9 +86,9 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
|
||||
|
||||
if (path_cache != "") {
|
||||
|
||||
ResourceCache::lock->write_lock();
|
||||
ResourceCache::lock.write_lock();
|
||||
ResourceCache::resources[path_cache] = this;
|
||||
ResourceCache::lock->write_unlock();
|
||||
ResourceCache::lock.write_unlock();
|
||||
}
|
||||
|
||||
_change_notify("resource_path");
|
||||
@@ -343,9 +343,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
|
||||
if (remapped_list.in_list() == p_remapped)
|
||||
return;
|
||||
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->write_lock();
|
||||
}
|
||||
ResourceCache::lock.write_lock();
|
||||
|
||||
if (p_remapped) {
|
||||
ResourceLoader::remapped_list.add(&remapped_list);
|
||||
@@ -353,9 +351,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
|
||||
ResourceLoader::remapped_list.remove(&remapped_list);
|
||||
}
|
||||
|
||||
if (ResourceCache::lock) {
|
||||
ResourceCache::lock->write_unlock();
|
||||
}
|
||||
ResourceCache::lock.write_unlock();
|
||||
}
|
||||
|
||||
bool Resource::is_translation_remapped() const {
|
||||
@@ -367,38 +363,24 @@ bool Resource::is_translation_remapped() const {
|
||||
//helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
|
||||
void Resource::set_id_for_path(const String &p_path, int p_id) {
|
||||
if (p_id == -1) {
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->write_lock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.write_lock();
|
||||
ResourceCache::resource_path_cache[p_path].erase(get_path());
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->write_unlock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.write_unlock();
|
||||
} else {
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->write_lock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.write_lock();
|
||||
ResourceCache::resource_path_cache[p_path][get_path()] = p_id;
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->write_unlock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.write_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int Resource::get_id_for_path(const String &p_path) const {
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->read_lock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.read_lock();
|
||||
if (ResourceCache::resource_path_cache[p_path].has(get_path())) {
|
||||
int result = ResourceCache::resource_path_cache[p_path][get_path()];
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->read_unlock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.read_unlock();
|
||||
return result;
|
||||
} else {
|
||||
if (ResourceCache::path_cache_lock) {
|
||||
ResourceCache::path_cache_lock->read_unlock();
|
||||
}
|
||||
ResourceCache::path_cache_lock.read_unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -444,9 +426,9 @@ Resource::Resource() :
|
||||
Resource::~Resource() {
|
||||
|
||||
if (path_cache != "") {
|
||||
ResourceCache::lock->write_lock();
|
||||
ResourceCache::lock.write_lock();
|
||||
ResourceCache::resources.erase(path_cache);
|
||||
ResourceCache::lock->write_unlock();
|
||||
ResourceCache::lock.write_unlock();
|
||||
}
|
||||
if (owners.size()) {
|
||||
WARN_PRINT("Resource is still owned.");
|
||||
@@ -458,19 +440,11 @@ HashMap<String, Resource *> ResourceCache::resources;
|
||||
HashMap<String, HashMap<String, int> > ResourceCache::resource_path_cache;
|
||||
#endif
|
||||
|
||||
RWLock *ResourceCache::lock = NULL;
|
||||
RWLock ResourceCache::lock;
|
||||
#ifdef TOOLS_ENABLED
|
||||
RWLock *ResourceCache::path_cache_lock = NULL;
|
||||
RWLock ResourceCache::path_cache_lock;
|
||||
#endif
|
||||
|
||||
void ResourceCache::setup() {
|
||||
|
||||
lock = RWLock::create();
|
||||
#ifdef TOOLS_ENABLED
|
||||
path_cache_lock = RWLock::create();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ResourceCache::clear() {
|
||||
if (resources.size()) {
|
||||
ERR_PRINT("Resources still in use at exit (run with --verbose for details).");
|
||||
@@ -484,7 +458,6 @@ void ResourceCache::clear() {
|
||||
}
|
||||
|
||||
resources.clear();
|
||||
memdelete(lock);
|
||||
}
|
||||
|
||||
void ResourceCache::reload_externals() {
|
||||
@@ -492,19 +465,19 @@ void ResourceCache::reload_externals() {
|
||||
|
||||
bool ResourceCache::has(const String &p_path) {
|
||||
|
||||
lock->read_lock();
|
||||
lock.read_lock();
|
||||
bool b = resources.has(p_path);
|
||||
lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
|
||||
return b;
|
||||
}
|
||||
Resource *ResourceCache::get(const String &p_path) {
|
||||
|
||||
lock->read_lock();
|
||||
lock.read_lock();
|
||||
|
||||
Resource **res = resources.getptr(p_path);
|
||||
|
||||
lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
|
||||
if (!res) {
|
||||
return NULL;
|
||||
@@ -515,28 +488,28 @@ Resource *ResourceCache::get(const String &p_path) {
|
||||
|
||||
void ResourceCache::get_cached_resources(List<Ref<Resource> > *p_resources) {
|
||||
|
||||
lock->read_lock();
|
||||
lock.read_lock();
|
||||
const String *K = NULL;
|
||||
while ((K = resources.next(K))) {
|
||||
|
||||
Resource *r = resources[*K];
|
||||
p_resources->push_back(Ref<Resource>(r));
|
||||
}
|
||||
lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
}
|
||||
|
||||
int ResourceCache::get_cached_resource_count() {
|
||||
|
||||
lock->read_lock();
|
||||
lock.read_lock();
|
||||
int rc = resources.size();
|
||||
lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ResourceCache::dump(const char *p_file, bool p_short) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
lock->read_lock();
|
||||
lock.read_lock();
|
||||
|
||||
Map<String, int> type_count;
|
||||
|
||||
@@ -573,6 +546,6 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
lock->read_unlock();
|
||||
lock.read_unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
+2
-3
@@ -148,16 +148,15 @@ typedef Ref<Resource> RES;
|
||||
class ResourceCache {
|
||||
friend class Resource;
|
||||
friend class ResourceLoader; //need the lock
|
||||
static RWLock *lock;
|
||||
static RWLock lock;
|
||||
static HashMap<String, Resource *> resources;
|
||||
#ifdef TOOLS_ENABLED
|
||||
static HashMap<String, HashMap<String, int> > resource_path_cache; // each tscn has a set of resource paths and IDs
|
||||
static RWLock *path_cache_lock;
|
||||
static RWLock path_cache_lock;
|
||||
#endif // TOOLS_ENABLED
|
||||
friend void unregister_core_types();
|
||||
static void clear();
|
||||
friend void register_core_types();
|
||||
static void setup();
|
||||
|
||||
public:
|
||||
static void reload_externals();
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* safe_refcount.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "safe_refcount.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
/* Implementation for MSVC-Windows */
|
||||
|
||||
// don't pollute my namespace!
|
||||
#include <windows.h>
|
||||
|
||||
#define ATOMIC_CONDITIONAL_INCREMENT_BODY(m_pw, m_win_type, m_win_cmpxchg, m_cpp_type) \
|
||||
/* try to increment until it actually works */ \
|
||||
/* taken from boost */ \
|
||||
while (true) { \
|
||||
m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
|
||||
if (tmp == 0) \
|
||||
return 0; /* if zero, can't add to it anymore */ \
|
||||
if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) \
|
||||
return tmp + 1; \
|
||||
}
|
||||
|
||||
#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \
|
||||
while (true) { \
|
||||
m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
|
||||
if (tmp >= m_val) \
|
||||
return tmp; /* already greater, or equal */ \
|
||||
if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) \
|
||||
return m_val; \
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){
|
||||
|
||||
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t)
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
|
||||
|
||||
return InterlockedDecrement((LONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
|
||||
|
||||
return InterlockedIncrement((LONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
|
||||
return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
|
||||
return InterlockedAdd((LONG volatile *)pw, val);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){
|
||||
|
||||
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t)
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){
|
||||
|
||||
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t)
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
|
||||
|
||||
return InterlockedDecrement64((LONGLONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
|
||||
|
||||
return InterlockedIncrement64((LONGLONG volatile *)pw);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
|
||||
return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
|
||||
return InterlockedAdd64((LONGLONG volatile *)pw, val);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){
|
||||
|
||||
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t)
|
||||
}
|
||||
|
||||
// The actual advertised functions; they'll call the right implementation
|
||||
|
||||
uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
|
||||
return _atomic_conditional_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint32_t atomic_decrement(volatile uint32_t *pw) {
|
||||
return _atomic_decrement_impl(pw);
|
||||
}
|
||||
|
||||
uint32_t atomic_increment(volatile uint32_t *pw) {
|
||||
return _atomic_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return _atomic_sub_impl(pw, val);
|
||||
}
|
||||
|
||||
uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return _atomic_add_impl(pw, val);
|
||||
}
|
||||
|
||||
uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
|
||||
return _atomic_exchange_if_greater_impl(pw, val);
|
||||
}
|
||||
|
||||
uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
|
||||
return _atomic_conditional_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint64_t atomic_decrement(volatile uint64_t *pw) {
|
||||
return _atomic_decrement_impl(pw);
|
||||
}
|
||||
|
||||
uint64_t atomic_increment(volatile uint64_t *pw) {
|
||||
return _atomic_increment_impl(pw);
|
||||
}
|
||||
|
||||
uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return _atomic_sub_impl(pw, val);
|
||||
}
|
||||
|
||||
uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return _atomic_add_impl(pw, val);
|
||||
}
|
||||
|
||||
uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
|
||||
return _atomic_exchange_if_greater_impl(pw, val);
|
||||
}
|
||||
#endif
|
||||
+258
-147
@@ -31,181 +31,292 @@
|
||||
#ifndef SAFE_REFCOUNT_H
|
||||
#define SAFE_REFCOUNT_H
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "platform_config.h"
|
||||
|
||||
// Atomic functions, these are used for multithread safe reference counters!
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#ifdef NO_THREADS
|
||||
#include <atomic>
|
||||
|
||||
/* Bogus implementation unaware of multiprocessing */
|
||||
// Design goals for these classes:
|
||||
// - No automatic conversions or arithmetic operators,
|
||||
// to keep explicit the use of atomics everywhere.
|
||||
// - Using acquire-release semantics, even to set the first value.
|
||||
// The first value may be set relaxedly in many cases, but adding the distinction
|
||||
// between relaxed and unrelaxed operation to the interface would make it needlessly
|
||||
// flexible. There's negligible waste in having release semantics for the initial
|
||||
// value and, as an important benefit, you can be sure the value is properly synchronized
|
||||
// even with threads that are already running.
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
|
||||
|
||||
if (*pw == 0)
|
||||
return 0;
|
||||
|
||||
(*pw)++;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
|
||||
|
||||
(*pw)--;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
|
||||
|
||||
(*pw)++;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
|
||||
|
||||
(*pw) -= val;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
|
||||
|
||||
(*pw) += val;
|
||||
|
||||
return *pw;
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
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 <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
|
||||
|
||||
while (true) {
|
||||
T tmp = static_cast<T const volatile &>(*pw);
|
||||
if (tmp == 0)
|
||||
return 0; // if zero, can't add to it anymore
|
||||
if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp)
|
||||
return tmp + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
|
||||
|
||||
return __sync_sub_and_fetch(pw, 1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
|
||||
|
||||
return __sync_add_and_fetch(pw, 1);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
|
||||
|
||||
return __sync_sub_and_fetch(pw, val);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
|
||||
|
||||
return __sync_add_and_fetch(pw, val);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
|
||||
|
||||
while (true) {
|
||||
T tmp = static_cast<T const volatile &>(*pw);
|
||||
if (tmp >= val)
|
||||
return tmp; // already greater, or equal
|
||||
if (__sync_val_compare_and_swap(pw, tmp, val) == tmp)
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
#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<T> 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>(T p_value = static_cast<T>(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<uint32_t> 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 T>
|
||||
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>(T p_value = static_cast<T>(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
|
||||
|
||||
+23
-27
@@ -47,12 +47,10 @@ StringName _scs_create(const char *p_chr) {
|
||||
}
|
||||
|
||||
bool StringName::configured = false;
|
||||
Mutex *StringName::lock = NULL;
|
||||
Mutex StringName::lock;
|
||||
|
||||
void StringName::setup() {
|
||||
|
||||
lock = Mutex::create();
|
||||
|
||||
ERR_FAIL_COND(configured);
|
||||
for (int i = 0; i < STRING_TABLE_LEN; i++) {
|
||||
|
||||
@@ -63,7 +61,7 @@ void StringName::setup() {
|
||||
|
||||
void StringName::cleanup() {
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
int lost_strings = 0;
|
||||
for (int i = 0; i < STRING_TABLE_LEN; i++) {
|
||||
@@ -87,9 +85,7 @@ void StringName::cleanup() {
|
||||
if (lost_strings) {
|
||||
print_verbose("StringName: " + itos(lost_strings) + " unclaimed string names at exit.");
|
||||
}
|
||||
lock->unlock();
|
||||
|
||||
memdelete(lock);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
void StringName::unref() {
|
||||
@@ -98,7 +94,7 @@ void StringName::unref() {
|
||||
|
||||
if (_data && _data->refcount.unref()) {
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
if (_data->prev) {
|
||||
_data->prev->next = _data->next;
|
||||
@@ -113,7 +109,7 @@ void StringName::unref() {
|
||||
_data->next->prev = _data->prev;
|
||||
}
|
||||
memdelete(_data);
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
_data = NULL;
|
||||
@@ -184,7 +180,7 @@ StringName::StringName(const char *p_name) {
|
||||
if (!p_name || p_name[0] == 0)
|
||||
return; //empty, ignore
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
uint32_t hash = String::hash(p_name);
|
||||
|
||||
@@ -203,7 +199,7 @@ StringName::StringName(const char *p_name) {
|
||||
if (_data) {
|
||||
if (_data->refcount.ref()) {
|
||||
// exists
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -220,7 +216,7 @@ StringName::StringName(const char *p_name) {
|
||||
_table[idx]->prev = _data;
|
||||
_table[idx] = _data;
|
||||
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
StringName::StringName(const StaticCString &p_static_string) {
|
||||
@@ -231,7 +227,7 @@ StringName::StringName(const StaticCString &p_static_string) {
|
||||
|
||||
ERR_FAIL_COND(!p_static_string.ptr || !p_static_string.ptr[0]);
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
uint32_t hash = String::hash(p_static_string.ptr);
|
||||
|
||||
@@ -250,7 +246,7 @@ StringName::StringName(const StaticCString &p_static_string) {
|
||||
if (_data) {
|
||||
if (_data->refcount.ref()) {
|
||||
// exists
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -267,7 +263,7 @@ StringName::StringName(const StaticCString &p_static_string) {
|
||||
_table[idx]->prev = _data;
|
||||
_table[idx] = _data;
|
||||
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
StringName::StringName(const String &p_name) {
|
||||
@@ -279,7 +275,7 @@ StringName::StringName(const String &p_name) {
|
||||
if (p_name == String())
|
||||
return;
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
uint32_t hash = p_name.hash();
|
||||
|
||||
@@ -297,7 +293,7 @@ StringName::StringName(const String &p_name) {
|
||||
if (_data) {
|
||||
if (_data->refcount.ref()) {
|
||||
// exists
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -314,7 +310,7 @@ StringName::StringName(const String &p_name) {
|
||||
_table[idx]->prev = _data;
|
||||
_table[idx] = _data;
|
||||
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
StringName StringName::search(const char *p_name) {
|
||||
@@ -325,7 +321,7 @@ StringName StringName::search(const char *p_name) {
|
||||
if (!p_name[0])
|
||||
return StringName();
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
uint32_t hash = String::hash(p_name);
|
||||
|
||||
@@ -342,12 +338,12 @@ StringName StringName::search(const char *p_name) {
|
||||
}
|
||||
|
||||
if (_data && _data->refcount.ref()) {
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
|
||||
return StringName(_data);
|
||||
}
|
||||
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return StringName(); //does not exist
|
||||
}
|
||||
|
||||
@@ -359,7 +355,7 @@ StringName StringName::search(const CharType *p_name) {
|
||||
if (!p_name[0])
|
||||
return StringName();
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
uint32_t hash = String::hash(p_name);
|
||||
|
||||
@@ -376,18 +372,18 @@ StringName StringName::search(const CharType *p_name) {
|
||||
}
|
||||
|
||||
if (_data && _data->refcount.ref()) {
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return StringName(_data);
|
||||
}
|
||||
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return StringName(); //does not exist
|
||||
}
|
||||
StringName StringName::search(const String &p_name) {
|
||||
|
||||
ERR_FAIL_COND_V(p_name == "", StringName());
|
||||
|
||||
lock->lock();
|
||||
lock.lock();
|
||||
|
||||
uint32_t hash = p_name.hash();
|
||||
|
||||
@@ -404,11 +400,11 @@ StringName StringName::search(const String &p_name) {
|
||||
}
|
||||
|
||||
if (_data && _data->refcount.ref()) {
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return StringName(_data);
|
||||
}
|
||||
|
||||
lock->unlock();
|
||||
lock.unlock();
|
||||
return StringName(); //does not exist
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user