Merge pull request #45618 from RandomShaper/modernize_mt_3.2

Backport of all the multi-threading modernization (3.2)
This commit is contained in:
Hein-Pieter van Braam 2021-02-18 20:47:24 +01:00 committed by GitHub
commit 220f24c191
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
191 changed files with 1688 additions and 4522 deletions

View file

@ -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...");
}
/////////////////////////////////////

View file

@ -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);

View file

@ -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);
}
//

View file

@ -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();

View file

@ -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);
}

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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(); \
} \
}

View file

@ -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();

View file

@ -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;

View file

@ -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);
}

View file

@ -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
}

View file

@ -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();
};

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

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

View file

@ -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() {
}

View file

@ -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();
}
};

View file

@ -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() {
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
};

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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!");
}

View file

@ -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);

View file

@ -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);

View file

@ -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();
}

View file

@ -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
}

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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;

View file

@ -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") {

View file

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

View file

@ -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;
}

View file

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

View file

@ -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),

View file

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

View file

@ -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),

View file

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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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++) {

View file

@ -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];

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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:

View file

@ -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);
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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) {

View file

@ -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]);
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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);
}

View file

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

View file

@ -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();
}

View file

@ -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;

View file

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

View file

@ -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;

View file

@ -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
}

View file

@ -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);

View file

@ -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