Merge pull request #45618 from RandomShaper/modernize_mt_3.2
Backport of all the multi-threading modernization (3.2)
This commit is contained in:
commit
220f24c191
191 changed files with 1688 additions and 4522 deletions
|
@ -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...");
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
107
core/io/ip.cpp
107
core/io/ip.cpp
|
@ -42,13 +42,13 @@ struct _IP_ResolverPrivate {
|
|||
|
||||
struct QueueItem {
|
||||
|
||||
volatile IP::ResolverStatus status;
|
||||
SafeNumeric<IP::ResolverStatus> status;
|
||||
IP_Address response;
|
||||
String hostname;
|
||||
IP::Type type;
|
||||
|
||||
void clear() {
|
||||
status = IP::RESOLVER_STATUS_NONE;
|
||||
status.set(IP::RESOLVER_STATUS_NONE);
|
||||
response = IP_Address();
|
||||
type = IP::TYPE_NONE;
|
||||
hostname = "";
|
||||
|
@ -64,16 +64,16 @@ struct _IP_ResolverPrivate {
|
|||
IP::ResolverID find_empty_id() const {
|
||||
|
||||
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
|
||||
if (queue[i].status == IP::RESOLVER_STATUS_NONE)
|
||||
if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE)
|
||||
return i;
|
||||
}
|
||||
return IP::RESOLVER_INVALID_ID;
|
||||
}
|
||||
|
||||
Mutex *mutex;
|
||||
Semaphore *sem;
|
||||
Mutex mutex;
|
||||
Semaphore sem;
|
||||
|
||||
Thread *thread;
|
||||
Thread thread;
|
||||
//Semaphore* semaphore;
|
||||
bool thread_abort;
|
||||
|
||||
|
@ -81,14 +81,14 @@ struct _IP_ResolverPrivate {
|
|||
|
||||
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
|
||||
|
||||
if (queue[i].status != IP::RESOLVER_STATUS_WAITING)
|
||||
if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING)
|
||||
continue;
|
||||
queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
|
||||
|
||||
if (!queue[i].response.is_valid())
|
||||
queue[i].status = IP::RESOLVER_STATUS_ERROR;
|
||||
queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
|
||||
else
|
||||
queue[i].status = IP::RESOLVER_STATUS_DONE;
|
||||
queue[i].status.set(IP::RESOLVER_STATUS_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,11 +98,11 @@ struct _IP_ResolverPrivate {
|
|||
|
||||
while (!ipr->thread_abort) {
|
||||
|
||||
ipr->sem->wait();
|
||||
ipr->sem.wait();
|
||||
|
||||
ipr->mutex->lock();
|
||||
ipr->mutex.lock();
|
||||
ipr->resolve_queues();
|
||||
ipr->mutex->unlock();
|
||||
ipr->mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,30 +115,30 @@ struct _IP_ResolverPrivate {
|
|||
|
||||
IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
|
||||
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
|
||||
IP_Address res = resolver->cache[key];
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
IP_Address res = _resolve_hostname(p_hostname, p_type);
|
||||
resolver->cache[key] = res;
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Type p_type) {
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
ResolverID id = resolver->find_empty_id();
|
||||
|
||||
if (id == RESOLVER_INVALID_ID) {
|
||||
WARN_PRINT("Out of resolver queries");
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -147,17 +147,17 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
|
|||
resolver->queue[id].type = p_type;
|
||||
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
|
||||
resolver->queue[id].response = resolver->cache[key];
|
||||
resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
|
||||
resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
|
||||
} else {
|
||||
resolver->queue[id].response = IP_Address();
|
||||
resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
|
||||
if (resolver->thread)
|
||||
resolver->sem->post();
|
||||
resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
|
||||
if (resolver->thread.is_started())
|
||||
resolver->sem.post();
|
||||
else
|
||||
resolver->resolve_queues();
|
||||
}
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -165,15 +165,15 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
|
|||
|
||||
ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP::RESOLVER_STATUS_NONE);
|
||||
|
||||
resolver->mutex->lock();
|
||||
if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) {
|
||||
resolver->mutex.lock();
|
||||
if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
|
||||
ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return IP::RESOLVER_STATUS_NONE;
|
||||
}
|
||||
IP::ResolverStatus res = resolver->queue[p_id].status;
|
||||
IP::ResolverStatus res = resolver->queue[p_id].status.get();
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -181,17 +181,17 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
|
|||
|
||||
ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP_Address());
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
|
||||
if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
|
||||
ERR_PRINTS("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return IP_Address();
|
||||
}
|
||||
|
||||
IP_Address res = resolver->queue[p_id].response;
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -199,16 +199,16 @@ void IP::erase_resolve_item(ResolverID p_id) {
|
|||
|
||||
ERR_FAIL_INDEX(p_id, IP::RESOLVER_MAX_QUERIES);
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE;
|
||||
resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
}
|
||||
|
||||
void IP::clear_cache(const String &p_hostname) {
|
||||
|
||||
resolver->mutex->lock();
|
||||
resolver->mutex.lock();
|
||||
|
||||
if (p_hostname.empty()) {
|
||||
resolver->cache.clear();
|
||||
|
@ -219,7 +219,7 @@ void IP::clear_cache(const String &p_hostname) {
|
|||
resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_ANY));
|
||||
}
|
||||
|
||||
resolver->mutex->unlock();
|
||||
resolver->mutex.unlock();
|
||||
}
|
||||
|
||||
Array IP::_get_local_addresses() const {
|
||||
|
@ -314,41 +314,16 @@ IP::IP() {
|
|||
|
||||
singleton = this;
|
||||
resolver = memnew(_IP_ResolverPrivate);
|
||||
resolver->sem = NULL;
|
||||
resolver->mutex = Mutex::create();
|
||||
|
||||
#ifndef NO_THREADS
|
||||
|
||||
resolver->sem = Semaphore::create();
|
||||
if (resolver->sem) {
|
||||
resolver->thread_abort = false;
|
||||
|
||||
resolver->thread = Thread::create(_IP_ResolverPrivate::_thread_function, resolver);
|
||||
|
||||
if (!resolver->thread)
|
||||
memdelete(resolver->sem); //wtf
|
||||
} else {
|
||||
resolver->thread = NULL;
|
||||
}
|
||||
#else
|
||||
resolver->sem = NULL;
|
||||
resolver->thread = NULL;
|
||||
#endif
|
||||
resolver->thread_abort = false;
|
||||
resolver->thread.start(_IP_ResolverPrivate::_thread_function, resolver);
|
||||
}
|
||||
|
||||
IP::~IP() {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
if (resolver->thread) {
|
||||
resolver->thread_abort = true;
|
||||
resolver->sem->post();
|
||||
Thread::wait_to_finish(resolver->thread);
|
||||
memdelete(resolver->thread);
|
||||
memdelete(resolver->sem);
|
||||
}
|
||||
resolver->thread_abort = true;
|
||||
resolver->sem.post();
|
||||
resolver->thread.wait_to_finish();
|
||||
|
||||
#endif
|
||||
|
||||
memdelete(resolver->mutex);
|
||||
memdelete(resolver);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
101
core/os/mutex.h
101
core/os/mutex.h
|
@ -32,42 +32,89 @@
|
|||
#define MUTEX_H
|
||||
|
||||
#include "core/error_list.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
/**
|
||||
* @class Mutex
|
||||
* @author Juan Linietsky
|
||||
* Portable Mutex (thread-safe locking) implementation.
|
||||
* Mutexes are always recursive ( they don't self-lock in a single thread ).
|
||||
* Mutexes can be used with a Lockp object like this, to avoid having to worry about unlocking:
|
||||
* Lockp( mutex );
|
||||
*/
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
class Mutex {
|
||||
protected:
|
||||
static Mutex *(*create_func)(bool);
|
||||
#include <mutex>
|
||||
|
||||
template <class StdMutexT>
|
||||
class MutexImpl {
|
||||
mutable StdMutexT mutex;
|
||||
friend class MutexLock;
|
||||
|
||||
public:
|
||||
virtual void lock() = 0; ///< Lock the mutex, block if locked by someone else
|
||||
virtual void unlock() = 0; ///< Unlock the mutex, let other threads continue
|
||||
virtual Error try_lock() = 0; ///< Attempt to lock the mutex, OK on success, ERROR means it can't lock.
|
||||
_ALWAYS_INLINE_ void lock() const {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
static Mutex *create(bool p_recursive = true); ///< Create a mutex
|
||||
_ALWAYS_INLINE_ void unlock() const {
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
virtual ~Mutex();
|
||||
_ALWAYS_INLINE_ Error try_lock() const {
|
||||
return mutex.try_lock() ? OK : ERR_BUSY;
|
||||
}
|
||||
};
|
||||
|
||||
// This is written this way instead of being a template to overcome a limitation of C++ pre-17
|
||||
// that would require MutexLock to be used like this: MutexLock<Mutex> lock;
|
||||
class MutexLock {
|
||||
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() {
|
||||
}
|
|
@ -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() {
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -169,8 +169,7 @@ Error AudioDriverALSA::init() {
|
|||
|
||||
Error err = init_device();
|
||||
if (err == OK) {
|
||||
mutex = Mutex::create();
|
||||
thread = Thread::create(AudioDriverALSA::thread_func, this);
|
||||
thread.start(AudioDriverALSA::thread_func, this);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -314,16 +313,12 @@ void AudioDriverALSA::set_device(String device) {
|
|||
|
||||
void AudioDriverALSA::lock() {
|
||||
|
||||
if (!thread || !mutex)
|
||||
return;
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void AudioDriverALSA::unlock() {
|
||||
|
||||
if (!thread || !mutex)
|
||||
return;
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void AudioDriverALSA::finish_device() {
|
||||
|
@ -336,25 +331,13 @@ void AudioDriverALSA::finish_device() {
|
|||
|
||||
void AudioDriverALSA::finish() {
|
||||
|
||||
if (thread) {
|
||||
exit_thread = true;
|
||||
Thread::wait_to_finish(thread);
|
||||
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
|
||||
if (mutex) {
|
||||
memdelete(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
}
|
||||
exit_thread = true;
|
||||
thread.wait_to_finish();
|
||||
|
||||
finish_device();
|
||||
}
|
||||
|
||||
AudioDriverALSA::AudioDriverALSA() :
|
||||
thread(NULL),
|
||||
mutex(NULL),
|
||||
pcm_handle(NULL),
|
||||
device_name("Default"),
|
||||
new_device("Default") {
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
|
||||
class AudioDriverALSA : public AudioDriver {
|
||||
|
||||
Thread *thread;
|
||||
Mutex *mutex;
|
||||
Thread thread;
|
||||
Mutex mutex;
|
||||
|
||||
snd_pcm_t *pcm_handle;
|
||||
|
||||
|
|
|
@ -148,27 +148,16 @@ Error MIDIDriverALSAMidi::open() {
|
|||
}
|
||||
snd_device_name_free_hint(hints);
|
||||
|
||||
mutex = Mutex::create();
|
||||
exit_thread = false;
|
||||
thread = Thread::create(MIDIDriverALSAMidi::thread_func, this);
|
||||
thread.start(MIDIDriverALSAMidi::thread_func, this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void MIDIDriverALSAMidi::close() {
|
||||
|
||||
if (thread) {
|
||||
exit_thread = true;
|
||||
Thread::wait_to_finish(thread);
|
||||
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
}
|
||||
|
||||
if (mutex) {
|
||||
memdelete(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
exit_thread = true;
|
||||
thread.wait_to_finish();
|
||||
|
||||
for (int i = 0; i < connected_inputs.size(); i++) {
|
||||
snd_rawmidi_t *midi_in = connected_inputs[i];
|
||||
|
@ -179,14 +168,12 @@ void MIDIDriverALSAMidi::close() {
|
|||
|
||||
void MIDIDriverALSAMidi::lock() const {
|
||||
|
||||
if (mutex)
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void MIDIDriverALSAMidi::unlock() const {
|
||||
|
||||
if (mutex)
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
|
||||
|
@ -210,9 +197,6 @@ PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
|
|||
|
||||
MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
|
||||
|
||||
mutex = NULL;
|
||||
thread = NULL;
|
||||
|
||||
exit_thread = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
|
||||
class MIDIDriverALSAMidi : public MIDIDriver {
|
||||
|
||||
Thread *thread;
|
||||
Mutex *mutex;
|
||||
Thread thread;
|
||||
Mutex mutex;
|
||||
|
||||
Vector<snd_rawmidi_t *> connected_inputs;
|
||||
|
||||
|
|
|
@ -69,8 +69,6 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID
|
|||
#endif
|
||||
|
||||
Error AudioDriverCoreAudio::init() {
|
||||
mutex = Mutex::create();
|
||||
|
||||
AudioComponentDescription desc;
|
||||
zeromem(&desc, sizeof(desc));
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
|
@ -280,19 +278,15 @@ AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
|
|||
};
|
||||
|
||||
void AudioDriverCoreAudio::lock() {
|
||||
if (mutex)
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
};
|
||||
|
||||
void AudioDriverCoreAudio::unlock() {
|
||||
if (mutex)
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
};
|
||||
|
||||
bool AudioDriverCoreAudio::try_lock() {
|
||||
if (mutex)
|
||||
return mutex->try_lock() == OK;
|
||||
return true;
|
||||
return mutex.try_lock() == OK;
|
||||
}
|
||||
|
||||
void AudioDriverCoreAudio::finish() {
|
||||
|
@ -344,11 +338,6 @@ void AudioDriverCoreAudio::finish() {
|
|||
audio_unit = NULL;
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (mutex) {
|
||||
memdelete(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Error AudioDriverCoreAudio::capture_init() {
|
||||
|
@ -691,7 +680,6 @@ AudioDriverCoreAudio::AudioDriverCoreAudio() :
|
|||
audio_unit(NULL),
|
||||
input_unit(NULL),
|
||||
active(false),
|
||||
mutex(NULL),
|
||||
device_name("Default"),
|
||||
capture_device_name("Default"),
|
||||
mix_rate(0),
|
||||
|
|
|
@ -46,7 +46,7 @@ class AudioDriverCoreAudio : public AudioDriver {
|
|||
AudioComponentInstance input_unit;
|
||||
|
||||
bool active;
|
||||
Mutex *mutex;
|
||||
Mutex mutex;
|
||||
|
||||
String device_name;
|
||||
String capture_device_name;
|
||||
|
|
|
@ -294,8 +294,7 @@ Error AudioDriverPulseAudio::init() {
|
|||
|
||||
Error err = init_device();
|
||||
if (err == OK) {
|
||||
mutex = Mutex::create();
|
||||
thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
|
||||
thread.start(AudioDriverPulseAudio::thread_func, this);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
@ -600,16 +599,12 @@ void AudioDriverPulseAudio::set_device(String device) {
|
|||
|
||||
void AudioDriverPulseAudio::lock() {
|
||||
|
||||
if (!thread || !mutex)
|
||||
return;
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void AudioDriverPulseAudio::unlock() {
|
||||
|
||||
if (!thread || !mutex)
|
||||
return;
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void AudioDriverPulseAudio::finish_device() {
|
||||
|
@ -623,11 +618,11 @@ void AudioDriverPulseAudio::finish_device() {
|
|||
|
||||
void AudioDriverPulseAudio::finish() {
|
||||
|
||||
if (!thread)
|
||||
if (!thread.is_started())
|
||||
return;
|
||||
|
||||
exit_thread = true;
|
||||
Thread::wait_to_finish(thread);
|
||||
thread.wait_to_finish();
|
||||
|
||||
finish_device();
|
||||
|
||||
|
@ -641,14 +636,6 @@ void AudioDriverPulseAudio::finish() {
|
|||
pa_mainloop_free(pa_ml);
|
||||
pa_ml = NULL;
|
||||
}
|
||||
|
||||
memdelete(thread);
|
||||
if (mutex) {
|
||||
memdelete(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
|
||||
thread = NULL;
|
||||
}
|
||||
|
||||
Error AudioDriverPulseAudio::capture_init_device() {
|
||||
|
@ -802,8 +789,6 @@ String AudioDriverPulseAudio::capture_get_device() {
|
|||
}
|
||||
|
||||
AudioDriverPulseAudio::AudioDriverPulseAudio() :
|
||||
thread(NULL),
|
||||
mutex(NULL),
|
||||
pa_ml(NULL),
|
||||
pa_ctx(NULL),
|
||||
pa_str(NULL),
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
|
||||
class AudioDriverPulseAudio : public AudioDriver {
|
||||
|
||||
Thread *thread;
|
||||
Mutex *mutex;
|
||||
Thread thread;
|
||||
Mutex mutex;
|
||||
|
||||
pa_mainloop *pa_ml;
|
||||
pa_context *pa_ctx;
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* mutex_posix.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "mutex_posix.h"
|
||||
|
||||
#include "core/os/memory.h"
|
||||
|
||||
#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
|
||||
|
||||
void MutexPosix::lock() {
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
void MutexPosix::unlock() {
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
Error MutexPosix::try_lock() {
|
||||
|
||||
return (pthread_mutex_trylock(&mutex) == 0) ? OK : ERR_BUSY;
|
||||
}
|
||||
|
||||
Mutex *MutexPosix::create_func_posix(bool p_recursive) {
|
||||
|
||||
return memnew(MutexPosix(p_recursive));
|
||||
}
|
||||
|
||||
void MutexPosix::make_default() {
|
||||
|
||||
create_func = create_func_posix;
|
||||
}
|
||||
|
||||
MutexPosix::MutexPosix(bool p_recursive) {
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
if (p_recursive)
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mutex, &attr);
|
||||
}
|
||||
|
||||
MutexPosix::~MutexPosix() {
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,61 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* mutex_posix.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MUTEX_POSIX_H
|
||||
#define MUTEX_POSIX_H
|
||||
|
||||
#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
class MutexPosix : public Mutex {
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
static Mutex *create_func_posix(bool p_recursive);
|
||||
|
||||
public:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
virtual Error try_lock();
|
||||
|
||||
static void make_default();
|
||||
|
||||
MutexPosix(bool p_recursive);
|
||||
|
||||
~MutexPosix();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -32,14 +32,10 @@
|
|||
|
||||
#ifdef UNIX_ENABLED
|
||||
|
||||
#include "core/os/thread_dummy.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "drivers/unix/dir_access_unix.h"
|
||||
#include "drivers/unix/file_access_unix.h"
|
||||
#include "drivers/unix/mutex_posix.h"
|
||||
#include "drivers/unix/net_socket_posix.h"
|
||||
#include "drivers/unix/rw_lock_posix.h"
|
||||
#include "drivers/unix/semaphore_posix.h"
|
||||
#include "drivers/unix/thread_posix.h"
|
||||
#include "servers/visual_server.h"
|
||||
|
||||
|
@ -64,6 +60,7 @@
|
|||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/// Clock Setup function (used by get_ticks_usec)
|
||||
|
@ -120,19 +117,10 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) {
|
|||
|
||||
void OS_Unix::initialize_core() {
|
||||
|
||||
#ifdef NO_THREADS
|
||||
ThreadDummy::make_default();
|
||||
SemaphoreDummy::make_default();
|
||||
MutexDummy::make_default();
|
||||
RWLockDummy::make_default();
|
||||
#else
|
||||
ThreadPosix::make_default();
|
||||
#if !defined(OSX_ENABLED) && !defined(IPHONE_ENABLED)
|
||||
SemaphorePosix::make_default();
|
||||
#endif
|
||||
MutexPosix::make_default();
|
||||
RWLockPosix::make_default();
|
||||
#if !defined(NO_THREADS)
|
||||
init_thread_posix();
|
||||
#endif
|
||||
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
|
||||
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
|
||||
|
@ -310,13 +298,9 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo
|
|||
|
||||
while (fgets(buf, 65535, f)) {
|
||||
|
||||
if (p_pipe_mutex) {
|
||||
p_pipe_mutex->lock();
|
||||
}
|
||||
p_pipe_mutex->lock();
|
||||
(*r_pipe) += String::utf8(buf);
|
||||
if (p_pipe_mutex) {
|
||||
p_pipe_mutex->unlock();
|
||||
}
|
||||
p_pipe_mutex->unlock();
|
||||
}
|
||||
int rv = pclose(f);
|
||||
if (r_exitcode)
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* rw_lock_posix.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
|
||||
|
||||
#include "rw_lock_posix.h"
|
||||
|
||||
#include "core/error_macros.h"
|
||||
#include "core/os/memory.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void RWLockPosix::read_lock() {
|
||||
|
||||
int err = pthread_rwlock_rdlock(&rwlock);
|
||||
if (err != 0) {
|
||||
perror("Acquiring lock failed");
|
||||
}
|
||||
ERR_FAIL_COND(err != 0);
|
||||
}
|
||||
|
||||
void RWLockPosix::read_unlock() {
|
||||
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
}
|
||||
|
||||
Error RWLockPosix::read_try_lock() {
|
||||
|
||||
if (pthread_rwlock_tryrdlock(&rwlock) != 0) {
|
||||
return ERR_BUSY;
|
||||
} else {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
void RWLockPosix::write_lock() {
|
||||
|
||||
int err = pthread_rwlock_wrlock(&rwlock);
|
||||
ERR_FAIL_COND(err != 0);
|
||||
}
|
||||
|
||||
void RWLockPosix::write_unlock() {
|
||||
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
}
|
||||
|
||||
Error RWLockPosix::write_try_lock() {
|
||||
if (pthread_rwlock_trywrlock(&rwlock) != 0) {
|
||||
return ERR_BUSY;
|
||||
} else {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
RWLock *RWLockPosix::create_func_posix() {
|
||||
|
||||
return memnew(RWLockPosix);
|
||||
}
|
||||
|
||||
void RWLockPosix::make_default() {
|
||||
|
||||
create_func = create_func_posix;
|
||||
}
|
||||
|
||||
RWLockPosix::RWLockPosix() {
|
||||
|
||||
//rwlock=PTHREAD_RWLOCK_INITIALIZER; fails on OSX
|
||||
pthread_rwlock_init(&rwlock, NULL);
|
||||
}
|
||||
|
||||
RWLockPosix::~RWLockPosix() {
|
||||
|
||||
pthread_rwlock_destroy(&rwlock);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* rw_lock_posix.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef RWLOCKPOSIX_H
|
||||
#define RWLOCKPOSIX_H
|
||||
|
||||
#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
|
||||
|
||||
#include "core/os/rw_lock.h"
|
||||
#include <pthread.h>
|
||||
|
||||
class RWLockPosix : public RWLock {
|
||||
|
||||
pthread_rwlock_t rwlock;
|
||||
|
||||
static RWLock *create_func_posix();
|
||||
|
||||
public:
|
||||
virtual void read_lock();
|
||||
virtual void read_unlock();
|
||||
virtual Error read_try_lock();
|
||||
|
||||
virtual void write_lock();
|
||||
virtual void write_unlock();
|
||||
virtual Error write_try_lock();
|
||||
|
||||
static void make_default();
|
||||
|
||||
RWLockPosix();
|
||||
|
||||
~RWLockPosix();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // RWLOCKPOSIX_H
|
|
@ -1,87 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* semaphore_posix.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "semaphore_posix.h"
|
||||
|
||||
#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(OSX_ENABLED) && !defined(IPHONE_ENABLED)
|
||||
|
||||
#include "core/os/memory.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Error SemaphorePosix::wait() {
|
||||
|
||||
while (sem_wait(&sem)) {
|
||||
if (errno == EINTR) {
|
||||
errno = 0;
|
||||
continue;
|
||||
} else {
|
||||
perror("sem waiting");
|
||||
return ERR_BUSY;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error SemaphorePosix::post() {
|
||||
|
||||
return (sem_post(&sem) == 0) ? OK : ERR_BUSY;
|
||||
}
|
||||
int SemaphorePosix::get() const {
|
||||
|
||||
int val;
|
||||
sem_getvalue(&sem, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
Semaphore *SemaphorePosix::create_semaphore_posix() {
|
||||
|
||||
return memnew(SemaphorePosix);
|
||||
}
|
||||
|
||||
void SemaphorePosix::make_default() {
|
||||
|
||||
create_func = create_semaphore_posix;
|
||||
}
|
||||
|
||||
SemaphorePosix::SemaphorePosix() {
|
||||
|
||||
int r = sem_init(&sem, 0, 0);
|
||||
if (r != 0)
|
||||
perror("sem creating");
|
||||
}
|
||||
|
||||
SemaphorePosix::~SemaphorePosix() {
|
||||
|
||||
sem_destroy(&sem);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* semaphore_posix.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef SEMAPHORE_POSIX_H
|
||||
#define SEMAPHORE_POSIX_H
|
||||
|
||||
#include "core/os/semaphore.h"
|
||||
|
||||
#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(OSX_ENABLED) && !defined(IPHONE_ENABLED)
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
class SemaphorePosix : public Semaphore {
|
||||
|
||||
mutable sem_t sem;
|
||||
|
||||
static Semaphore *create_semaphore_posix();
|
||||
|
||||
public:
|
||||
virtual Error wait();
|
||||
virtual Error post();
|
||||
virtual int get() const;
|
||||
|
||||
static void make_default();
|
||||
SemaphorePosix();
|
||||
|
||||
~SemaphorePosix();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -28,92 +28,14 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "thread_posix.h"
|
||||
|
||||
#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS)
|
||||
|
||||
#include "core/os/memory.h"
|
||||
#include "core/safe_refcount.h"
|
||||
#include "core/script_language.h"
|
||||
#include "thread_posix.h"
|
||||
|
||||
#ifdef PTHREAD_BSD_SET_NAME
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
static void _thread_id_key_destr_callback(void *p_value) {
|
||||
memdelete(static_cast<Thread::ID *>(p_value));
|
||||
}
|
||||
|
||||
static pthread_key_t _create_thread_id_key() {
|
||||
pthread_key_t key;
|
||||
pthread_key_create(&key, &_thread_id_key_destr_callback);
|
||||
return key;
|
||||
}
|
||||
|
||||
pthread_key_t ThreadPosix::thread_id_key = _create_thread_id_key();
|
||||
Thread::ID ThreadPosix::next_thread_id = 0;
|
||||
|
||||
Thread::ID ThreadPosix::get_id() const {
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Thread *ThreadPosix::create_thread_posix() {
|
||||
|
||||
return memnew(ThreadPosix);
|
||||
}
|
||||
|
||||
void *ThreadPosix::thread_callback(void *userdata) {
|
||||
|
||||
ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata);
|
||||
t->id = atomic_increment(&next_thread_id);
|
||||
pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id)));
|
||||
|
||||
ScriptServer::thread_enter(); //scripts may need to attach a stack
|
||||
|
||||
t->callback(t->user);
|
||||
|
||||
ScriptServer::thread_exit();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
|
||||
|
||||
ThreadPosix *tr = memnew(ThreadPosix);
|
||||
tr->callback = p_callback;
|
||||
tr->user = p_user;
|
||||
pthread_attr_init(&tr->pthread_attr);
|
||||
pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE);
|
||||
pthread_attr_setstacksize(&tr->pthread_attr, 256 * 1024);
|
||||
|
||||
pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr);
|
||||
|
||||
return tr;
|
||||
}
|
||||
Thread::ID ThreadPosix::get_thread_id_func_posix() {
|
||||
|
||||
void *value = pthread_getspecific(thread_id_key);
|
||||
|
||||
if (value)
|
||||
return *static_cast<ID *>(value);
|
||||
|
||||
ID new_id = atomic_increment(&next_thread_id);
|
||||
pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id)));
|
||||
return new_id;
|
||||
}
|
||||
void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) {
|
||||
|
||||
ThreadPosix *tp = static_cast<ThreadPosix *>(p_thread);
|
||||
ERR_FAIL_COND(!tp);
|
||||
ERR_FAIL_COND(tp->pthread == 0);
|
||||
|
||||
pthread_join(tp->pthread, NULL);
|
||||
tp->pthread = 0;
|
||||
}
|
||||
|
||||
Error ThreadPosix::set_name_func_posix(const String &p_name) {
|
||||
#include "core/os/thread.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
static Error set_name(const String &p_name) {
|
||||
#ifdef PTHREAD_NO_RENAME
|
||||
return ERR_UNAVAILABLE;
|
||||
|
||||
|
@ -141,22 +63,10 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) {
|
|||
return err == 0 ? OK : ERR_INVALID_PARAMETER;
|
||||
|
||||
#endif // PTHREAD_NO_RENAME
|
||||
};
|
||||
|
||||
void ThreadPosix::make_default() {
|
||||
|
||||
create_func = create_func_posix;
|
||||
get_thread_id_func = get_thread_id_func_posix;
|
||||
wait_to_finish_func = wait_to_finish_func_posix;
|
||||
set_name_func = set_name_func_posix;
|
||||
}
|
||||
|
||||
ThreadPosix::ThreadPosix() {
|
||||
|
||||
pthread = 0;
|
||||
}
|
||||
|
||||
ThreadPosix::~ThreadPosix() {
|
||||
void init_thread_posix() {
|
||||
Thread::_set_platform_funcs(&set_name, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,43 +31,8 @@
|
|||
#ifndef THREAD_POSIX_H
|
||||
#define THREAD_POSIX_H
|
||||
|
||||
#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS)
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
class ThreadPosix : public Thread {
|
||||
|
||||
static pthread_key_t thread_id_key;
|
||||
static ID next_thread_id;
|
||||
|
||||
pthread_t pthread;
|
||||
pthread_attr_t pthread_attr;
|
||||
ThreadCreateCallback callback;
|
||||
void *user;
|
||||
ID id;
|
||||
|
||||
static Thread *create_thread_posix();
|
||||
|
||||
static void *thread_callback(void *userdata);
|
||||
|
||||
static Thread *create_func_posix(ThreadCreateCallback p_callback, void *, const Settings &);
|
||||
static ID get_thread_id_func_posix();
|
||||
static void wait_to_finish_func_posix(Thread *p_thread);
|
||||
|
||||
static Error set_name_func_posix(const String &p_name);
|
||||
|
||||
ThreadPosix();
|
||||
|
||||
public:
|
||||
virtual ID get_id() const;
|
||||
|
||||
static void make_default();
|
||||
|
||||
~ThreadPosix();
|
||||
};
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
void init_thread_posix();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -406,8 +406,7 @@ Error AudioDriverWASAPI::init() {
|
|||
exit_thread = false;
|
||||
thread_exited = false;
|
||||
|
||||
mutex = Mutex::create(true);
|
||||
thread = Thread::create(thread_func, this);
|
||||
thread.start(thread_func, this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -782,33 +781,21 @@ void AudioDriverWASAPI::start() {
|
|||
|
||||
void AudioDriverWASAPI::lock() {
|
||||
|
||||
if (mutex)
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void AudioDriverWASAPI::unlock() {
|
||||
|
||||
if (mutex)
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void AudioDriverWASAPI::finish() {
|
||||
|
||||
if (thread) {
|
||||
exit_thread = true;
|
||||
Thread::wait_to_finish(thread);
|
||||
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
}
|
||||
exit_thread = true;
|
||||
thread.wait_to_finish();
|
||||
|
||||
finish_capture_device();
|
||||
finish_render_device();
|
||||
|
||||
if (mutex) {
|
||||
memdelete(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Error AudioDriverWASAPI::capture_start() {
|
||||
|
@ -863,9 +850,6 @@ String AudioDriverWASAPI::capture_get_device() {
|
|||
|
||||
AudioDriverWASAPI::AudioDriverWASAPI() {
|
||||
|
||||
mutex = NULL;
|
||||
thread = NULL;
|
||||
|
||||
samples_in.clear();
|
||||
|
||||
channels = 0;
|
||||
|
|
|
@ -75,8 +75,8 @@ class AudioDriverWASAPI : public AudioDriver {
|
|||
AudioDeviceWASAPI audio_input;
|
||||
AudioDeviceWASAPI audio_output;
|
||||
|
||||
Mutex *mutex;
|
||||
Thread *thread;
|
||||
Mutex mutex;
|
||||
Thread thread;
|
||||
|
||||
Vector<int32_t> samples_in;
|
||||
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* mutex_windows.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "mutex_windows.h"
|
||||
|
||||
#include "core/os/memory.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
void MutexWindows::lock() {
|
||||
|
||||
#ifdef WINDOWS_USE_MUTEX
|
||||
WaitForSingleObject(mutex, INFINITE);
|
||||
#else
|
||||
EnterCriticalSection(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MutexWindows::unlock() {
|
||||
|
||||
#ifdef WINDOWS_USE_MUTEX
|
||||
ReleaseMutex(mutex);
|
||||
#else
|
||||
LeaveCriticalSection(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
Error MutexWindows::try_lock() {
|
||||
|
||||
#ifdef WINDOWS_USE_MUTEX
|
||||
return (WaitForSingleObject(mutex, 0) == WAIT_TIMEOUT) ? ERR_BUSY : OK;
|
||||
#else
|
||||
|
||||
if (TryEnterCriticalSection(&mutex))
|
||||
return OK;
|
||||
else
|
||||
return ERR_BUSY;
|
||||
#endif
|
||||
}
|
||||
|
||||
Mutex *MutexWindows::create_func_windows(bool p_recursive) {
|
||||
|
||||
return memnew(MutexWindows);
|
||||
}
|
||||
|
||||
void MutexWindows::make_default() {
|
||||
|
||||
create_func = create_func_windows;
|
||||
}
|
||||
|
||||
MutexWindows::MutexWindows() {
|
||||
|
||||
#ifdef WINDOWS_USE_MUTEX
|
||||
mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
#else
|
||||
#ifdef UWP_ENABLED
|
||||
InitializeCriticalSectionEx(&mutex, 0, 0);
|
||||
#else
|
||||
InitializeCriticalSection(&mutex);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
MutexWindows::~MutexWindows() {
|
||||
|
||||
#ifdef WINDOWS_USE_MUTEX
|
||||
CloseHandle(mutex);
|
||||
#else
|
||||
|
||||
DeleteCriticalSection(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* mutex_windows.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MUTEX_WINDOWS_H
|
||||
#define MUTEX_WINDOWS_H
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class MutexWindows : public Mutex {
|
||||
|
||||
#ifdef WINDOWS_USE_MUTEX
|
||||
HANDLE mutex;
|
||||
#else
|
||||
CRITICAL_SECTION mutex;
|
||||
#endif
|
||||
|
||||
static Mutex *create_func_windows(bool p_recursive);
|
||||
|
||||
public:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
virtual Error try_lock();
|
||||
|
||||
static void make_default();
|
||||
|
||||
MutexWindows();
|
||||
~MutexWindows();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,95 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* rw_lock_windows.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
|
||||
#include "rw_lock_windows.h"
|
||||
|
||||
#include "core/error_macros.h"
|
||||
#include "core/os/memory.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void RWLockWindows::read_lock() {
|
||||
|
||||
AcquireSRWLockShared(&lock);
|
||||
}
|
||||
|
||||
void RWLockWindows::read_unlock() {
|
||||
|
||||
ReleaseSRWLockShared(&lock);
|
||||
}
|
||||
|
||||
Error RWLockWindows::read_try_lock() {
|
||||
|
||||
if (TryAcquireSRWLockShared(&lock) == 0) {
|
||||
return ERR_BUSY;
|
||||
} else {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
void RWLockWindows::write_lock() {
|
||||
|
||||
AcquireSRWLockExclusive(&lock);
|
||||
}
|
||||
|
||||
void RWLockWindows::write_unlock() {
|
||||
|
||||
ReleaseSRWLockExclusive(&lock);
|
||||
}
|
||||
|
||||
Error RWLockWindows::write_try_lock() {
|
||||
if (TryAcquireSRWLockExclusive(&lock) == 0) {
|
||||
return ERR_BUSY;
|
||||
} else {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
RWLock *RWLockWindows::create_func_windows() {
|
||||
|
||||
return memnew(RWLockWindows);
|
||||
}
|
||||
|
||||
void RWLockWindows::make_default() {
|
||||
|
||||
create_func = create_func_windows;
|
||||
}
|
||||
|
||||
RWLockWindows::RWLockWindows() {
|
||||
|
||||
InitializeSRWLock(&lock);
|
||||
}
|
||||
|
||||
RWLockWindows::~RWLockWindows() {
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,64 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* rw_lock_windows.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef RWLOCKWINDOWS_H
|
||||
#define RWLOCKWINDOWS_H
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
|
||||
#include "core/os/rw_lock.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class RWLockWindows : public RWLock {
|
||||
|
||||
SRWLOCK lock;
|
||||
|
||||
static RWLock *create_func_windows();
|
||||
|
||||
public:
|
||||
virtual void read_lock();
|
||||
virtual void read_unlock();
|
||||
virtual Error read_try_lock();
|
||||
|
||||
virtual void write_lock();
|
||||
virtual void write_unlock();
|
||||
virtual Error write_try_lock();
|
||||
|
||||
static void make_default();
|
||||
|
||||
RWLockWindows();
|
||||
|
||||
~RWLockWindows();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // RWLOCKWINDOWS_H
|
|
@ -1,98 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* semaphore_windows.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "semaphore_windows.h"
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
|
||||
#include "core/os/memory.h"
|
||||
|
||||
Error SemaphoreWindows::wait() {
|
||||
|
||||
WaitForSingleObjectEx(semaphore, INFINITE, false);
|
||||
return OK;
|
||||
}
|
||||
Error SemaphoreWindows::post() {
|
||||
|
||||
ReleaseSemaphore(semaphore, 1, NULL);
|
||||
return OK;
|
||||
}
|
||||
int SemaphoreWindows::get() const {
|
||||
long previous;
|
||||
switch (WaitForSingleObjectEx(semaphore, 0, false)) {
|
||||
case WAIT_OBJECT_0: {
|
||||
ERR_FAIL_COND_V(!ReleaseSemaphore(semaphore, 1, &previous), -1);
|
||||
return previous + 1;
|
||||
} break;
|
||||
case WAIT_TIMEOUT: {
|
||||
return 0;
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_V(-1);
|
||||
}
|
||||
|
||||
Semaphore *SemaphoreWindows::create_semaphore_windows() {
|
||||
|
||||
return memnew(SemaphoreWindows);
|
||||
}
|
||||
|
||||
void SemaphoreWindows::make_default() {
|
||||
|
||||
create_func = create_semaphore_windows;
|
||||
}
|
||||
|
||||
SemaphoreWindows::SemaphoreWindows() {
|
||||
|
||||
#ifdef UWP_ENABLED
|
||||
semaphore = CreateSemaphoreEx(
|
||||
NULL,
|
||||
0,
|
||||
0xFFFFFFF, //wathever
|
||||
NULL,
|
||||
0,
|
||||
SEMAPHORE_ALL_ACCESS);
|
||||
#else
|
||||
semaphore = CreateSemaphore(
|
||||
NULL,
|
||||
0,
|
||||
0xFFFFFFF, //wathever
|
||||
NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
SemaphoreWindows::~SemaphoreWindows() {
|
||||
|
||||
CloseHandle(semaphore);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* semaphore_windows.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef SEMAPHORE_WINDOWS_H
|
||||
#define SEMAPHORE_WINDOWS_H
|
||||
|
||||
#include "core/os/semaphore.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class SemaphoreWindows : public Semaphore {
|
||||
|
||||
mutable HANDLE semaphore;
|
||||
|
||||
static Semaphore *create_semaphore_windows();
|
||||
|
||||
public:
|
||||
virtual Error wait();
|
||||
virtual Error post();
|
||||
virtual int get() const;
|
||||
|
||||
static void make_default();
|
||||
SemaphoreWindows();
|
||||
|
||||
~SemaphoreWindows();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* thread_windows.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "thread_windows.h"
|
||||
|
||||
#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED)
|
||||
|
||||
#include "core/os/memory.h"
|
||||
|
||||
Thread::ID ThreadWindows::get_id() const {
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Thread *ThreadWindows::create_thread_windows() {
|
||||
|
||||
return memnew(ThreadWindows);
|
||||
}
|
||||
|
||||
DWORD ThreadWindows::thread_callback(LPVOID userdata) {
|
||||
|
||||
ThreadWindows *t = reinterpret_cast<ThreadWindows *>(userdata);
|
||||
|
||||
ScriptServer::thread_enter(); //scripts may need to attach a stack
|
||||
|
||||
t->id = (ID)GetCurrentThreadId(); // must implement
|
||||
t->callback(t->user);
|
||||
SetEvent(t->handle);
|
||||
|
||||
ScriptServer::thread_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
|
||||
|
||||
ThreadWindows *tr = memnew(ThreadWindows);
|
||||
tr->callback = p_callback;
|
||||
tr->user = p_user;
|
||||
tr->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
QueueUserWorkItem(thread_callback, tr, WT_EXECUTELONGFUNCTION);
|
||||
|
||||
return tr;
|
||||
}
|
||||
Thread::ID ThreadWindows::get_thread_id_func_windows() {
|
||||
|
||||
return (ID)GetCurrentThreadId(); //must implement
|
||||
}
|
||||
void ThreadWindows::wait_to_finish_func_windows(Thread *p_thread) {
|
||||
|
||||
ThreadWindows *tp = static_cast<ThreadWindows *>(p_thread);
|
||||
ERR_FAIL_COND(!tp);
|
||||
WaitForSingleObject(tp->handle, INFINITE);
|
||||
CloseHandle(tp->handle);
|
||||
//`memdelete(tp);
|
||||
}
|
||||
|
||||
void ThreadWindows::make_default() {
|
||||
|
||||
create_func = create_func_windows;
|
||||
get_thread_id_func = get_thread_id_func_windows;
|
||||
wait_to_finish_func = wait_to_finish_func_windows;
|
||||
}
|
||||
|
||||
ThreadWindows::ThreadWindows() :
|
||||
handle(NULL) {
|
||||
}
|
||||
|
||||
ThreadWindows::~ThreadWindows() {
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,68 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* thread_windows.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef THREAD_WINDOWS_H
|
||||
#define THREAD_WINDOWS_H
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "core/script_language.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class ThreadWindows : public Thread {
|
||||
|
||||
ThreadCreateCallback callback;
|
||||
void *user;
|
||||
ID id;
|
||||
HANDLE handle;
|
||||
|
||||
static Thread *create_thread_windows();
|
||||
|
||||
static DWORD WINAPI thread_callback(LPVOID userdata);
|
||||
|
||||
static Thread *create_func_windows(ThreadCreateCallback p_callback, void *, const Settings &);
|
||||
static ID get_thread_id_func_windows();
|
||||
static void wait_to_finish_func_windows(Thread *p_thread);
|
||||
|
||||
ThreadWindows();
|
||||
|
||||
public:
|
||||
virtual ID get_id() const;
|
||||
|
||||
static void make_default();
|
||||
|
||||
~ThreadWindows();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -79,8 +79,7 @@ Error AudioDriverXAudio2::init() {
|
|||
hr = xaudio->CreateSourceVoice(&source_voice, &wave_format, 0, XAUDIO2_MAX_FREQ_RATIO, &voice_callback);
|
||||
ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 source voice. Error code: " + itos(hr) + ".");
|
||||
|
||||
mutex = Mutex::create();
|
||||
thread = Thread::create(AudioDriverXAudio2::thread_func, this);
|
||||
thread.start(AudioDriverXAudio2::thread_func, this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -158,24 +157,20 @@ float AudioDriverXAudio2::get_latency() {
|
|||
|
||||
void AudioDriverXAudio2::lock() {
|
||||
|
||||
if (!thread || !mutex)
|
||||
return;
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
}
|
||||
void AudioDriverXAudio2::unlock() {
|
||||
|
||||
if (!thread || !mutex)
|
||||
return;
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void AudioDriverXAudio2::finish() {
|
||||
|
||||
if (!thread)
|
||||
if (!thread.is_started())
|
||||
return;
|
||||
|
||||
exit_thread = true;
|
||||
Thread::wait_to_finish(thread);
|
||||
thread.wait_to_finish();
|
||||
|
||||
if (source_voice) {
|
||||
source_voice->Stop(0);
|
||||
|
@ -192,16 +187,9 @@ void AudioDriverXAudio2::finish() {
|
|||
}
|
||||
|
||||
mastering_voice->DestroyVoice();
|
||||
|
||||
memdelete(thread);
|
||||
if (mutex)
|
||||
memdelete(mutex);
|
||||
thread = NULL;
|
||||
}
|
||||
|
||||
AudioDriverXAudio2::AudioDriverXAudio2() :
|
||||
thread(NULL),
|
||||
mutex(NULL),
|
||||
current_buffer(0) {
|
||||
wave_format = { 0 };
|
||||
for (int i = 0; i < AUDIO_BUFFERS; i++) {
|
||||
|
|
|
@ -64,8 +64,8 @@ class AudioDriverXAudio2 : public AudioDriver {
|
|||
void STDMETHODCALLTYPE OnVoiceError(void *pBufferContext, HRESULT Error) {}
|
||||
};
|
||||
|
||||
Thread *thread;
|
||||
Mutex *mutex;
|
||||
Thread thread;
|
||||
Mutex mutex;
|
||||
|
||||
int32_t *samples_in;
|
||||
int16_t *samples_out[AUDIO_BUFFERS];
|
||||
|
|
|
@ -158,7 +158,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) {
|
|||
|
||||
preview->playback->stop();
|
||||
|
||||
preview->generating = false;
|
||||
preview->generating.clear();
|
||||
}
|
||||
|
||||
Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<AudioStream> &p_stream) {
|
||||
|
@ -175,7 +175,7 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
|
|||
Preview *preview = &previews[p_stream->get_instance_id()];
|
||||
preview->base_stream = p_stream;
|
||||
preview->playback = preview->base_stream->instance_playback();
|
||||
preview->generating = true;
|
||||
preview->generating.set();
|
||||
preview->id = p_stream->get_instance_id();
|
||||
|
||||
float len_s = preview->base_stream->get_length();
|
||||
|
@ -199,8 +199,10 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
|
|||
preview->preview->preview = maxmin;
|
||||
preview->preview->length = len_s;
|
||||
|
||||
if (preview->playback.is_valid())
|
||||
preview->thread = Thread::create(_preview_thread, preview);
|
||||
if (preview->playback.is_valid()) {
|
||||
preview->thread = memnew(Thread);
|
||||
preview->thread->start(_preview_thread, preview);
|
||||
}
|
||||
|
||||
return preview->preview;
|
||||
}
|
||||
|
@ -218,9 +220,10 @@ void AudioStreamPreviewGenerator::_notification(int p_what) {
|
|||
if (p_what == NOTIFICATION_PROCESS) {
|
||||
List<ObjectID> to_erase;
|
||||
for (Map<ObjectID, Preview>::Element *E = previews.front(); E; E = E->next()) {
|
||||
if (!E->get().generating) {
|
||||
if (!E->get().generating.is_set()) {
|
||||
if (E->get().thread) {
|
||||
Thread::wait_to_finish(E->get().thread);
|
||||
E->get().thread->wait_to_finish();
|
||||
memdelete(E->get().thread);
|
||||
E->get().thread = NULL;
|
||||
}
|
||||
if (!ObjectDB::get_instance(E->key())) { //no longer in use, get rid of preview
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define AUDIO_STREAM_PREVIEW_H
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "core/safe_refcount.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "servers/audio/audio_stream.h"
|
||||
|
||||
|
@ -60,9 +61,20 @@ class AudioStreamPreviewGenerator : public Node {
|
|||
Ref<AudioStreamPreview> preview;
|
||||
Ref<AudioStream> base_stream;
|
||||
Ref<AudioStreamPlayback> playback;
|
||||
volatile bool generating;
|
||||
SafeFlag generating;
|
||||
ObjectID id;
|
||||
Thread *thread;
|
||||
|
||||
// Needed for the bookkeeping of the Map
|
||||
Preview &operator=(const Preview &p_rhs) {
|
||||
preview = p_rhs.preview;
|
||||
base_stream = p_rhs.base_stream;
|
||||
playback = p_rhs.playback;
|
||||
generating.set_to(generating.is_set());
|
||||
id = p_rhs.id;
|
||||
thread = p_rhs.thread;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
Map<ObjectID, Preview> previews;
|
||||
|
|
|
@ -609,7 +609,7 @@ void EditorFileSystem::scan() {
|
|||
if (false /*&& bool(Globals::get_singleton()->get("debug/disable_scan"))*/)
|
||||
return;
|
||||
|
||||
if (scanning || scanning_changes || thread)
|
||||
if (scanning || scanning_changes || thread.is_started())
|
||||
return;
|
||||
|
||||
_update_extensions();
|
||||
|
@ -632,13 +632,13 @@ void EditorFileSystem::scan() {
|
|||
first_scan = false;
|
||||
} else {
|
||||
|
||||
ERR_FAIL_COND(thread);
|
||||
ERR_FAIL_COND(thread.is_started());
|
||||
set_process(true);
|
||||
Thread::Settings s;
|
||||
scanning = true;
|
||||
scan_total = 0;
|
||||
s.priority = Thread::PRIORITY_LOW;
|
||||
thread = Thread::create(_thread_func, this, s);
|
||||
thread.start(_thread_func, this, s);
|
||||
//tree->hide();
|
||||
//progress->show();
|
||||
}
|
||||
|
@ -1067,7 +1067,7 @@ void EditorFileSystem::get_changed_sources(List<String> *r_changed) {
|
|||
void EditorFileSystem::scan_changes() {
|
||||
|
||||
if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan
|
||||
scanning || scanning_changes || thread) {
|
||||
scanning || scanning_changes || thread.is_started()) {
|
||||
scan_changes_pending = true;
|
||||
set_process(true);
|
||||
return;
|
||||
|
@ -1097,12 +1097,12 @@ void EditorFileSystem::scan_changes() {
|
|||
emit_signal("sources_changed", sources_changed.size() > 0);
|
||||
} else {
|
||||
|
||||
ERR_FAIL_COND(thread_sources);
|
||||
ERR_FAIL_COND(thread_sources.is_started());
|
||||
set_process(true);
|
||||
scan_total = 0;
|
||||
Thread::Settings s;
|
||||
s.priority = Thread::PRIORITY_LOW;
|
||||
thread_sources = Thread::create(_thread_func_sources, this, s);
|
||||
thread_sources.start(_thread_func_sources, this, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1116,17 +1116,14 @@ void EditorFileSystem::_notification(int p_what) {
|
|||
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
Thread *active_thread = thread ? thread : thread_sources;
|
||||
if (use_threads && active_thread) {
|
||||
Thread &active_thread = thread.is_started() ? thread : thread_sources;
|
||||
if (use_threads && active_thread.is_started()) {
|
||||
//abort thread if in progress
|
||||
abort_scan = true;
|
||||
while (scanning) {
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
}
|
||||
Thread::wait_to_finish(active_thread);
|
||||
memdelete(active_thread);
|
||||
thread = NULL;
|
||||
thread_sources = NULL;
|
||||
active_thread.wait_to_finish();
|
||||
WARN_PRINT("Scan thread aborted...");
|
||||
set_process(false);
|
||||
}
|
||||
|
@ -1151,9 +1148,7 @@ void EditorFileSystem::_notification(int p_what) {
|
|||
|
||||
set_process(false);
|
||||
|
||||
Thread::wait_to_finish(thread_sources);
|
||||
memdelete(thread_sources);
|
||||
thread_sources = NULL;
|
||||
thread_sources.wait_to_finish();
|
||||
if (_update_scan_actions())
|
||||
emit_signal("filesystem_changed");
|
||||
emit_signal("sources_changed", sources_changed.size() > 0);
|
||||
|
@ -1168,9 +1163,7 @@ void EditorFileSystem::_notification(int p_what) {
|
|||
memdelete(filesystem);
|
||||
filesystem = new_filesystem;
|
||||
new_filesystem = NULL;
|
||||
Thread::wait_to_finish(thread);
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
thread.wait_to_finish();
|
||||
_update_scan_actions();
|
||||
emit_signal("filesystem_changed");
|
||||
emit_signal("sources_changed", sources_changed.size() > 0);
|
||||
|
@ -1452,10 +1445,10 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
|
|||
|
||||
void EditorFileSystem::update_script_classes() {
|
||||
|
||||
if (!update_script_classes_queued)
|
||||
if (!update_script_classes_queued.is_set())
|
||||
return;
|
||||
|
||||
update_script_classes_queued = false;
|
||||
update_script_classes_queued.clear();
|
||||
ScriptServer::global_classes_clear();
|
||||
if (get_filesystem()) {
|
||||
_scan_script_classes(get_filesystem());
|
||||
|
@ -1474,11 +1467,11 @@ void EditorFileSystem::update_script_classes() {
|
|||
}
|
||||
|
||||
void EditorFileSystem::_queue_update_script_classes() {
|
||||
if (update_script_classes_queued) {
|
||||
if (update_script_classes_queued.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_script_classes_queued = true;
|
||||
update_script_classes_queued.set();
|
||||
call_deferred("update_script_classes");
|
||||
}
|
||||
|
||||
|
@ -2135,11 +2128,9 @@ EditorFileSystem::EditorFileSystem() {
|
|||
filesystem = memnew(EditorFileSystemDirectory); //like, empty
|
||||
filesystem->parent = NULL;
|
||||
|
||||
thread = NULL;
|
||||
scanning = false;
|
||||
importing = false;
|
||||
use_threads = true;
|
||||
thread_sources = NULL;
|
||||
new_filesystem = NULL;
|
||||
|
||||
abort_scan = false;
|
||||
|
@ -2155,7 +2146,7 @@ EditorFileSystem::EditorFileSystem() {
|
|||
memdelete(da);
|
||||
|
||||
scan_total = 0;
|
||||
update_script_classes_queued = false;
|
||||
update_script_classes_queued.clear();
|
||||
first_scan = true;
|
||||
scan_changes_pending = false;
|
||||
revalidate_import_files = false;
|
||||
|
|
|
@ -34,8 +34,10 @@
|
|||
#include "core/os/dir_access.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "core/safe_refcount.h"
|
||||
#include "core/set.h"
|
||||
#include "scene/main/node.h"
|
||||
|
||||
class FileAccess;
|
||||
|
||||
struct EditorProgressBG;
|
||||
|
@ -136,7 +138,7 @@ class EditorFileSystem : public Node {
|
|||
};
|
||||
|
||||
bool use_threads;
|
||||
Thread *thread;
|
||||
Thread thread;
|
||||
static void _thread_func(void *_userdata);
|
||||
|
||||
EditorFileSystemDirectory *new_filesystem;
|
||||
|
@ -200,7 +202,7 @@ class EditorFileSystem : public Node {
|
|||
|
||||
void _scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess *da, const ScanProgress &p_progress);
|
||||
|
||||
Thread *thread_sources;
|
||||
Thread thread_sources;
|
||||
bool scanning_changes;
|
||||
bool scanning_changes_done;
|
||||
|
||||
|
@ -231,7 +233,7 @@ class EditorFileSystem : public Node {
|
|||
};
|
||||
|
||||
void _scan_script_classes(EditorFileSystemDirectory *p_dir);
|
||||
volatile bool update_script_classes_queued;
|
||||
SafeFlag update_script_classes_queued;
|
||||
void _queue_update_script_classes();
|
||||
|
||||
String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;
|
||||
|
|
|
@ -5735,13 +5735,13 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err
|
|||
static void _execute_thread(void *p_ud) {
|
||||
|
||||
EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud;
|
||||
Error err = OS::get_singleton()->execute(eta->path, eta->args, true, NULL, &eta->output, &eta->exitcode, true, eta->execute_output_mutex);
|
||||
Error err = OS::get_singleton()->execute(eta->path, eta->args, true, NULL, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
|
||||
print_verbose("Thread exit status: " + itos(eta->exitcode));
|
||||
if (err != OK) {
|
||||
eta->exitcode = err;
|
||||
}
|
||||
|
||||
eta->done = true;
|
||||
eta->done.set();
|
||||
}
|
||||
|
||||
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
|
||||
|
@ -5755,31 +5755,25 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
|
|||
ExecuteThreadArgs eta;
|
||||
eta.path = p_path;
|
||||
eta.args = p_arguments;
|
||||
eta.execute_output_mutex = Mutex::create();
|
||||
eta.exitcode = 255;
|
||||
eta.done = false;
|
||||
|
||||
int prev_len = 0;
|
||||
|
||||
eta.execute_output_thread = Thread::create(_execute_thread, &eta);
|
||||
eta.execute_output_thread.start(_execute_thread, &eta);
|
||||
|
||||
ERR_FAIL_COND_V(!eta.execute_output_thread, 0);
|
||||
|
||||
while (!eta.done) {
|
||||
eta.execute_output_mutex->lock();
|
||||
while (!eta.done.is_set()) {
|
||||
eta.execute_output_mutex.lock();
|
||||
if (prev_len != eta.output.length()) {
|
||||
String to_add = eta.output.substr(prev_len, eta.output.length());
|
||||
prev_len = eta.output.length();
|
||||
execute_outputs->add_text(to_add);
|
||||
Main::iteration();
|
||||
}
|
||||
eta.execute_output_mutex->unlock();
|
||||
eta.execute_output_mutex.unlock();
|
||||
OS::get_singleton()->delay_usec(1000);
|
||||
}
|
||||
|
||||
Thread::wait_to_finish(eta.execute_output_thread);
|
||||
memdelete(eta.execute_output_thread);
|
||||
memdelete(eta.execute_output_mutex);
|
||||
eta.execute_output_thread.wait_to_finish();
|
||||
execute_outputs->add_text("\nExit Code: " + itos(eta.exitcode));
|
||||
|
||||
if (p_close_on_errors && eta.exitcode != 0) {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef EDITOR_NODE_H
|
||||
#define EDITOR_NODE_H
|
||||
|
||||
#include "core/safe_refcount.h"
|
||||
#include "editor/editor_data.h"
|
||||
#include "editor/editor_folding.h"
|
||||
#include "editor/editor_run.h"
|
||||
|
@ -106,10 +107,10 @@ public:
|
|||
String path;
|
||||
List<String> args;
|
||||
String output;
|
||||
Thread *execute_output_thread;
|
||||
Mutex *execute_output_mutex;
|
||||
Thread execute_output_thread;
|
||||
Mutex execute_output_mutex;
|
||||
int exitcode;
|
||||
volatile bool done;
|
||||
SafeFlag done;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -109,7 +109,7 @@ void EditorResourcePreview::_thread_func(void *ud) {
|
|||
|
||||
void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture> &p_texture, const Ref<Texture> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
|
||||
|
||||
preview_mutex->lock();
|
||||
preview_mutex.lock();
|
||||
|
||||
String path = p_str;
|
||||
uint32_t hash = 0;
|
||||
|
@ -131,7 +131,7 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur
|
|||
|
||||
cache[path] = item;
|
||||
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
|
||||
MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_small_texture, p_ud);
|
||||
}
|
||||
|
@ -217,11 +217,11 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
|
|||
|
||||
void EditorResourcePreview::_thread() {
|
||||
|
||||
exited = false;
|
||||
while (!exit) {
|
||||
exited.clear();
|
||||
while (!exit.is_set()) {
|
||||
|
||||
preview_sem->wait();
|
||||
preview_mutex->lock();
|
||||
preview_sem.wait();
|
||||
preview_mutex.lock();
|
||||
|
||||
if (queue.size()) {
|
||||
|
||||
|
@ -237,10 +237,10 @@ void EditorResourcePreview::_thread() {
|
|||
|
||||
_preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
|
||||
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
} else {
|
||||
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
|
||||
Ref<ImageTexture> texture;
|
||||
Ref<ImageTexture> small_texture;
|
||||
|
@ -347,10 +347,10 @@ void EditorResourcePreview::_thread() {
|
|||
}
|
||||
|
||||
} else {
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
}
|
||||
}
|
||||
exited = true;
|
||||
exited.set();
|
||||
}
|
||||
|
||||
void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
|
||||
|
@ -358,7 +358,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
|
|||
ERR_FAIL_NULL(p_receiver);
|
||||
ERR_FAIL_COND(!p_res.is_valid());
|
||||
|
||||
preview_mutex->lock();
|
||||
preview_mutex.lock();
|
||||
|
||||
String path_id = "ID:" + itos(p_res->get_instance_id());
|
||||
|
||||
|
@ -366,7 +366,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
|
|||
|
||||
cache[path_id].order = order++;
|
||||
p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -380,18 +380,18 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
|
|||
item.userdata = p_userdata;
|
||||
|
||||
queue.push_back(item);
|
||||
preview_mutex->unlock();
|
||||
preview_sem->post();
|
||||
preview_mutex.unlock();
|
||||
preview_sem.post();
|
||||
}
|
||||
|
||||
void EditorResourcePreview::queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
|
||||
|
||||
ERR_FAIL_NULL(p_receiver);
|
||||
preview_mutex->lock();
|
||||
preview_mutex.lock();
|
||||
if (cache.has(p_path)) {
|
||||
cache[p_path].order = order++;
|
||||
p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -402,8 +402,8 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
|
|||
item.userdata = p_userdata;
|
||||
|
||||
queue.push_back(item);
|
||||
preview_mutex->unlock();
|
||||
preview_sem->post();
|
||||
preview_mutex.unlock();
|
||||
preview_sem.post();
|
||||
}
|
||||
|
||||
void EditorResourcePreview::add_preview_generator(const Ref<EditorResourcePreviewGenerator> &p_generator) {
|
||||
|
@ -436,7 +436,7 @@ void EditorResourcePreview::_bind_methods() {
|
|||
|
||||
void EditorResourcePreview::check_for_invalidation(const String &p_path) {
|
||||
|
||||
preview_mutex->lock();
|
||||
preview_mutex.lock();
|
||||
|
||||
bool call_invalidated = false;
|
||||
if (cache.has(p_path)) {
|
||||
|
@ -448,7 +448,7 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
|
|||
}
|
||||
}
|
||||
|
||||
preview_mutex->unlock();
|
||||
preview_mutex.unlock();
|
||||
|
||||
if (call_invalidated) { //do outside mutex
|
||||
call_deferred("emit_signal", "preview_invalidated", p_path);
|
||||
|
@ -456,37 +456,28 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
|
|||
}
|
||||
|
||||
void EditorResourcePreview::start() {
|
||||
ERR_FAIL_COND_MSG(thread, "Thread already started.");
|
||||
thread = Thread::create(_thread_func, this);
|
||||
ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
|
||||
thread.start(_thread_func, this);
|
||||
}
|
||||
|
||||
void EditorResourcePreview::stop() {
|
||||
if (thread) {
|
||||
exit = true;
|
||||
preview_sem->post();
|
||||
while (!exited) {
|
||||
if (thread.is_started()) {
|
||||
exit.set();
|
||||
preview_sem.post();
|
||||
while (!exited.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10000);
|
||||
VisualServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
|
||||
}
|
||||
Thread::wait_to_finish(thread);
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
}
|
||||
|
||||
EditorResourcePreview::EditorResourcePreview() {
|
||||
thread = NULL;
|
||||
singleton = this;
|
||||
preview_mutex = Mutex::create();
|
||||
preview_sem = Semaphore::create();
|
||||
order = 0;
|
||||
exit = false;
|
||||
exited = false;
|
||||
}
|
||||
|
||||
EditorResourcePreview::~EditorResourcePreview() {
|
||||
|
||||
stop();
|
||||
memdelete(preview_mutex);
|
||||
memdelete(preview_sem);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "core/os/semaphore.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/safe_refcount.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
|
@ -70,11 +71,11 @@ class EditorResourcePreview : public Node {
|
|||
|
||||
List<QueueItem> queue;
|
||||
|
||||
Mutex *preview_mutex;
|
||||
Semaphore *preview_sem;
|
||||
Thread *thread;
|
||||
volatile bool exit;
|
||||
volatile bool exited;
|
||||
Mutex preview_mutex;
|
||||
Semaphore preview_sem;
|
||||
Thread thread;
|
||||
SafeFlag exit;
|
||||
SafeFlag exited;
|
||||
|
||||
struct Item {
|
||||
Ref<Texture> preview;
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
void EditorFileServer::_close_client(ClientData *cd) {
|
||||
|
||||
cd->connection->disconnect_from_host();
|
||||
cd->efs->wait_mutex->lock();
|
||||
cd->efs->to_wait.insert(cd->thread);
|
||||
cd->efs->wait_mutex->unlock();
|
||||
cd->efs->wait_mutex.lock();
|
||||
cd->efs->to_wait.insert(&cd->thread);
|
||||
cd->efs->wait_mutex.unlock();
|
||||
while (cd->files.size()) {
|
||||
memdelete(cd->files.front()->get());
|
||||
cd->files.erase(cd->files.front());
|
||||
|
@ -291,20 +291,19 @@ void EditorFileServer::_thread_start(void *s) {
|
|||
cd->connection = self->server->take_connection();
|
||||
cd->efs = self;
|
||||
cd->quit = false;
|
||||
cd->thread = Thread::create(_subthread_start, cd);
|
||||
cd->thread.start(_subthread_start, cd);
|
||||
}
|
||||
}
|
||||
|
||||
self->wait_mutex->lock();
|
||||
self->wait_mutex.lock();
|
||||
while (self->to_wait.size()) {
|
||||
Thread *w = self->to_wait.front()->get();
|
||||
self->to_wait.erase(w);
|
||||
self->wait_mutex->unlock();
|
||||
Thread::wait_to_finish(w);
|
||||
memdelete(w);
|
||||
self->wait_mutex->lock();
|
||||
self->wait_mutex.unlock();
|
||||
w->wait_to_finish();
|
||||
self->wait_mutex.lock();
|
||||
}
|
||||
self->wait_mutex->unlock();
|
||||
self->wait_mutex.unlock();
|
||||
|
||||
OS::get_singleton()->delay_usec(100000);
|
||||
}
|
||||
|
@ -331,11 +330,10 @@ void EditorFileServer::stop() {
|
|||
EditorFileServer::EditorFileServer() {
|
||||
|
||||
server.instance();
|
||||
wait_mutex = Mutex::create();
|
||||
quit = false;
|
||||
active = false;
|
||||
cmd = CMD_NONE;
|
||||
thread = Thread::create(_thread_start, this);
|
||||
thread.start(_thread_start, this);
|
||||
|
||||
EDITOR_DEF("filesystem/file_server/port", 6010);
|
||||
EDITOR_DEF("filesystem/file_server/password", "");
|
||||
|
@ -344,7 +342,5 @@ EditorFileServer::EditorFileServer() {
|
|||
EditorFileServer::~EditorFileServer() {
|
||||
|
||||
quit = true;
|
||||
Thread::wait_to_finish(thread);
|
||||
memdelete(thread);
|
||||
memdelete(wait_mutex);
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class EditorFileServer : public Object {
|
|||
|
||||
struct ClientData {
|
||||
|
||||
Thread *thread;
|
||||
Thread thread;
|
||||
Ref<StreamPeerTCP> connection;
|
||||
Map<int, FileAccess *> files;
|
||||
EditorFileServer *efs;
|
||||
|
@ -62,8 +62,8 @@ class EditorFileServer : public Object {
|
|||
static void _close_client(ClientData *cd);
|
||||
static void _subthread_start(void *s);
|
||||
|
||||
Mutex *wait_mutex;
|
||||
Thread *thread;
|
||||
Mutex wait_mutex;
|
||||
Thread thread;
|
||||
static void _thread_start(void *);
|
||||
bool quit;
|
||||
Command cmd;
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
void ResourceImporterTexture::_texture_reimport_srgb(const Ref<StreamTexture> &p_tex) {
|
||||
|
||||
singleton->mutex->lock();
|
||||
singleton->mutex.lock();
|
||||
StringName path = p_tex->get_path();
|
||||
|
||||
if (!singleton->make_flags.has(path)) {
|
||||
|
@ -47,12 +47,12 @@ void ResourceImporterTexture::_texture_reimport_srgb(const Ref<StreamTexture> &p
|
|||
|
||||
singleton->make_flags[path] |= MAKE_SRGB_FLAG;
|
||||
|
||||
singleton->mutex->unlock();
|
||||
singleton->mutex.unlock();
|
||||
}
|
||||
|
||||
void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture> &p_tex) {
|
||||
|
||||
singleton->mutex->lock();
|
||||
singleton->mutex.lock();
|
||||
StringName path = p_tex->get_path();
|
||||
|
||||
if (!singleton->make_flags.has(path)) {
|
||||
|
@ -61,12 +61,12 @@ void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture> &p_t
|
|||
|
||||
singleton->make_flags[path] |= MAKE_3D_FLAG;
|
||||
|
||||
singleton->mutex->unlock();
|
||||
singleton->mutex.unlock();
|
||||
}
|
||||
|
||||
void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture> &p_tex) {
|
||||
|
||||
singleton->mutex->lock();
|
||||
singleton->mutex.lock();
|
||||
StringName path = p_tex->get_path();
|
||||
|
||||
if (!singleton->make_flags.has(path)) {
|
||||
|
@ -75,7 +75,7 @@ void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture>
|
|||
|
||||
singleton->make_flags[path] |= MAKE_NORMAL_FLAG;
|
||||
|
||||
singleton->mutex->unlock();
|
||||
singleton->mutex.unlock();
|
||||
}
|
||||
|
||||
void ResourceImporterTexture::update_imports() {
|
||||
|
@ -83,10 +83,10 @@ void ResourceImporterTexture::update_imports() {
|
|||
if (EditorFileSystem::get_singleton()->is_scanning() || EditorFileSystem::get_singleton()->is_importing()) {
|
||||
return; // do nothing for now
|
||||
}
|
||||
mutex->lock();
|
||||
mutex.lock();
|
||||
|
||||
if (make_flags.empty()) {
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ void ResourceImporterTexture::update_imports() {
|
|||
|
||||
make_flags.clear();
|
||||
|
||||
mutex->unlock();
|
||||
mutex.unlock();
|
||||
|
||||
if (to_reimport.size()) {
|
||||
EditorFileSystem::get_singleton()->reimport_files(to_reimport);
|
||||
|
@ -611,10 +611,4 @@ ResourceImporterTexture::ResourceImporterTexture() {
|
|||
StreamTexture::request_3d_callback = _texture_reimport_3d;
|
||||
StreamTexture::request_srgb_callback = _texture_reimport_srgb;
|
||||
StreamTexture::request_normal_callback = _texture_reimport_normal;
|
||||
mutex = Mutex::create();
|
||||
}
|
||||
|
||||
ResourceImporterTexture::~ResourceImporterTexture() {
|
||||
|
||||
memdelete(mutex);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ protected:
|
|||
MAKE_NORMAL_FLAG = 4
|
||||
};
|
||||
|
||||
Mutex *mutex;
|
||||
Mutex mutex;
|
||||
Map<StringName, int> make_flags;
|
||||
|
||||
static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex);
|
||||
|
@ -94,7 +94,6 @@ public:
|
|||
virtual String get_import_settings_string() const;
|
||||
|
||||
ResourceImporterTexture();
|
||||
~ResourceImporterTexture();
|
||||
};
|
||||
|
||||
#endif // RESOURCEIMPORTTEXTURE_H
|
||||
|
|
|
@ -308,7 +308,7 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
|
|||
|
||||
void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) {
|
||||
|
||||
preview_done = true;
|
||||
preview_done.set();
|
||||
}
|
||||
|
||||
void EditorMaterialPreviewPlugin::_bind_methods() {
|
||||
|
@ -336,10 +336,10 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size
|
|||
|
||||
VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
|
||||
|
||||
preview_done = false;
|
||||
preview_done.clear();
|
||||
VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
|
||||
|
||||
while (!preview_done) {
|
||||
while (!preview_done.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
}
|
||||
|
||||
|
@ -699,7 +699,7 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
|
|||
|
||||
void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) {
|
||||
|
||||
preview_done = true;
|
||||
preview_done.set();
|
||||
}
|
||||
|
||||
void EditorMeshPreviewPlugin::_bind_methods() {
|
||||
|
@ -737,10 +737,10 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p
|
|||
|
||||
VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
|
||||
|
||||
preview_done = false;
|
||||
preview_done.clear();
|
||||
VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
|
||||
|
||||
while (!preview_done) {
|
||||
while (!preview_done.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
}
|
||||
|
||||
|
@ -819,7 +819,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
|
|||
|
||||
void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) {
|
||||
|
||||
preview_done = true;
|
||||
preview_done.set();
|
||||
}
|
||||
|
||||
void EditorFontPreviewPlugin::_bind_methods() {
|
||||
|
@ -861,11 +861,11 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c
|
|||
|
||||
font->draw(canvas_item, pos, sampled_text);
|
||||
|
||||
preview_done = false;
|
||||
preview_done.clear();
|
||||
VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
|
||||
VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
|
||||
|
||||
while (!preview_done) {
|
||||
while (!preview_done.is_set()) {
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include "editor/editor_resource_preview.h"
|
||||
|
||||
#include "core/safe_refcount.h"
|
||||
|
||||
void post_process_preview(Ref<Image> p_image);
|
||||
|
||||
class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
|
@ -92,7 +94,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
|
|||
RID light2;
|
||||
RID light_instance2;
|
||||
RID camera;
|
||||
mutable volatile bool preview_done;
|
||||
mutable SafeFlag preview_done;
|
||||
|
||||
void _preview_done(const Variant &p_udata);
|
||||
|
||||
|
@ -137,7 +139,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
|
|||
RID light2;
|
||||
RID light_instance2;
|
||||
RID camera;
|
||||
mutable volatile bool preview_done;
|
||||
mutable SafeFlag preview_done;
|
||||
|
||||
void _preview_done(const Variant &p_udata);
|
||||
|
||||
|
@ -160,7 +162,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator {
|
|||
RID viewport_texture;
|
||||
RID canvas;
|
||||
RID canvas_item;
|
||||
mutable volatile bool preview_done;
|
||||
mutable SafeFlag preview_done;
|
||||
|
||||
void _preview_done(const Variant &p_udata);
|
||||
|
||||
|
|
|
@ -352,8 +352,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
engine = memnew(Engine);
|
||||
|
||||
ClassDB::init();
|
||||
|
||||
MAIN_PRINT("Main: Initialize CORE");
|
||||
|
||||
register_core_types();
|
||||
|
@ -361,8 +359,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
|
||||
MAIN_PRINT("Main: Initialize Globals");
|
||||
|
||||
Thread::_main_thread_id = Thread::get_caller_id();
|
||||
|
||||
globals = memnew(ProjectSettings);
|
||||
input_map = memnew(InputMap);
|
||||
|
||||
|
@ -1277,9 +1273,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
// Print engine name and version
|
||||
print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
if (p_main_tid_override) {
|
||||
Thread::_main_thread_id = p_main_tid_override;
|
||||
Thread::main_thread_id = p_main_tid_override;
|
||||
}
|
||||
#endif
|
||||
|
||||
Error err = OS::get_singleton()->initialize(video_mode, video_driver_idx, audio_driver_idx);
|
||||
if (err != OK) {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/os/os.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "core/print_string.h"
|
||||
#include "core/safe_refcount.h"
|
||||
|
||||
#include <ConvectionKernels.h>
|
||||
|
||||
|
@ -56,7 +57,7 @@ struct CVTTCompressionJobQueue {
|
|||
CVTTCompressionJobParams job_params;
|
||||
const CVTTCompressionRowTask *job_tasks;
|
||||
uint32_t num_tasks;
|
||||
uint32_t current_task;
|
||||
SafeNumeric<uint32_t> current_task;
|
||||
};
|
||||
|
||||
static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) {
|
||||
|
@ -131,7 +132,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const
|
|||
static void _digest_job_queue(void *p_job_queue) {
|
||||
CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue);
|
||||
|
||||
for (uint32_t next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) {
|
||||
for (uint32_t next_task = job_queue->current_task.increment(); next_task <= job_queue->num_tasks; next_task = job_queue->current_task.increment()) {
|
||||
_digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]);
|
||||
}
|
||||
}
|
||||
|
@ -263,16 +264,17 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS
|
|||
PoolVector<CVTTCompressionRowTask>::Read tasks_rb = tasks.read();
|
||||
|
||||
job_queue.job_tasks = &tasks_rb[0];
|
||||
job_queue.current_task = 0;
|
||||
job_queue.current_task.set(0);
|
||||
job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
|
||||
|
||||
for (int i = 0; i < num_job_threads; i++) {
|
||||
threads_wb[i] = Thread::create(_digest_job_queue, &job_queue);
|
||||
threads_wb[i] = memnew(Thread);
|
||||
threads_wb[i]->start(_digest_job_queue, &job_queue);
|
||||
}
|
||||
_digest_job_queue(&job_queue);
|
||||
|
||||
for (int i = 0; i < num_job_threads; i++) {
|
||||
Thread::wait_to_finish(threads_wb[i]);
|
||||
threads_wb[i]->wait_to_finish();
|
||||
memdelete(threads_wb[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ extern "C" {
|
|||
|
||||
JNIEnv *GDAPI godot_android_get_env() {
|
||||
#ifdef __ANDROID__
|
||||
return ThreadAndroid::get_env();
|
||||
return get_jni_env();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
|
|
@ -220,15 +220,9 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) {
|
|||
nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
|
||||
#endif
|
||||
|
||||
#ifndef NO_THREADS
|
||||
owners_lock->lock();
|
||||
#endif
|
||||
|
||||
owners_lock.lock();
|
||||
instance_owners.insert(p_this);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
owners_lock->unlock();
|
||||
#endif
|
||||
owners_lock.unlock();
|
||||
|
||||
return nsi;
|
||||
}
|
||||
|
@ -524,17 +518,10 @@ NativeScript::NativeScript() {
|
|||
library = Ref<GDNative>();
|
||||
lib_path = "";
|
||||
class_name = "";
|
||||
#ifndef NO_THREADS
|
||||
owners_lock = Mutex::create();
|
||||
#endif
|
||||
}
|
||||
|
||||
NativeScript::~NativeScript() {
|
||||
NSL->unregister_script(this);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
memdelete(owners_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GET_SCRIPT_DESC() script->get_script_desc()
|
||||
|
@ -911,15 +898,9 @@ NativeScriptInstance::~NativeScriptInstance() {
|
|||
|
||||
if (owner) {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script->owners_lock->lock();
|
||||
#endif
|
||||
|
||||
script->owners_lock.lock();
|
||||
script->instance_owners.erase(owner);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script->owners_lock->unlock();
|
||||
#endif
|
||||
script->owners_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,10 +995,6 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) {
|
|||
|
||||
NativeScriptLanguage::NativeScriptLanguage() {
|
||||
NativeScriptLanguage::singleton = this;
|
||||
#ifndef NO_THREADS
|
||||
has_objects_to_register = false;
|
||||
mutex = Mutex::create();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
profiling = false;
|
||||
|
@ -1053,10 +1030,6 @@ NativeScriptLanguage::~NativeScriptLanguage() {
|
|||
NSL->library_classes.clear();
|
||||
NSL->library_gdnatives.clear();
|
||||
NSL->library_script_users.clear();
|
||||
|
||||
#ifndef NO_THREADS
|
||||
memdelete(mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
String NativeScriptLanguage::get_name() const {
|
||||
|
@ -1470,7 +1443,7 @@ void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeSc
|
|||
MutexLock lock(mutex);
|
||||
libs_to_init.insert(lib);
|
||||
scripts_to_register.insert(script);
|
||||
has_objects_to_register = true;
|
||||
has_objects_to_register.set();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1563,7 +1536,7 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
|
|||
|
||||
void NativeScriptLanguage::frame() {
|
||||
#ifndef NO_THREADS
|
||||
if (has_objects_to_register) {
|
||||
if (has_objects_to_register.is_set()) {
|
||||
MutexLock lock(mutex);
|
||||
for (Set<Ref<GDNativeLibrary> >::Element *L = libs_to_init.front(); L; L = L->next()) {
|
||||
init_library(L->get());
|
||||
|
@ -1573,7 +1546,7 @@ void NativeScriptLanguage::frame() {
|
|||
register_script(S->get());
|
||||
}
|
||||
scripts_to_register.clear();
|
||||
has_objects_to_register = false;
|
||||
has_objects_to_register.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "core/ordered_hash_map.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "core/resource.h"
|
||||
#include "core/safe_refcount.h"
|
||||
#include "core/script_language.h"
|
||||
#include "core/self_list.h"
|
||||
#include "scene/main/node.h"
|
||||
|
@ -121,9 +122,7 @@ class NativeScript : public Script {
|
|||
String script_class_name;
|
||||
String script_class_icon_path;
|
||||
|
||||
#ifndef NO_THREADS
|
||||
Mutex *owners_lock;
|
||||
#endif
|
||||
Mutex owners_lock;
|
||||
Set<Object *> instance_owners;
|
||||
|
||||
protected:
|
||||
|
@ -238,11 +237,11 @@ private:
|
|||
void _unload_stuff(bool p_reload = false);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
Mutex *mutex;
|
||||
Mutex mutex;
|
||||
|
||||
Set<Ref<GDNativeLibrary> > libs_to_init;
|
||||
Set<NativeScript *> scripts_to_register;
|
||||
volatile bool has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed
|
||||
SafeFlag has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed
|
||||
void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -400,39 +400,15 @@ void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool
|
|||
}
|
||||
|
||||
void PluginScriptLanguage::lock() {
|
||||
#ifndef NO_THREADS
|
||||
if (_lock) {
|
||||
_lock->lock();
|
||||
}
|
||||
#endif
|
||||
_lock.lock();
|
||||
}
|
||||
|
||||
void PluginScriptLanguage::unlock() {
|
||||
#ifndef NO_THREADS
|
||||
if (_lock) {
|
||||
_lock->unlock();
|
||||
}
|
||||
#endif
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_desc *desc) :
|
||||
_desc(*desc) {
|
||||
_resource_loader = Ref<ResourceFormatLoaderPluginScript>(memnew(ResourceFormatLoaderPluginScript(this)));
|
||||
_resource_saver = Ref<ResourceFormatSaverPluginScript>(memnew(ResourceFormatSaverPluginScript(this)));
|
||||
|
||||
// TODO: totally remove _lock attribute if NO_THREADS is set
|
||||
#ifdef NO_THREADS
|
||||
_lock = NULL;
|
||||
#else
|
||||
_lock = Mutex::create();
|
||||
#endif
|
||||
}
|
||||
|
||||
PluginScriptLanguage::~PluginScriptLanguage() {
|
||||
#ifndef NO_THREADS
|
||||
if (_lock) {
|
||||
memdelete(_lock);
|
||||
_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ class PluginScriptLanguage : public ScriptLanguage {
|
|||
const godot_pluginscript_language_desc _desc;
|
||||
godot_pluginscript_language_data *_data;
|
||||
|
||||
Mutex *_lock;
|
||||
Mutex _lock;
|
||||
SelfList<PluginScript>::List _script_list;
|
||||
|
||||
public:
|
||||
|
@ -126,7 +126,7 @@ public:
|
|||
void unlock();
|
||||
|
||||
PluginScriptLanguage(const godot_pluginscript_language_desc *desc);
|
||||
virtual ~PluginScriptLanguage();
|
||||
virtual ~PluginScriptLanguage() {}
|
||||
};
|
||||
|
||||
#endif // PLUGINSCRIPT_LANGUAGE_H
|
||||
|
|
|
@ -101,15 +101,9 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
|
|||
|
||||
/* STEP 2, INITIALIZE AND CONSTRUCT */
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
instances.insert(instance->owner);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
|
||||
initializer->call(instance, p_args, p_argcount, r_error);
|
||||
|
||||
|
@ -117,11 +111,11 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
|
|||
instance->script = Ref<GDScript>();
|
||||
instance->owner->set_script_instance(NULL);
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
#endif
|
||||
instances.erase(p_owner);
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
#endif
|
||||
|
||||
ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing
|
||||
|
@ -343,14 +337,9 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this)
|
|||
|
||||
bool GDScript::instance_has(const Object *p_this) const {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
bool hasit = instances.has((Object *)p_this);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
|
||||
return hasit;
|
||||
}
|
||||
|
@ -564,14 +553,9 @@ void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
|
|||
|
||||
Error GDScript::reload(bool p_keep_state) {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
bool has_instances = instances.size();
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
|
||||
ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
|
||||
|
||||
|
@ -926,14 +910,9 @@ GDScript::GDScript() :
|
|||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->lock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.lock();
|
||||
GDScriptLanguage::get_singleton()->script_list.add(&script_list);
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->unlock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -970,18 +949,14 @@ void GDScript::_save_orphaned_subclasses() {
|
|||
|
||||
GDScript::~GDScript() {
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->lock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.lock();
|
||||
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
|
||||
// Order matters since clearing the stack may already cause
|
||||
// the GDSCriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
E->self()->_clear_stack();
|
||||
}
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->unlock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.unlock();
|
||||
|
||||
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
|
||||
memdelete(E->get());
|
||||
|
@ -990,14 +965,9 @@ GDScript::~GDScript() {
|
|||
_save_orphaned_subclasses();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->lock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.lock();
|
||||
GDScriptLanguage::get_singleton()->script_list.remove(&script_list);
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->unlock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1400,9 +1370,7 @@ GDScriptInstance::GDScriptInstance() {
|
|||
}
|
||||
|
||||
GDScriptInstance::~GDScriptInstance() {
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
|
||||
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
|
||||
// Order matters since clearing the stack may already cause
|
||||
|
@ -1415,9 +1383,7 @@ GDScriptInstance::~GDScriptInstance() {
|
|||
script->instances.erase(owner);
|
||||
}
|
||||
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
}
|
||||
|
||||
/************* SCRIPT LANGUAGE **************/
|
||||
|
@ -1517,9 +1483,7 @@ void GDScriptLanguage::finish() {
|
|||
void GDScriptLanguage::profiling_start() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
SelfList<GDScriptFunction> *elem = function_list.first();
|
||||
while (elem) {
|
||||
|
@ -1536,25 +1500,16 @@ void GDScriptLanguage::profiling_start() {
|
|||
}
|
||||
|
||||
profiling = true;
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GDScriptLanguage::profiling_stop() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
profiling = false;
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1562,9 +1517,7 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
|
|||
|
||||
int current = 0;
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
SelfList<GDScriptFunction> *elem = function_list.first();
|
||||
while (elem) {
|
||||
|
@ -1578,10 +1531,7 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
|
|||
current++;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
#endif
|
||||
|
||||
return current;
|
||||
|
@ -1592,9 +1542,7 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
|
|||
int current = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
SelfList<GDScriptFunction> *elem = function_list.first();
|
||||
while (elem) {
|
||||
|
@ -1610,10 +1558,7 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
|
|||
elem = elem->next();
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
#endif
|
||||
|
||||
return current;
|
||||
|
@ -1644,9 +1589,7 @@ void GDScriptLanguage::reload_all_scripts() {
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
print_verbose("GDScript: Reloading all scripts");
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
List<Ref<GDScript> > scripts;
|
||||
|
||||
|
@ -1659,9 +1602,7 @@ void GDScriptLanguage::reload_all_scripts() {
|
|||
elem = elem->next();
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
//as scripts are going to be reloaded, must proceed without locking here
|
||||
|
||||
|
@ -1680,9 +1621,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
List<Ref<GDScript> > scripts;
|
||||
|
||||
|
@ -1695,9 +1634,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
|
|||
elem = elem->next();
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
//when someone asks you why dynamically typed languages are easier to write....
|
||||
|
||||
|
@ -1816,9 +1753,7 @@ void GDScriptLanguage::frame() {
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (profiling) {
|
||||
if (lock) {
|
||||
lock->lock();
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
SelfList<GDScriptFunction> *elem = function_list.first();
|
||||
while (elem) {
|
||||
|
@ -1831,9 +1766,7 @@ void GDScriptLanguage::frame() {
|
|||
elem = elem->next();
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
lock->unlock();
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2202,11 +2135,6 @@ GDScriptLanguage::GDScriptLanguage() {
|
|||
_debug_parse_err_line = -1;
|
||||
_debug_parse_err_file = "";
|
||||
|
||||
#ifdef NO_THREADS
|
||||
lock = NULL;
|
||||
#else
|
||||
lock = Mutex::create();
|
||||
#endif
|
||||
profiling = false;
|
||||
script_frame_time = 0;
|
||||
|
||||
|
@ -2240,10 +2168,6 @@ GDScriptLanguage::GDScriptLanguage() {
|
|||
|
||||
GDScriptLanguage::~GDScriptLanguage() {
|
||||
|
||||
if (lock) {
|
||||
memdelete(lock);
|
||||
lock = NULL;
|
||||
}
|
||||
if (_call_stack) {
|
||||
memdelete_arr(_call_stack);
|
||||
}
|
||||
|
|
|
@ -351,7 +351,7 @@ class GDScriptLanguage : public ScriptLanguage {
|
|||
|
||||
friend class GDScriptInstance;
|
||||
|
||||
Mutex *lock;
|
||||
Mutex lock;
|
||||
|
||||
friend class GDScript;
|
||||
|
||||
|
|
|
@ -1279,9 +1279,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
gdfs->state.ip = ip + ipofs;
|
||||
gdfs->state.line = line;
|
||||
gdfs->state.script = _script;
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
|
||||
_script->pending_func_states.add(&gdfs->scripts_list);
|
||||
if (p_instance) {
|
||||
|
@ -1290,9 +1288,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
} else {
|
||||
gdfs->state.instance = NULL;
|
||||
}
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
#ifdef DEBUG_ENABLED
|
||||
gdfs->state.function_name = name;
|
||||
gdfs->state.script_path = _script->get_path();
|
||||
|
@ -1776,14 +1772,9 @@ GDScriptFunction::GDScriptFunction() :
|
|||
#ifdef DEBUG_ENABLED
|
||||
_func_cname = NULL;
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->lock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.lock();
|
||||
GDScriptLanguage::get_singleton()->function_list.add(&function_list);
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->unlock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.unlock();
|
||||
|
||||
profile.call_count = 0;
|
||||
profile.self_time = 0;
|
||||
|
@ -1800,14 +1791,9 @@ GDScriptFunction::GDScriptFunction() :
|
|||
|
||||
GDScriptFunction::~GDScriptFunction() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->lock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.lock();
|
||||
GDScriptLanguage::get_singleton()->function_list.remove(&function_list);
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->lock) {
|
||||
GDScriptLanguage::get_singleton()->lock->unlock();
|
||||
}
|
||||
GDScriptLanguage::get_singleton()->lock.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1958,12 +1944,8 @@ GDScriptFunctionState::GDScriptFunctionState() :
|
|||
GDScriptFunctionState::~GDScriptFunctionState() {
|
||||
|
||||
_clear_stack();
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.lock();
|
||||
scripts_list.remove_from_list();
|
||||
instances_list.remove_from_list();
|
||||
#ifndef NO_THREADS
|
||||
GDScriptLanguage::singleton->lock->unlock();
|
||||
#endif
|
||||
GDScriptLanguage::singleton->lock.unlock();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "editor/editor_node.h"
|
||||
|
||||
GDScriptLanguageServer::GDScriptLanguageServer() {
|
||||
thread = NULL;
|
||||
thread_running = false;
|
||||
started = false;
|
||||
|
||||
|
@ -88,9 +87,8 @@ void GDScriptLanguageServer::start() {
|
|||
if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
|
||||
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
|
||||
if (use_thread) {
|
||||
ERR_FAIL_COND(thread != NULL);
|
||||
thread_running = true;
|
||||
thread = Thread::create(GDScriptLanguageServer::thread_main, this);
|
||||
thread.start(GDScriptLanguageServer::thread_main, this);
|
||||
}
|
||||
set_process_internal(!use_thread);
|
||||
started = true;
|
||||
|
@ -99,11 +97,9 @@ void GDScriptLanguageServer::start() {
|
|||
|
||||
void GDScriptLanguageServer::stop() {
|
||||
if (use_thread) {
|
||||
ERR_FAIL_COND(NULL == thread);
|
||||
ERR_FAIL_COND(!thread.is_started());
|
||||
thread_running = false;
|
||||
Thread::wait_to_finish(thread);
|
||||
memdelete(thread);
|
||||
thread = NULL;
|
||||
thread.wait_to_finish();
|
||||
}
|
||||
protocol.stop();
|
||||
started = false;
|
||||
|
|
|
@ -40,7 +40,7 @@ class GDScriptLanguageServer : public EditorPlugin {
|
|||
|
||||
GDScriptLanguageProtocol protocol;
|
||||
|
||||
Thread *thread;
|
||||
Thread thread;
|
||||
bool thread_running;
|
||||
bool started;
|
||||
bool use_thread;
|
||||
|
|
|
@ -251,7 +251,8 @@ bool LightmapperCPU::_parallel_run(int p_count, const String &p_description, Bak
|
|||
td.count = p_count;
|
||||
td.thread_func = p_thread_func;
|
||||
td.userdata = p_userdata;
|
||||
Thread *runner_thread = Thread::create(_thread_func_callback, &td);
|
||||
Thread runner_thread;
|
||||
runner_thread.start(_thread_func_callback, &td);
|
||||
|
||||
int progress = thread_progress;
|
||||
|
||||
|
@ -263,8 +264,7 @@ bool LightmapperCPU::_parallel_run(int p_count, const String &p_description, Bak
|
|||
progress = thread_progress;
|
||||
}
|
||||
thread_cancelled = cancelled;
|
||||
Thread::wait_to_finish(runner_thread);
|
||||
memdelete(runner_thread);
|
||||
runner_thread.wait_to_finish();
|
||||
#endif
|
||||
|
||||
thread_cancelled = false;
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#include "mono_gd/gd_mono_utils.h"
|
||||
#include "signal_awaiter_utils.h"
|
||||
#include "utils/macros.h"
|
||||
#include "utils/mutex_utils.h"
|
||||
#include "utils/string_utils.h"
|
||||
#include "utils/thread_local.h"
|
||||
|
||||
|
@ -638,7 +637,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
|
|||
|
||||
void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
SCOPED_MUTEX_LOCK(unsafe_object_references_lock);
|
||||
MutexLock lock(unsafe_object_references_lock);
|
||||
ObjectID id = p_obj->get_instance_id();
|
||||
unsafe_object_references[id]++;
|
||||
#endif
|
||||
|
@ -646,7 +645,7 @@ void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
|
|||
|
||||
void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
SCOPED_MUTEX_LOCK(unsafe_object_references_lock);
|
||||
MutexLock lock(unsafe_object_references_lock);
|
||||
ObjectID id = p_obj->get_instance_id();
|
||||
Map<ObjectID, int>::Element *elem = unsafe_object_references.find(id);
|
||||
ERR_FAIL_NULL(elem);
|
||||
|
@ -769,7 +768,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
|||
List<Ref<CSharpScript> > scripts;
|
||||
|
||||
{
|
||||
SCOPED_MUTEX_LOCK(script_instances_mutex);
|
||||
MutexLock lock(script_instances_mutex);
|
||||
|
||||
for (SelfList<CSharpScript> *elem = script_list.first(); elem; elem = elem->next()) {
|
||||
// Cast to CSharpScript to avoid being erased by accident
|
||||
|
@ -1209,7 +1208,7 @@ void CSharpLanguage::set_language_index(int p_idx) {
|
|||
void CSharpLanguage::release_script_gchandle(Ref<MonoGCHandle> &p_gchandle) {
|
||||
|
||||
if (!p_gchandle->is_released()) { // Do not lock unnecessarily
|
||||
SCOPED_MUTEX_LOCK(get_singleton()->script_gchandle_release_mutex);
|
||||
MutexLock lock(get_singleton()->script_gchandle_release_mutex);
|
||||
p_gchandle->release();
|
||||
}
|
||||
}
|
||||
|
@ -1219,7 +1218,7 @@ void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, Ref<Mon
|
|||
uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(p_expected_obj); // We might lock after this, so pin it
|
||||
|
||||
if (!p_gchandle->is_released()) { // Do not lock unnecessarily
|
||||
SCOPED_MUTEX_LOCK(get_singleton()->script_gchandle_release_mutex);
|
||||
MutexLock lock(get_singleton()->script_gchandle_release_mutex);
|
||||
|
||||
MonoObject *target = p_gchandle->get_target();
|
||||
|
||||
|
@ -1244,24 +1243,6 @@ CSharpLanguage::CSharpLanguage() {
|
|||
|
||||
gdmono = NULL;
|
||||
|
||||
#ifdef NO_THREADS
|
||||
script_instances_mutex = NULL;
|
||||
script_gchandle_release_mutex = NULL;
|
||||
language_bind_mutex = NULL;
|
||||
#else
|
||||
script_instances_mutex = Mutex::create();
|
||||
script_gchandle_release_mutex = Mutex::create();
|
||||
language_bind_mutex = Mutex::create();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#ifdef NO_THREADS
|
||||
unsafe_object_references_lock = NULL;
|
||||
#else
|
||||
unsafe_object_references_lock = Mutex::create();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
lang_idx = -1;
|
||||
|
||||
scripts_metadata_invalidated = true;
|
||||
|
@ -1274,29 +1255,6 @@ CSharpLanguage::CSharpLanguage() {
|
|||
CSharpLanguage::~CSharpLanguage() {
|
||||
|
||||
finish();
|
||||
|
||||
if (script_instances_mutex) {
|
||||
memdelete(script_instances_mutex);
|
||||
script_instances_mutex = NULL;
|
||||
}
|
||||
|
||||
if (language_bind_mutex) {
|
||||
memdelete(language_bind_mutex);
|
||||
language_bind_mutex = NULL;
|
||||
}
|
||||
|
||||
if (script_gchandle_release_mutex) {
|
||||
memdelete(script_gchandle_release_mutex);
|
||||
script_gchandle_release_mutex = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (unsafe_object_references_lock) {
|
||||
memdelete(unsafe_object_references_lock);
|
||||
unsafe_object_references_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
singleton = NULL;
|
||||
}
|
||||
|
||||
|
@ -1351,7 +1309,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
|
|||
|
||||
void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
|
||||
|
||||
SCOPED_MUTEX_LOCK(language_bind_mutex);
|
||||
MutexLock lock(language_bind_mutex);
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *match = script_bindings.find(p_object);
|
||||
if (match)
|
||||
|
@ -1386,7 +1344,7 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
|
|||
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||
|
||||
{
|
||||
SCOPED_MUTEX_LOCK(language_bind_mutex);
|
||||
MutexLock lock(language_bind_mutex);
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
|
||||
|
||||
|
@ -2216,7 +2174,7 @@ CSharpInstance::~CSharpInstance() {
|
|||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
|
||||
if (!script_binding.inited) {
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
|
||||
if (!script_binding.inited) { // Other thread may have set it up
|
||||
// Already had a binding that needs to be setup
|
||||
|
@ -2232,7 +2190,7 @@ CSharpInstance::~CSharpInstance() {
|
|||
}
|
||||
|
||||
if (script.is_valid() && owner) {
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// CSharpInstance must not be created unless it's going to be added to the list for sure
|
||||
|
@ -3034,7 +2992,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
|||
instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
|
||||
|
||||
{
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
instances.insert(instance->owner);
|
||||
}
|
||||
|
||||
|
@ -3122,7 +3080,7 @@ PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_t
|
|||
|
||||
bool CSharpScript::instance_has(const Object *p_this) const {
|
||||
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
return instances.has((Object *)p_this);
|
||||
}
|
||||
|
||||
|
@ -3195,7 +3153,7 @@ Error CSharpScript::reload(bool p_keep_state) {
|
|||
|
||||
bool has_instances;
|
||||
{
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
has_instances = instances.size();
|
||||
}
|
||||
|
||||
|
@ -3394,7 +3352,7 @@ CSharpScript::CSharpScript() :
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
{
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
CSharpLanguage::get_singleton()->script_list.add(&this->script_list);
|
||||
}
|
||||
#endif
|
||||
|
@ -3403,7 +3361,7 @@ CSharpScript::CSharpScript() :
|
|||
CSharpScript::~CSharpScript() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
|
||||
CSharpLanguage::get_singleton()->script_list.remove(&this->script_list);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -307,16 +307,16 @@ class CSharpLanguage : public ScriptLanguage {
|
|||
GDMono *gdmono;
|
||||
SelfList<CSharpScript>::List script_list;
|
||||
|
||||
Mutex *script_instances_mutex;
|
||||
Mutex *script_gchandle_release_mutex;
|
||||
Mutex *language_bind_mutex;
|
||||
Mutex script_instances_mutex;
|
||||
Mutex script_gchandle_release_mutex;
|
||||
Mutex language_bind_mutex;
|
||||
|
||||
Map<Object *, CSharpScriptBinding> script_bindings;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// List of unsafe object references
|
||||
Map<ObjectID, int> unsafe_object_references;
|
||||
Mutex *unsafe_object_references_lock;
|
||||
Mutex unsafe_object_references_lock;
|
||||
#endif
|
||||
|
||||
struct StringNameCache {
|
||||
|
@ -358,7 +358,7 @@ class CSharpLanguage : public ScriptLanguage {
|
|||
public:
|
||||
StringNameCache string_names;
|
||||
|
||||
Mutex *get_language_bind_mutex() { return language_bind_mutex; }
|
||||
Mutex &get_language_bind_mutex() { return language_bind_mutex; }
|
||||
|
||||
_FORCE_INLINE_ int get_language_index() { return lang_idx; }
|
||||
void set_language_index(int p_idx);
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
|
||||
#include "../csharp_script.h"
|
||||
#include "../utils/macros.h"
|
||||
#include "../utils/mutex_utils.h"
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_cache.h"
|
||||
#include "gd_mono_class.h"
|
||||
|
@ -75,7 +74,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
|
|||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
|
||||
|
||||
if (!script_binding.inited) {
|
||||
SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
|
||||
if (!script_binding.inited) { // Other thread may have set it up
|
||||
// Already had a binding that needs to be setup
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue