diff options
Diffstat (limited to 'core/os')
-rw-r--r-- | core/os/copymem.h | 4 | ||||
-rw-r--r-- | core/os/dir_access.cpp | 111 | ||||
-rw-r--r-- | core/os/dir_access.h | 33 | ||||
-rw-r--r-- | core/os/file_access.cpp | 199 | ||||
-rw-r--r-- | core/os/file_access.h | 27 | ||||
-rw-r--r-- | core/os/keyboard.cpp | 16 | ||||
-rw-r--r-- | core/os/keyboard.h | 9 | ||||
-rw-r--r-- | core/os/main_loop.cpp | 62 | ||||
-rw-r--r-- | core/os/main_loop.h | 32 | ||||
-rw-r--r-- | core/os/memory.cpp | 21 | ||||
-rw-r--r-- | core/os/memory.h | 46 | ||||
-rw-r--r-- | core/os/midi_driver.cpp | 9 | ||||
-rw-r--r-- | core/os/midi_driver.h | 7 | ||||
-rw-r--r-- | core/os/mutex.cpp | 4 | ||||
-rw-r--r-- | core/os/mutex.h | 9 | ||||
-rw-r--r-- | core/os/os.cpp | 178 | ||||
-rw-r--r-- | core/os/os.h | 69 | ||||
-rw-r--r-- | core/os/pool_allocator.cpp | 596 | ||||
-rw-r--r-- | core/os/pool_allocator.h | 149 | ||||
-rw-r--r-- | core/os/rw_lock.cpp | 10 | ||||
-rw-r--r-- | core/os/rw_lock.h | 26 | ||||
-rw-r--r-- | core/os/semaphore.h | 9 | ||||
-rw-r--r-- | core/os/spin_lock.h (renamed from core/os/semaphore.cpp) | 28 | ||||
-rw-r--r-- | core/os/thread.cpp | 24 | ||||
-rw-r--r-- | core/os/thread.h | 12 | ||||
-rw-r--r-- | core/os/thread_dummy.cpp | 12 | ||||
-rw-r--r-- | core/os/thread_dummy.h | 6 | ||||
-rw-r--r-- | core/os/thread_safe.h | 4 | ||||
-rw-r--r-- | core/os/threaded_array_processor.h | 12 |
29 files changed, 1160 insertions, 564 deletions
diff --git a/core/os/copymem.h b/core/os/copymem.h index 04ea3caeff..6fd559356c 100644 --- a/core/os/copymem.h +++ b/core/os/copymem.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 94c8cd5d73..fb9da9fbed 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -30,62 +30,62 @@ #include "dir_access.h" +#include "core/config/project_settings.h" #include "core/os/file_access.h" #include "core/os/memory.h" #include "core/os/os.h" -#include "core/project_settings.h" String DirAccess::_get_root_path() const { - switch (_access_type) { - - case ACCESS_RESOURCES: return ProjectSettings::get_singleton()->get_resource_path(); - case ACCESS_USERDATA: return OS::get_singleton()->get_user_data_dir(); - default: return ""; + case ACCESS_RESOURCES: + return ProjectSettings::get_singleton()->get_resource_path(); + case ACCESS_USERDATA: + return OS::get_singleton()->get_user_data_dir(); + default: + return ""; } } -String DirAccess::_get_root_string() const { +String DirAccess::_get_root_string() const { switch (_access_type) { - - case ACCESS_RESOURCES: return "res://"; - case ACCESS_USERDATA: return "user://"; - default: return ""; + case ACCESS_RESOURCES: + return "res://"; + case ACCESS_USERDATA: + return "user://"; + default: + return ""; } } int DirAccess::get_current_drive() { - String path = get_current_dir().to_lower(); for (int i = 0; i < get_drive_count(); i++) { String d = get_drive(i).to_lower(); - if (path.begins_with(d)) + if (path.begins_with(d)) { return i; + } } return 0; } bool DirAccess::drives_are_shortcuts() { - return false; } static Error _erase_recursive(DirAccess *da) { - List<String> dirs; List<String> files; da->list_dir_begin(); String n = da->get_next(); while (n != String()) { - if (n != "." && n != "..") { - - if (da->current_is_dir()) + if (da->current_is_dir()) { dirs.push_back(n); - else + } else { files.push_back(n); + } } n = da->get_next(); @@ -94,10 +94,8 @@ static Error _erase_recursive(DirAccess *da) { da->list_dir_end(); for (List<String>::Element *E = dirs.front(); E; E = E->next()) { - Error err = da->change_dir(E->get()); if (err == OK) { - err = _erase_recursive(da); if (err) { da->change_dir(".."); @@ -117,7 +115,6 @@ static Error _erase_recursive(DirAccess *da) { } for (List<String>::Element *E = files.front(); E; E = E->next()) { - Error err = da->remove(da->get_current_dir().plus_file(E->get())); if (err) { return err; @@ -128,15 +125,13 @@ static Error _erase_recursive(DirAccess *da) { } Error DirAccess::erase_contents_recursive() { - return _erase_recursive(this); } Error DirAccess::make_dir_recursive(String p_dir) { - if (p_dir.length() < 1) { return OK; - }; + } String full_dir; @@ -154,13 +149,13 @@ Error DirAccess::make_dir_recursive(String p_dir) { String base; - if (full_dir.begins_with("res://")) + if (full_dir.begins_with("res://")) { base = "res://"; - else if (full_dir.begins_with("user://")) + } else if (full_dir.begins_with("user://")) { base = "user://"; - else if (full_dir.begins_with("/")) + } else if (full_dir.begins_with("/")) { base = "/"; - else if (full_dir.find(":/") != -1) { + } else if (full_dir.find(":/") != -1) { base = full_dir.substr(0, full_dir.find(":/") + 2); } else { ERR_FAIL_V(ERR_INVALID_PARAMETER); @@ -172,11 +167,9 @@ Error DirAccess::make_dir_recursive(String p_dir) { String curpath = base; for (int i = 0; i < subdirs.size(); i++) { - curpath = curpath.plus_file(subdirs[i]); Error err = make_dir(curpath); if (err != OK && err != ERR_ALREADY_EXISTS) { - ERR_FAIL_V(err); } } @@ -185,42 +178,34 @@ Error DirAccess::make_dir_recursive(String p_dir) { } String DirAccess::fix_path(String p_path) const { - switch (_access_type) { - case ACCESS_RESOURCES: { - if (ProjectSettings::get_singleton()) { if (p_path.begins_with("res://")) { - String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (resource_path != "") { - return p_path.replace_first("res:/", resource_path); - }; + } return p_path.replace_first("res://", ""); } } } break; case ACCESS_USERDATA: { - if (p_path.begins_with("user://")) { - String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { - return p_path.replace_first("user:/", data_dir); - }; + } return p_path.replace_first("user://", ""); } } break; case ACCESS_FILESYSTEM: { - return p_path; } break; - case ACCESS_MAX: break; // Can't happen, but silences warning + case ACCESS_MAX: + break; // Can't happen, but silences warning } return p_path; @@ -229,16 +214,12 @@ String DirAccess::fix_path(String p_path) const { DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { nullptr, nullptr, nullptr }; DirAccess *DirAccess::create_for_path(const String &p_path) { - DirAccess *da = nullptr; if (p_path.begins_with("res://")) { - da = create(ACCESS_RESOURCES); } else if (p_path.begins_with("user://")) { - da = create(ACCESS_USERDATA); } else { - da = create(ACCESS_FILESYSTEM); } @@ -246,13 +227,13 @@ DirAccess *DirAccess::create_for_path(const String &p_path) { } DirAccess *DirAccess::open(const String &p_path, Error *r_error) { - DirAccess *da = create_for_path(p_path); ERR_FAIL_COND_V_MSG(!da, nullptr, "Cannot create DirAccess for path '" + p_path + "'."); Error err = da->change_dir(p_path); - if (r_error) + if (r_error) { *r_error = err; + } if (err != OK) { memdelete(da); return nullptr; @@ -262,20 +243,19 @@ DirAccess *DirAccess::open(const String &p_path, Error *r_error) { } DirAccess *DirAccess::create(AccessType p_access) { - DirAccess *da = create_func[p_access] ? create_func[p_access]() : nullptr; if (da) { da->_access_type = p_access; } return da; -}; +} String DirAccess::get_full_path(const String &p_path, AccessType p_access) { - DirAccess *d = DirAccess::create(p_access); - if (!d) + if (!d) { return p_path; + } d->change_dir(p_path); String full = d->get_current_dir(); @@ -284,7 +264,6 @@ String DirAccess::get_full_path(const String &p_path, AccessType p_access) { } Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { - //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); Error err; FileAccess *fsrc = FileAccess::open(p_from, FileAccess::READ, &err); @@ -296,7 +275,6 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { FileAccess *fdst = FileAccess::open(p_to, FileAccess::WRITE, &err); if (err) { - fsrc->close(); memdelete(fsrc); ERR_PRINT("Failed to open " + p_to); @@ -308,7 +286,6 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { fsrc->seek(0); err = OK; while (size--) { - if (fsrc->get_error() != OK) { err = fsrc->get_error(); break; @@ -325,8 +302,9 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { fdst->close(); err = FileAccess::set_unix_permissions(p_to, p_chmod_flags); // If running on a platform with no chmod support (i.e., Windows), don't fail - if (err == ERR_UNAVAILABLE) + if (err == ERR_UNAVAILABLE) { err = OK; + } } memdelete(fsrc); @@ -360,12 +338,10 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag list_dir_begin(); String n = get_next(); while (n != String()) { - if (n != "." && n != "..") { - - if (current_is_dir()) + if (current_is_dir()) { dirs.push_back(n); - else { + } else { const String &rel_path = n; if (!n.is_rel_path()) { list_dir_end(); @@ -433,17 +409,8 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) { } bool DirAccess::exists(String p_dir) { - DirAccess *da = DirAccess::create_for_path(p_dir); bool valid = da->change_dir(p_dir) == OK; memdelete(da); return valid; } - -DirAccess::DirAccess() { - - _access_type = ACCESS_FILESYSTEM; -} - -DirAccess::~DirAccess() { -} diff --git a/core/os/dir_access.h b/core/os/dir_access.h index 60eb553968..c49c4cc4b8 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,8 +31,8 @@ #ifndef DIR_ACCESS_H #define DIR_ACCESS_H +#include "core/string/ustring.h" #include "core/typedefs.h" -#include "core/ustring.h" //@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies class DirAccess { @@ -47,7 +47,7 @@ public: typedef DirAccess *(*CreateFunc)(); private: - AccessType _access_type; + AccessType _access_type = ACCESS_FILESYSTEM; static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags); @@ -57,11 +57,9 @@ protected: String _get_root_string() const; String fix_path(String p_path) const; - bool next_is_dir; template <class T> static DirAccess *_create_builtin() { - return memnew(T); } @@ -110,42 +108,33 @@ public: static String get_full_path(const String &p_path, AccessType p_access); static DirAccess *create_for_path(const String &p_path); - /* - enum DirType { - - FILE_TYPE_INVALID, - FILE_TYPE_FILE, - FILE_TYPE_DIR, - }; - - //virtual DirType get_file_type() const=0; -*/ static DirAccess *create(AccessType p_access); template <class T> static void make_default(AccessType p_access) { - create_func[p_access] = _create_builtin<T>; } static DirAccess *open(const String &p_path, Error *r_error = nullptr); - DirAccess(); - virtual ~DirAccess(); + DirAccess() {} + virtual ~DirAccess() {} }; struct DirAccessRef { - _FORCE_INLINE_ DirAccess *operator->() { - return f; } operator bool() const { return f != nullptr; } + DirAccess *f; + DirAccessRef(DirAccess *fa) { f = fa; } ~DirAccessRef() { - if (f) memdelete(f); + if (f) { + memdelete(f); + } } }; diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 3922f031b7..5a3df88619 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -30,11 +30,11 @@ #include "file_access.h" +#include "core/config/project_settings.h" #include "core/crypto/crypto_core.h" #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" #include "core/os/os.h" -#include "core/project_settings.h" FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr }; @@ -43,7 +43,6 @@ FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr; bool FileAccess::backup_save = false; FileAccess *FileAccess::create(AccessType p_access) { - ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr); FileAccess *ret = create_func[p_access](); @@ -52,34 +51,30 @@ FileAccess *FileAccess::create(AccessType p_access) { } bool FileAccess::exists(const String &p_name) { - - if (PackedData::get_singleton() && PackedData::get_singleton()->has_path(p_name)) + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_name)) { return true; + } FileAccess *f = open(p_name, READ); - if (!f) + if (!f) { return false; + } memdelete(f); return true; } void FileAccess::_set_access_type(AccessType p_access) { - _access_type = p_access; -}; +} FileAccess *FileAccess::create_for_path(const String &p_path) { - FileAccess *ret = nullptr; if (p_path.begins_with("res://")) { - ret = create(ACCESS_RESOURCES); } else if (p_path.begins_with("user://")) { - ret = create(ACCESS_USERDATA); } else { - ret = create(ACCESS_FILESYSTEM); } @@ -87,20 +82,19 @@ FileAccess *FileAccess::create_for_path(const String &p_path) { } Error FileAccess::reopen(const String &p_path, int p_mode_flags) { - return _open(p_path, p_mode_flags); -}; +} FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) { - //try packed data first FileAccess *ret = nullptr; if (!(p_mode_flags & WRITE) && PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled()) { ret = PackedData::get_singleton()->try_open_path(p_path); if (ret) { - if (r_error) + if (r_error) { *r_error = OK; + } return ret; } } @@ -108,10 +102,10 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er ret = create_for_path(p_path); Error err = ret->_open(p_path, p_mode_flags); - if (r_error) + if (r_error) { *r_error = err; + } if (err != OK) { - memdelete(ret); ret = nullptr; } @@ -120,9 +114,8 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er } FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) { - return create_func[p_access]; -}; +} String FileAccess::fix_path(const String &p_path) const { //helper used by file accesses that use a single filesystem @@ -130,40 +123,33 @@ String FileAccess::fix_path(const String &p_path) const { String r_path = p_path.replace("\\", "/"); switch (_access_type) { - case ACCESS_RESOURCES: { - if (ProjectSettings::get_singleton()) { if (r_path.begins_with("res://")) { - String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (resource_path != "") { - return r_path.replace("res:/", resource_path); - }; + } return r_path.replace("res://", ""); } } } break; case ACCESS_USERDATA: { - if (r_path.begins_with("user://")) { - String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { - return r_path.replace("user:/", data_dir); - }; + } return r_path.replace("user://", ""); } } break; case ACCESS_FILESYSTEM: { - return r_path; } break; - case ACCESS_MAX: break; // Can't happen, but silences warning + case ACCESS_MAX: + break; // Can't happen, but silences warning } return r_path; @@ -172,7 +158,6 @@ String FileAccess::fix_path(const String &p_path) const { /* these are all implemented for ease of porting, then can later be optimized */ uint16_t FileAccess::get_16() const { - uint16_t res; uint8_t a, b; @@ -180,7 +165,6 @@ uint16_t FileAccess::get_16() const { b = get_8(); if (endian_swap) { - SWAP(a, b); } @@ -190,8 +174,8 @@ uint16_t FileAccess::get_16() const { return res; } -uint32_t FileAccess::get_32() const { +uint32_t FileAccess::get_32() const { uint32_t res; uint16_t a, b; @@ -199,7 +183,6 @@ uint32_t FileAccess::get_32() const { b = get_16(); if (endian_swap) { - SWAP(a, b); } @@ -209,8 +192,8 @@ uint32_t FileAccess::get_32() const { return res; } -uint64_t FileAccess::get_64() const { +uint64_t FileAccess::get_64() const { uint64_t res; uint32_t a, b; @@ -218,7 +201,6 @@ uint64_t FileAccess::get_64() const { b = get_32(); if (endian_swap) { - SWAP(a, b); } @@ -230,38 +212,35 @@ uint64_t FileAccess::get_64() const { } float FileAccess::get_float() const { - MarshallFloat m; m.i = get_32(); return m.f; -}; +} real_t FileAccess::get_real() const { - - if (real_is_double) + if (real_is_double) { return get_double(); - else + } else { return get_float(); + } } double FileAccess::get_double() const { - MarshallDouble m; m.l = get_64(); return m.d; -}; +} String FileAccess::get_token() const { - CharString token; - CharType c = get_8(); + char32_t c = get_8(); while (!eof_reached()) { - if (c <= ' ') { - if (token.length()) + if (token.length()) { break; + } } else { token += c; } @@ -275,21 +254,18 @@ class CharBuffer { Vector<char> vector; char stack_buffer[256]; - char *buffer; - int capacity; - int written; + char *buffer = nullptr; + int capacity = 0; + int written = 0; bool grow() { - if (vector.resize(next_power_of_2(1 + written)) != OK) { - return false; } if (buffer == stack_buffer) { // first chunk? for (int i = 0; i < written; i++) { - vector.write[i] = stack_buffer[i]; } } @@ -304,14 +280,11 @@ class CharBuffer { public: _FORCE_INLINE_ CharBuffer() : buffer(stack_buffer), - capacity(sizeof(stack_buffer) / sizeof(char)), - written(0) { + capacity(sizeof(stack_buffer) / sizeof(char)) { } _FORCE_INLINE_ void push_back(char c) { - if (written >= capacity) { - ERR_FAIL_COND(!grow()); } @@ -319,24 +292,22 @@ public: } _FORCE_INLINE_ const char *get_data() const { - return buffer; } }; String FileAccess::get_line() const { - CharBuffer line; - CharType c = get_8(); + char32_t c = get_8(); while (!eof_reached()) { - if (c == '\n' || c == '\0') { line.push_back(0); return String::utf8(line.get_data()); - } else if (c != '\r') + } else if (c != '\r') { line.push_back(c); + } c = get_8(); } @@ -345,21 +316,21 @@ String FileAccess::get_line() const { } Vector<String> FileAccess::get_csv_line(const String &p_delim) const { - ERR_FAIL_COND_V(p_delim.length() != 1, Vector<String>()); String l; int qc = 0; do { - if (eof_reached()) + if (eof_reached()) { break; + } l += get_line() + "\n"; qc = 0; for (int i = 0; i < l.length(); i++) { - - if (l[i] == '"') + if (l[i] == '"') { qc++; + } } } while (qc % 2); @@ -371,20 +342,18 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const { bool in_quote = false; String current; for (int i = 0; i < l.length(); i++) { - - CharType c = l[i]; - CharType s[2] = { 0, 0 }; + char32_t c = l[i]; + char32_t s[2] = { 0, 0 }; if (!in_quote && c == p_delim[0]) { strings.push_back(current); current = String(); } else if (c == '"') { - if (l[i + 1] == '"') { + if (l[i + 1] == '"' && in_quote) { s[0] = '"'; current += s; i++; } else { - in_quote = !in_quote; } } else { @@ -399,10 +368,10 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const { } int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const { - int i = 0; - for (i = 0; i < p_length && !eof_reached(); i++) + for (i = 0; i < p_length && !eof_reached(); i++) { p_dst[i] = get_8(); + } return i; } @@ -425,44 +394,40 @@ String FileAccess::get_as_utf8_string() const { } void FileAccess::store_16(uint16_t p_dest) { - uint8_t a, b; a = p_dest & 0xFF; b = p_dest >> 8; if (endian_swap) { - SWAP(a, b); } store_8(a); store_8(b); } -void FileAccess::store_32(uint32_t p_dest) { +void FileAccess::store_32(uint32_t p_dest) { uint16_t a, b; a = p_dest & 0xFFFF; b = p_dest >> 16; if (endian_swap) { - SWAP(a, b); } store_16(a); store_16(b); } -void FileAccess::store_64(uint64_t p_dest) { +void FileAccess::store_64(uint64_t p_dest) { uint32_t a, b; a = p_dest & 0xFFFFFFFF; b = p_dest >> 32; if (endian_swap) { - SWAP(a, b); } @@ -471,31 +436,29 @@ void FileAccess::store_64(uint64_t p_dest) { } void FileAccess::store_real(real_t p_real) { - - if (sizeof(real_t) == 4) + if (sizeof(real_t) == 4) { store_float(p_real); - else + } else { store_double(p_real); + } } void FileAccess::store_float(float p_dest) { - MarshallFloat m; m.f = p_dest; store_32(m.i); -}; +} void FileAccess::store_double(double p_dest) { - MarshallDouble m; m.d = p_dest; store_64(m.l); -}; +} uint64_t FileAccess::get_modified_time(const String &p_file) { - - if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) { return 0; + } FileAccess *fa = create_for_path(p_file); ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'."); @@ -506,9 +469,9 @@ uint64_t FileAccess::get_modified_time(const String &p_file) { } uint32_t FileAccess::get_unix_permissions(const String &p_file) { - - if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) { return 0; + } FileAccess *fa = create_for_path(p_file); ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'."); @@ -519,6 +482,9 @@ uint32_t FileAccess::get_unix_permissions(const String &p_file) { } Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) { + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) { + return ERR_UNAVAILABLE; + } FileAccess *fa = create_for_path(p_file); ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); @@ -529,23 +495,21 @@ Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissi } void FileAccess::store_string(const String &p_string) { - - if (p_string.length() == 0) + if (p_string.length() == 0) { return; + } CharString cs = p_string.utf8(); store_buffer((uint8_t *)&cs[0], cs.length()); } void FileAccess::store_pascal_string(const String &p_string) { - CharString cs = p_string.utf8(); store_32(cs.length()); store_buffer((uint8_t *)&cs[0], cs.length()); -}; +} String FileAccess::get_pascal_string() { - uint32_t sl = get_32(); CharString cs; cs.resize(sl + 1); @@ -556,16 +520,14 @@ String FileAccess::get_pascal_string() { ret.parse_utf8(cs.ptr()); return ret; -}; +} void FileAccess::store_line(const String &p_line) { - store_string(p_line); store_8('\n'); } void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_delim) { - ERR_FAIL_COND(p_delim.length() != 1); String line = ""; @@ -587,13 +549,12 @@ void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_ } void FileAccess::store_buffer(const uint8_t *p_src, int p_length) { - - for (int i = 0; i < p_length; i++) + for (int i = 0; i < p_length; i++) { store_8(p_src[i]); + } } Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) { - FileAccess *f = FileAccess::open(p_path, READ, r_error); if (!f) { if (r_error) { // if error requested, do not throw error @@ -609,7 +570,6 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err } String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { - Error err; Vector<uint8_t> array = get_file_as_array(p_path, &err); if (r_error) { @@ -628,10 +588,10 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { } String FileAccess::get_md5(const String &p_file) { - FileAccess *f = FileAccess::open(p_file, READ); - if (!f) + if (!f) { return String(); + } CryptoCore::MD5Context ctx; ctx.start(); @@ -639,14 +599,13 @@ String FileAccess::get_md5(const String &p_file) { unsigned char step[32768]; while (true) { - int br = f->get_buffer(step, 32768); if (br > 0) { - ctx.update(step, br); } - if (br < 4096) + if (br < 4096) { break; + } } unsigned char hash[16]; @@ -658,7 +617,6 @@ String FileAccess::get_md5(const String &p_file) { } String FileAccess::get_multiple_md5(const Vector<String> &p_file) { - CryptoCore::MD5Context ctx; ctx.start(); @@ -669,14 +627,13 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) { unsigned char step[32768]; while (true) { - int br = f->get_buffer(step, 32768); if (br > 0) { - ctx.update(step, br); } - if (br < 4096) + if (br < 4096) { break; + } } memdelete(f); } @@ -688,10 +645,10 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) { } String FileAccess::get_sha256(const String &p_file) { - FileAccess *f = FileAccess::open(p_file, READ); - if (!f) + if (!f) { return String(); + } CryptoCore::SHA256Context ctx; ctx.start(); @@ -699,14 +656,13 @@ String FileAccess::get_sha256(const String &p_file) { unsigned char step[32768]; while (true) { - int br = f->get_buffer(step, 32768); if (br > 0) { - ctx.update(step, br); } - if (br < 4096) + if (br < 4096) { break; + } } unsigned char hash[32]; @@ -715,10 +671,3 @@ String FileAccess::get_sha256(const String &p_file) { memdelete(f); return String::hex_encode_buffer(hash, 32); } - -FileAccess::FileAccess() { - - endian_swap = false; - real_is_double = false; - _access_type = ACCESS_FILESYSTEM; -}; diff --git a/core/os/file_access.h b/core/os/file_access.h index 010cc74a87..1c78204c1d 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -33,15 +33,14 @@ #include "core/math/math_defs.h" #include "core/os/memory.h" +#include "core/string/ustring.h" #include "core/typedefs.h" -#include "core/ustring.h" /** * Multi-Platform abstraction for accessing to files. */ class FileAccess { - public: enum AccessType { ACCESS_RESOURCES, @@ -53,8 +52,8 @@ public: typedef void (*FileCloseFailNotify)(const String &); typedef FileAccess *(*CreateFunc)(); - bool endian_swap; - bool real_is_double; + bool endian_swap = false; + bool real_is_double = false; virtual uint32_t _get_unix_permissions(const String &p_file) = 0; virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0; @@ -69,11 +68,10 @@ protected: private: static bool backup_save; - AccessType _access_type; + AccessType _access_type = ACCESS_FILESYSTEM; static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */ template <class T> static FileAccess *_create_builtin() { - return memnew(T); } @@ -83,7 +81,6 @@ public: virtual void _set_access_type(AccessType p_access); enum ModeFlags { - READ = 1, WRITE = 2, READ_WRITE = 3, @@ -172,27 +169,29 @@ public: template <class T> static void make_default(AccessType p_access) { - create_func[p_access] = _create_builtin<T>; } - FileAccess(); + FileAccess() {} virtual ~FileAccess() {} }; struct FileAccessRef { - _FORCE_INLINE_ FileAccess *operator->() { - return f; } operator bool() const { return f != nullptr; } + FileAccess *f; + operator FileAccess *() { return f; } + FileAccessRef(FileAccess *fa) { f = fa; } ~FileAccessRef() { - if (f) memdelete(f); + if (f) { + memdelete(f); + } } }; diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index c65d3fefc2..4b2cafd8fe 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -38,7 +38,6 @@ struct _KeyCodeText { }; static const _KeyCodeText _keycodes[] = { - /* clang-format off */ {KEY_ESCAPE ,"Escape"}, {KEY_TAB ,"Tab"}, @@ -293,9 +292,7 @@ static const _KeyCodeText _keycodes[] = { }; bool keycode_has_unicode(uint32_t p_keycode) { - switch (p_keycode) { - case KEY_ESCAPE: case KEY_TAB: case KEY_BACKTAB: @@ -394,7 +391,6 @@ bool keycode_has_unicode(uint32_t p_keycode) { } String keycode_get_string(uint32_t p_code) { - String codestr; if (p_code & KEY_MASK_SHIFT) { codestr += find_keycode_name(KEY_SHIFT); @@ -418,9 +414,7 @@ String keycode_get_string(uint32_t p_code) { const _KeyCodeText *kct = &_keycodes[0]; while (kct->text) { - if (kct->code == (int)p_code) { - codestr += kct->text; return codestr; } @@ -433,11 +427,9 @@ String keycode_get_string(uint32_t p_code) { } int find_keycode(const String &p_code) { - const _KeyCodeText *kct = &_keycodes[0]; while (kct->text) { - if (p_code.nocasecmp_to(kct->text) == 0) { return kct->code; } @@ -448,11 +440,9 @@ int find_keycode(const String &p_code) { } const char *find_keycode_name(int p_keycode) { - const _KeyCodeText *kct = &_keycodes[0]; while (kct->text) { - if (kct->code == p_keycode) { return kct->text; } @@ -463,12 +453,10 @@ const char *find_keycode_name(int p_keycode) { } int keycode_get_count() { - const _KeyCodeText *kct = &_keycodes[0]; int count = 0; while (kct->text) { - count++; kct++; } diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 5d11e6a378..3ef70e786f 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,7 +31,7 @@ #ifndef KEYBOARD_H #define KEYBOARD_H -#include "core/ustring.h" +#include "core/string/ustring.h" /* Special Key: @@ -294,11 +294,9 @@ enum KeyList { KEY_DIVISION = 0x00F7, KEY_YDIAERESIS = 0x00FF, - }; enum KeyModifierMask { - KEY_CODE_MASK = ((1 << 25) - 1), ///< Apply this mask to any keycode to remove modifiers. KEY_MODIFIER_MASK = (0xFF << 24), ///< Apply this mask to isolate modifiers. KEY_MASK_SHIFT = (1 << 25), @@ -314,7 +312,6 @@ enum KeyModifierMask { KEY_MASK_KPAD = (1 << 29), KEY_MASK_GROUP_SWITCH = (1 << 30) // bit 31 can't be used because variant uses regular 32 bits int as datatype - }; String keycode_get_string(uint32_t p_code); diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 0d1a080682..016d9d0a09 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -30,18 +30,12 @@ #include "main_loop.h" -#include "core/script_language.h" +#include "core/object/script_language.h" void MainLoop::_bind_methods() { - - ClassDB::bind_method(D_METHOD("init"), &MainLoop::init); - ClassDB::bind_method(D_METHOD("iteration", "delta"), &MainLoop::iteration); - ClassDB::bind_method(D_METHOD("idle", "delta"), &MainLoop::idle); - ClassDB::bind_method(D_METHOD("finish"), &MainLoop::finish); - BIND_VMETHOD(MethodInfo("_initialize")); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_iteration", PropertyInfo(Variant::FLOAT, "delta"))); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_idle", PropertyInfo(Variant::FLOAT, "delta"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_physics_process", PropertyInfo(Variant::FLOAT, "delta"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_process", PropertyInfo(Variant::FLOAT, "delta"))); BIND_VMETHOD(MethodInfo("_finalize")); BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); @@ -49,48 +43,46 @@ void MainLoop::_bind_methods() { BIND_CONSTANT(NOTIFICATION_WM_ABOUT); BIND_CONSTANT(NOTIFICATION_CRASH); BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); - BIND_CONSTANT(NOTIFICATION_APP_RESUMED); - BIND_CONSTANT(NOTIFICATION_APP_PAUSED); + BIND_CONSTANT(NOTIFICATION_APPLICATION_RESUMED); + BIND_CONSTANT(NOTIFICATION_APPLICATION_PAUSED); + BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_IN); + BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT); + BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED); ADD_SIGNAL(MethodInfo("on_request_permissions_result", PropertyInfo(Variant::STRING, "permission"), PropertyInfo(Variant::BOOL, "granted"))); }; -void MainLoop::set_init_script(const Ref<Script> &p_init_script) { - - init_script = p_init_script; -} - -MainLoop::MainLoop() { -} - -MainLoop::~MainLoop() { +void MainLoop::set_initialize_script(const Ref<Script> &p_initialize_script) { + initialize_script = p_initialize_script; } -void MainLoop::init() { - - if (init_script.is_valid()) - set_script(init_script); +void MainLoop::initialize() { + if (initialize_script.is_valid()) { + set_script(initialize_script); + } - if (get_script_instance()) + if (get_script_instance()) { get_script_instance()->call("_initialize"); + } } -bool MainLoop::iteration(float p_time) { - if (get_script_instance()) - return get_script_instance()->call("_iteration", p_time); +bool MainLoop::physics_process(float p_time) { + if (get_script_instance()) { + return get_script_instance()->call("_physics_process", p_time); + } return false; } -bool MainLoop::idle(float p_time) { - if (get_script_instance()) - return get_script_instance()->call("_idle", p_time); +bool MainLoop::process(float p_time) { + if (get_script_instance()) { + return get_script_instance()->call("_process", p_time); + } return false; } -void MainLoop::finish() { - +void MainLoop::finalize() { if (get_script_instance()) { get_script_instance()->call("_finalize"); set_script(Variant()); //clear script diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 8f6c8c91b1..25a09fe98f 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -32,15 +32,14 @@ #define MAIN_LOOP_H #include "core/input/input_event.h" -#include "core/reference.h" -#include "core/script_language.h" +#include "core/object/reference.h" +#include "core/object/script_language.h" class MainLoop : public Object { - GDCLASS(MainLoop, Object); OBJ_CATEGORY("Main Loop"); - Ref<Script> init_script; + Ref<Script> initialize_script; protected: static void _bind_methods(); @@ -53,19 +52,22 @@ public: NOTIFICATION_WM_ABOUT = 2011, NOTIFICATION_CRASH = 2012, NOTIFICATION_OS_IME_UPDATE = 2013, - NOTIFICATION_APP_RESUMED = 2014, - NOTIFICATION_APP_PAUSED = 2015, + NOTIFICATION_APPLICATION_RESUMED = 2014, + NOTIFICATION_APPLICATION_PAUSED = 2015, + NOTIFICATION_APPLICATION_FOCUS_IN = 2016, + NOTIFICATION_APPLICATION_FOCUS_OUT = 2017, + NOTIFICATION_TEXT_SERVER_CHANGED = 2018, }; - virtual void init(); - virtual bool iteration(float p_time); - virtual bool idle(float p_time); - virtual void finish(); + virtual void initialize(); + virtual bool physics_process(float p_time); + virtual bool process(float p_time); + virtual void finalize(); - void set_init_script(const Ref<Script> &p_init_script); + void set_initialize_script(const Ref<Script> &p_initialize_script); - MainLoop(); - virtual ~MainLoop(); + MainLoop() {} + virtual ~MainLoop() {} }; #endif // MAIN_LOOP_H diff --git a/core/os/memory.cpp b/core/os/memory.cpp index d921c10ad4..14808c2ce6 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -30,36 +30,31 @@ #include "memory.h" -#include "core/error_macros.h" +#include "core/error/error_macros.h" #include "core/os/copymem.h" -#include "core/safe_refcount.h" +#include "core/templates/safe_refcount.h" #include <stdio.h> #include <stdlib.h> void *operator new(size_t p_size, const char *p_description) { - return Memory::alloc_static(p_size, false); } void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) { - return p_allocfunc(p_size); } #ifdef _MSC_VER void operator delete(void *p_mem, const char *p_description) { - CRASH_NOW_MSG("Call to placement delete should not happen."); } void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) { - CRASH_NOW_MSG("Call to placement delete should not happen."); } void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) { - CRASH_NOW_MSG("Call to placement delete should not happen."); } #endif @@ -72,7 +67,6 @@ uint64_t Memory::max_usage = 0; uint64_t Memory::alloc_count = 0; void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { - #ifdef DEBUG_ENABLED bool prepad = true; #else @@ -102,7 +96,6 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { } void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { - if (p_memory == nullptr) { return alloc_static(p_bytes, p_pad_align); } @@ -144,7 +137,6 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { return mem + PAD_ALIGN; } } else { - mem = (uint8_t *)realloc(mem, p_bytes); ERR_FAIL_COND_V(mem == nullptr && p_bytes > 0, nullptr); @@ -154,7 +146,6 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { } void Memory::free_static(void *p_ptr, bool p_pad_align) { - ERR_FAIL_COND(p_ptr == nullptr); uint8_t *mem = (uint8_t *)p_ptr; @@ -177,13 +168,11 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) { free(mem); } else { - free(mem); } } uint64_t Memory::get_mem_available() { - return -1; // 0xFFFF... } @@ -204,8 +193,6 @@ uint64_t Memory::get_mem_max_usage() { } _GlobalNil::_GlobalNil() { - - color = 1; left = this; right = this; parent = this; diff --git a/core/os/memory.h b/core/os/memory.h index dcaedd92ba..c2ae3f4ae7 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,8 +31,8 @@ #ifndef MEMORY_H #define MEMORY_H -#include "core/error_macros.h" -#include "core/safe_refcount.h" +#include "core/error/error_macros.h" +#include "core/templates/safe_refcount.h" #include <stddef.h> @@ -41,7 +41,6 @@ #endif class Memory { - Memory(); #ifdef DEBUG_ENABLED static uint64_t mem_usage; @@ -87,7 +86,6 @@ _ALWAYS_INLINE_ void postinitialize_handler(void *) {} template <class T> _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { - postinitialize_handler(p_obj); return p_obj; } @@ -110,44 +108,48 @@ _ALWAYS_INLINE_ bool predelete_handler(void *) { template <class T> void memdelete(T *p_class) { - - if (!predelete_handler(p_class)) + if (!predelete_handler(p_class)) { return; // doesn't want to be deleted - if (!__has_trivial_destructor(T)) + } + if (!__has_trivial_destructor(T)) { p_class->~T(); + } Memory::free_static(p_class, false); } template <class T, class A> void memdelete_allocator(T *p_class) { - - if (!predelete_handler(p_class)) + if (!predelete_handler(p_class)) { return; // doesn't want to be deleted - if (!__has_trivial_destructor(T)) + } + if (!__has_trivial_destructor(T)) { p_class->~T(); + } A::free(p_class); } -#define memdelete_notnull(m_v) \ - { \ - if (m_v) memdelete(m_v); \ +#define memdelete_notnull(m_v) \ + { \ + if (m_v) { \ + memdelete(m_v); \ + } \ } #define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count) template <typename T> T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { - - if (p_elements == 0) - return 0; + if (p_elements == 0) { + return nullptr; + } /** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the same strategy used by std::vector, and the Vector class, so it should be safe.*/ size_t len = sizeof(T) * p_elements; uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true); - T *failptr = 0; //get rid of a warning + T *failptr = nullptr; //get rid of a warning ERR_FAIL_COND_V(!mem, failptr); *(mem - 1) = p_elements; @@ -170,14 +172,12 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { template <typename T> size_t memarr_len(const T *p_class) { - uint64_t *ptr = (uint64_t *)p_class; return *(ptr - 1); } template <typename T> void memdelete_arr(T *p_class) { - uint64_t *ptr = (uint64_t *)p_class; if (!__has_trivial_destructor(T)) { @@ -192,8 +192,7 @@ void memdelete_arr(T *p_class) { } struct _GlobalNil { - - int color; + int color = 1; _GlobalNil *right; _GlobalNil *left; _GlobalNil *parent; @@ -202,7 +201,6 @@ struct _GlobalNil { }; struct _GlobalNilClass { - static _GlobalNil _nil; }; diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp index efd87d3ab6..a8be84c56c 100644 --- a/core/os/midi_driver.cpp +++ b/core/os/midi_driver.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -36,17 +36,14 @@ uint8_t MIDIDriver::last_received_message = 0x00; MIDIDriver *MIDIDriver::singleton = nullptr; MIDIDriver *MIDIDriver::get_singleton() { - return singleton; } void MIDIDriver::set_singleton() { - singleton = this; } void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) { - Ref<InputEventMIDI> event; event.instance(); uint32_t param_position = 1; @@ -122,12 +119,10 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_ } PackedStringArray MIDIDriver::get_connected_inputs() { - PackedStringArray list; return list; } MIDIDriver::MIDIDriver() { - set_singleton(); } diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h index b7377a8a40..ccf624e07e 100644 --- a/core/os/midi_driver.h +++ b/core/os/midi_driver.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -32,14 +32,13 @@ #define MIDI_DRIVER_H #include "core/typedefs.h" -#include "core/variant.h" +#include "core/variant/variant.h" /** * Multi-Platform abstraction for accessing to MIDI. */ class MIDIDriver { - static MIDIDriver *singleton; static uint8_t last_received_message; diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp index 31a0dc2bfa..b7d7752d35 100644 --- a/core/os/mutex.cpp +++ b/core/os/mutex.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ diff --git a/core/os/mutex.h b/core/os/mutex.h index 526549dd93..d77ec362a1 100644 --- a/core/os/mutex.h +++ b/core/os/mutex.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,7 +31,7 @@ #ifndef MUTEX_H #define MUTEX_H -#include "core/error_list.h" +#include "core/error/error_list.h" #include "core/typedefs.h" #if !defined(NO_THREADS) @@ -82,8 +82,7 @@ extern template class MutexLock<MutexImpl<std::mutex>>; #else class FakeMutex { - - FakeMutex(){}; + FakeMutex() {} }; template <class MutexT> diff --git a/core/os/os.cpp b/core/os/os.cpp index 425132fbec..182bab4058 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -30,20 +30,20 @@ #include "os.h" +#include "core/config/project_settings.h" #include "core/input/input.h" #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/os/midi_driver.h" -#include "core/project_settings.h" #include "core/version_generated.gen.h" #include "servers/audio_server.h" #include <stdarg.h> OS *OS::singleton = nullptr; +uint64_t OS::target_ticks = 0; OS *OS::get_singleton() { - return singleton; } @@ -80,23 +80,13 @@ String OS::get_iso_date_time(bool local) const { timezone; } -uint64_t OS::get_splash_tick_msec() const { - return _msec_splash; -} -uint64_t OS::get_unix_time() const { - - return 0; -}; -uint64_t OS::get_system_time_secs() const { - return 0; -} -uint64_t OS::get_system_time_msecs() const { +double OS::get_unix_time() const { return 0; } -void OS::debug_break(){ +void OS::debug_break() { // something -}; +} void OS::_set_logger(CompositeLogger *p_logger) { if (_logger) { @@ -116,19 +106,17 @@ void OS::add_logger(Logger *p_logger) { } void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type) { - _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); } void OS::print(const char *p_format, ...) { - va_list argp; va_start(argp, p_format); _logger->logv(p_format, argp, false); va_end(argp); -}; +} void OS::printerr(const char *p_format, ...) { va_list argp; @@ -137,73 +125,67 @@ void OS::printerr(const char *p_format, ...) { _logger->logv(p_format, argp, true); va_end(argp); -}; +} void OS::set_low_processor_usage_mode(bool p_enabled) { - low_processor_usage_mode = p_enabled; } bool OS::is_in_low_processor_usage_mode() const { - return low_processor_usage_mode; } void OS::set_low_processor_usage_mode_sleep_usec(int p_usec) { - low_processor_usage_mode_sleep_usec = p_usec; } int OS::get_low_processor_usage_mode_sleep_usec() const { - return low_processor_usage_mode_sleep_usec; } String OS::get_executable_path() const { - return _execpath; } int OS::get_process_id() const { - return -1; -}; +} void OS::vibrate_handheld(int p_duration_ms) { - WARN_PRINT("vibrate_handheld() only works with Android and iOS"); } bool OS::is_stdout_verbose() const { - return _verbose_stdout; } -void OS::dump_memory_to_file(const char *p_file) { +bool OS::is_stdout_debug_enabled() const { + return _debug_stdout; +} +void OS::dump_memory_to_file(const char *p_file) { //Memory::dump_static_mem_to_file(p_file); } static FileAccess *_OSPRF = nullptr; static void _OS_printres(Object *p_obj) { - Resource *res = Object::cast_to<Resource>(p_obj); - if (!res) + if (!res) { return; + } String str = itos(res->get_instance_id()) + String(res->get_class()) + ":" + String(res->get_name()) + " - " + res->get_path(); - if (_OSPRF) + if (_OSPRF) { _OSPRF->store_line(str); - else + } else { print_line(str); + } } void OS::print_all_resources(String p_to_file) { - ERR_FAIL_COND(p_to_file != "" && _OSPRF); if (p_to_file != "") { - Error err; _OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err); if (err != OK) { @@ -215,50 +197,43 @@ void OS::print_all_resources(String p_to_file) { ObjectDB::debug_objects(_OS_printres); if (p_to_file != "") { - - if (_OSPRF) + if (_OSPRF) { memdelete(_OSPRF); + } _OSPRF = nullptr; } } void OS::print_resources_in_use(bool p_short) { - ResourceCache::dump(nullptr, p_short); } void OS::dump_resources_to_file(const char *p_file) { - ResourceCache::dump(p_file); } void OS::set_no_window_mode(bool p_enable) { - _no_window = p_enable; } bool OS::is_no_window_mode_enabled() const { - return _no_window; } int OS::get_exit_code() const { - return _exit_code; } -void OS::set_exit_code(int p_code) { +void OS::set_exit_code(int p_code) { _exit_code = p_code; } String OS::get_locale() const { - return "en"; } // Helper function to ensure that a dir name/path will be valid on the OS String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_dir_separator) const { - Vector<String> invalid_chars = String(": * ? \" < > |").split(" "); if (p_allow_dir_separator) { // Dir separators are allowed, but disallow ".." to avoid going up the filesystem @@ -278,76 +253,64 @@ String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_dir_separato // Get properly capitalized engine name for system paths String OS::get_godot_dir_name() const { - // Default to lowercase, so only override when different case is needed return String(VERSION_SHORT_NAME).to_lower(); } // OS equivalent of XDG_DATA_HOME String OS::get_data_path() const { - return "."; } // OS equivalent of XDG_CONFIG_HOME String OS::get_config_path() const { - return "."; } // OS equivalent of XDG_CACHE_HOME String OS::get_cache_path() const { - return "."; } // Path to macOS .app bundle resources String OS::get_bundle_resource_dir() const { - return "."; -}; +} // OS specific path for user:// String OS::get_user_data_dir() const { - return "."; -}; +} // Absolute path to res:// String OS::get_resource_dir() const { - return ProjectSettings::get_singleton()->get_resource_path(); } // Access system-specific dirs like Documents, Downloads, etc. String OS::get_system_dir(SystemDir p_dir) const { - return "."; } Error OS::shell_open(String p_uri) { return ERR_UNAVAILABLE; -}; +} // implement these with the canvas? uint64_t OS::get_static_memory_usage() const { - return Memory::get_mem_usage(); } uint64_t OS::get_static_memory_peak_usage() const { - return Memory::get_mem_max_usage(); } Error OS::set_cwd(const String &p_cwd) { - return ERR_CANT_OPEN; } uint64_t OS::get_free_static_memory() const { - return Memory::get_mem_available(); } @@ -355,7 +318,6 @@ void OS::yield() { } void OS::ensure_user_data_dir() { - String dd = get_user_data_dir(); DirAccess *da = DirAccess::open(dd); if (da) { @@ -371,28 +333,23 @@ void OS::ensure_user_data_dir() { } String OS::get_model_name() const { - return "GenericDevice"; } void OS::set_cmdline(const char *p_execpath, const List<String> &p_args) { - _execpath = p_execpath; _cmdline = p_args; -}; +} String OS::get_unique_id() const { - ERR_FAIL_V(""); } int OS::get_processor_count() const { - return 1; } bool OS::can_use_threads() const { - #ifdef NO_THREADS return false; #else @@ -401,24 +358,25 @@ bool OS::can_use_threads() const { } void OS::set_has_server_feature_callback(HasServerFeatureCallback p_callback) { - has_server_feature_callback = p_callback; } bool OS::has_feature(const String &p_feature) { - - if (p_feature == get_name()) + if (p_feature == get_name()) { return true; + } #ifdef DEBUG_ENABLED - if (p_feature == "debug") + if (p_feature == "debug") { return true; + } #else if (p_feature == "release") return true; #endif #ifdef TOOLS_ENABLED - if (p_feature == "editor") + if (p_feature == "editor") { return true; + } #else if (p_feature == "standalone") return true; @@ -458,15 +416,17 @@ bool OS::has_feature(const String &p_feature) { } #endif - if (_check_internal_feature_support(p_feature)) + if (_check_internal_feature_support(p_feature)) { return true; + } if (has_server_feature_callback && has_server_feature_callback(p_feature)) { return true; } - if (ProjectSettings::get_singleton()->has_custom_feature(p_feature)) + if (ProjectSettings::get_singleton()->has_custom_feature(p_feature)) { return true; + } return false; } @@ -485,47 +445,67 @@ List<String> OS::get_restart_on_exit_arguments() const { } PackedStringArray OS::get_connected_midi_inputs() { - - if (MIDIDriver::get_singleton()) + if (MIDIDriver::get_singleton()) { return MIDIDriver::get_singleton()->get_connected_inputs(); + } PackedStringArray list; - return list; + ERR_FAIL_V_MSG(list, vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name())); } void OS::open_midi_inputs() { - - if (MIDIDriver::get_singleton()) + if (MIDIDriver::get_singleton()) { MIDIDriver::get_singleton()->open(); + } else { + ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name())); + } } void OS::close_midi_inputs() { - - if (MIDIDriver::get_singleton()) + if (MIDIDriver::get_singleton()) { MIDIDriver::get_singleton()->close(); + } else { + ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name())); + } } -OS::OS() { - void *volatile stack_bottom; +void OS::add_frame_delay(bool p_can_draw) { + const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); + if (frame_delay) { + // Add fixed frame delay to decrease CPU/GPU usage. This doesn't take + // the actual frame time into account. + // Due to the high fluctuation of the actual sleep duration, it's not recommended + // to use this as a FPS limiter. + delay_usec(frame_delay * 1000); + } - restart_on_exit = false; - singleton = this; - _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. - low_processor_usage_mode = false; - low_processor_usage_mode_sleep_usec = 10000; - _verbose_stdout = false; - _no_window = false; - _exit_code = 0; + // Add a dynamic frame delay to decrease CPU/GPU usage. This takes the + // previous frame time into account for a smoother result. + uint64_t dynamic_delay = 0; + if (is_in_low_processor_usage_mode() || !p_can_draw) { + dynamic_delay = get_low_processor_usage_mode_sleep_usec(); + } + const int target_fps = Engine::get_singleton()->get_target_fps(); + if (target_fps > 0 && !Engine::get_singleton()->is_editor_hint()) { + // Override the low processor usage mode sleep delay if the target FPS is lower. + dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / target_fps)); + } - _render_thread_mode = RENDER_THREAD_SAFE; + if (dynamic_delay > 0) { + target_ticks += dynamic_delay; + uint64_t current_ticks = get_ticks_usec(); - _allow_hidpi = false; - _allow_layered = false; - _stack_bottom = (void *)(&stack_bottom); + if (current_ticks < target_ticks) { + delay_usec(target_ticks - current_ticks); + } - _logger = nullptr; + current_ticks = get_ticks_usec(); + target_ticks = MIN(MAX(target_ticks, current_ticks - dynamic_delay), current_ticks + dynamic_delay); + } +} - has_server_feature_callback = nullptr; +OS::OS() { + singleton = this; Vector<Logger *> loggers; loggers.push_back(memnew(StdLogger)); diff --git a/core/os/os.h b/core/os/os.h index 38114e6814..e02ce7d5ec 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,43 +31,40 @@ #ifndef OS_H #define OS_H -#include "core/engine.h" -#include "core/image.h" +#include "core/config/engine.h" +#include "core/io/image.h" #include "core/io/logger.h" -#include "core/list.h" #include "core/os/main_loop.h" -#include "core/ustring.h" -#include "core/vector.h" +#include "core/string/ustring.h" +#include "core/templates/list.h" +#include "core/templates/vector.h" #include <stdarg.h> class OS { - static OS *singleton; + static uint64_t target_ticks; String _execpath; List<String> _cmdline; - bool _keep_screen_on; - bool low_processor_usage_mode; - int low_processor_usage_mode_sleep_usec; - bool _verbose_stdout; + bool _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. + bool low_processor_usage_mode = false; + int low_processor_usage_mode_sleep_usec = 10000; + bool _verbose_stdout = false; + bool _debug_stdout = false; String _local_clipboard; - uint64_t _msec_splash; - bool _no_window; - int _exit_code; + bool _no_window = false; + int _exit_code = 0; int _orientation; - bool _allow_hidpi; - bool _allow_layered; + bool _allow_hidpi = false; + bool _allow_layered = false; bool _use_vsync; bool _vsync_via_compositor; - bool _disable_wintab; char *last_error; - void *_stack_bottom; - - CompositeLogger *_logger; + CompositeLogger *_logger = nullptr; - bool restart_on_exit; + bool restart_on_exit = false; List<String> restart_commandline; protected: @@ -78,7 +75,6 @@ public: typedef bool (*HasServerFeatureCallback)(const String &p_feature); enum RenderThreadMode { - RENDER_THREAD_UNSAFE, RENDER_THREAD_SAFE, RENDER_SEPARATE_THREAD @@ -86,11 +82,13 @@ public: protected: friend class Main; + // Needed by tests to setup command-line args. + friend int test_main(int argc, char *argv[]); - HasServerFeatureCallback has_server_feature_callback; - RenderThreadMode _render_thread_mode; + HasServerFeatureCallback has_server_feature_callback = nullptr; + RenderThreadMode _render_thread_mode = RENDER_THREAD_SAFE; - // functions used by main to initialize/deinitialize the OS + // Functions used by Main to initialize/deinitialize the OS. void add_logger(Logger *p_logger); virtual void initialize() = 0; @@ -131,7 +129,8 @@ public: virtual int get_low_processor_usage_mode_sleep_usec() const; virtual String get_executable_path() const; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0; + virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) = 0; virtual Error kill(const ProcessID &p_pid) = 0; virtual int get_process_id() const; virtual void vibrate_handheld(int p_duration_ms = 500); @@ -149,7 +148,11 @@ public: bool is_layered_allowed() const { return _allow_layered; } bool is_hidpi_allowed() const { return _allow_hidpi; } - bool is_wintab_disabled() const { return _disable_wintab; } + + virtual int get_tablet_driver_count() const { return 0; }; + virtual String get_tablet_driver_name(int p_driver) const { return ""; }; + virtual String get_current_tablet_driver() const { return ""; }; + virtual void set_current_tablet_driver(const String &p_driver){}; void ensure_user_data_dir(); @@ -185,7 +188,6 @@ public: }; struct Date { - int year; Month month; int day; @@ -194,7 +196,6 @@ public: }; struct Time { - int hour; int min; int sec; @@ -209,18 +210,18 @@ public: virtual Time get_time(bool local = false) const = 0; virtual TimeZoneInfo get_time_zone_info() const = 0; virtual String get_iso_date_time(bool local = false) const; - virtual uint64_t get_unix_time() const; - virtual uint64_t get_system_time_secs() const; - virtual uint64_t get_system_time_msecs() const; + virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; + virtual void add_frame_delay(bool p_can_draw); + virtual uint64_t get_ticks_usec() const = 0; uint32_t get_ticks_msec() const; - uint64_t get_splash_tick_msec() const; virtual bool is_userfs_persistent() const { return true; } bool is_stdout_verbose() const; + bool is_stdout_debug_enabled() const; virtual void disable_crash_handler() {} virtual bool is_disable_crash_handler() const { return false; } diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp new file mode 100644 index 0000000000..b538ca0c96 --- /dev/null +++ b/core/os/pool_allocator.cpp @@ -0,0 +1,596 @@ +/*************************************************************************/ +/* pool_allocator.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 "pool_allocator.h" + +#include "core/error/error_macros.h" +#include "core/os/copymem.h" +#include "core/os/memory.h" +#include "core/os/os.h" +#include "core/string/print_string.h" + +#include <assert.h> + +#define COMPACT_CHUNK(m_entry, m_to_pos) \ + do { \ + void *_dst = &((unsigned char *)pool)[m_to_pos]; \ + void *_src = &((unsigned char *)pool)[(m_entry).pos]; \ + movemem(_dst, _src, aligned((m_entry).len)); \ + (m_entry).pos = m_to_pos; \ + } while (0); + +void PoolAllocator::mt_lock() const { +} + +void PoolAllocator::mt_unlock() const { +} + +bool PoolAllocator::get_free_entry(EntryArrayPos *p_pos) { + if (entry_count == entry_max) { + return false; + } + + for (int i = 0; i < entry_max; i++) { + if (entry_array[i].len == 0) { + *p_pos = i; + return true; + } + } + + ERR_PRINT("Out of memory Chunks!"); + + return false; // +} + +/** + * Find a hole + * @param p_pos The hole is behind the block pointed by this variable upon return. if pos==entry_count, then allocate at end + * @param p_for_size hole size + * @return false if hole found, true if no hole found + */ +bool PoolAllocator::find_hole(EntryArrayPos *p_pos, int p_for_size) { + /* position where previous entry ends. Defaults to zero (begin of pool) */ + + int prev_entry_end_pos = 0; + + for (int i = 0; i < entry_count; i++) { + Entry &entry = entry_array[entry_indices[i]]; + + /* determine hole size to previous entry */ + + int hole_size = entry.pos - prev_entry_end_pos; + + /* determine if what we want fits in that hole */ + if (hole_size >= p_for_size) { + *p_pos = i; + return true; + } + + /* prepare for next one */ + prev_entry_end_pos = entry_end(entry); + } + + /* No holes between entries, check at the end..*/ + + if ((pool_size - prev_entry_end_pos) >= p_for_size) { + *p_pos = entry_count; + return true; + } + + return false; +} + +void PoolAllocator::compact(int p_up_to) { + uint32_t prev_entry_end_pos = 0; + + if (p_up_to < 0) { + p_up_to = entry_count; + } + for (int i = 0; i < p_up_to; i++) { + Entry &entry = entry_array[entry_indices[i]]; + + /* determine hole size to previous entry */ + + int hole_size = entry.pos - prev_entry_end_pos; + + /* if we can compact, do it */ + if (hole_size > 0 && !entry.lock) { + COMPACT_CHUNK(entry, prev_entry_end_pos); + } + + /* prepare for next one */ + prev_entry_end_pos = entry_end(entry); + } +} + +void PoolAllocator::compact_up(int p_from) { + uint32_t next_entry_end_pos = pool_size; // - static_area_size; + + for (int i = entry_count - 1; i >= p_from; i--) { + Entry &entry = entry_array[entry_indices[i]]; + + /* determine hole size to nextious entry */ + + int hole_size = next_entry_end_pos - (entry.pos + aligned(entry.len)); + + /* if we can compact, do it */ + if (hole_size > 0 && !entry.lock) { + COMPACT_CHUNK(entry, (next_entry_end_pos - aligned(entry.len))); + } + + /* prepare for next one */ + next_entry_end_pos = entry.pos; + } +} + +bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, Entry *p_entry) { + EntryArrayPos entry_pos = entry_max; + + for (int i = 0; i < entry_count; i++) { + if (&entry_array[entry_indices[i]] == p_entry) { + entry_pos = i; + break; + } + } + + if (entry_pos == entry_max) { + return false; + } + + *p_map_pos = entry_pos; + return true; +} + +PoolAllocator::ID PoolAllocator::alloc(int p_size) { + ERR_FAIL_COND_V(p_size < 1, POOL_ALLOCATOR_INVALID_ID); +#ifdef DEBUG_ENABLED + if (p_size > free_mem) { + OS::get_singleton()->debug_break(); + } +#endif + ERR_FAIL_COND_V(p_size > free_mem, POOL_ALLOCATOR_INVALID_ID); + + mt_lock(); + + if (entry_count == entry_max) { + mt_unlock(); + ERR_PRINT("entry_count==entry_max"); + return POOL_ALLOCATOR_INVALID_ID; + } + + int size_to_alloc = aligned(p_size); + + EntryIndicesPos new_entry_indices_pos; + + if (!find_hole(&new_entry_indices_pos, size_to_alloc)) { + /* No hole could be found, try compacting mem */ + compact(); + /* Then search again */ + + if (!find_hole(&new_entry_indices_pos, size_to_alloc)) { + mt_unlock(); + ERR_FAIL_V_MSG(POOL_ALLOCATOR_INVALID_ID, "Memory can't be compacted further."); + } + } + + EntryArrayPos new_entry_array_pos; + + bool found_free_entry = get_free_entry(&new_entry_array_pos); + + if (!found_free_entry) { + mt_unlock(); + ERR_FAIL_V_MSG(POOL_ALLOCATOR_INVALID_ID, "No free entry found in PoolAllocator."); + } + + /* move all entry indices up, make room for this one */ + for (int i = entry_count; i > new_entry_indices_pos; i--) { + entry_indices[i] = entry_indices[i - 1]; + } + + entry_indices[new_entry_indices_pos] = new_entry_array_pos; + + entry_count++; + + Entry &entry = entry_array[entry_indices[new_entry_indices_pos]]; + + entry.len = p_size; + entry.pos = (new_entry_indices_pos == 0) ? 0 : entry_end(entry_array[entry_indices[new_entry_indices_pos - 1]]); //alloc either at beginning or end of previous + entry.lock = 0; + entry.check = (check_count++) & CHECK_MASK; + free_mem -= size_to_alloc; + if (free_mem < free_mem_peak) { + free_mem_peak = free_mem; + } + + ID retval = (entry_indices[new_entry_indices_pos] << CHECK_BITS) | entry.check; + mt_unlock(); + + //ERR_FAIL_COND_V( (uintptr_t)get(retval)%align != 0, retval ); + + return retval; +} + +PoolAllocator::Entry *PoolAllocator::get_entry(ID p_mem) { + unsigned int check = p_mem & CHECK_MASK; + int entry = p_mem >> CHECK_BITS; + ERR_FAIL_INDEX_V(entry, entry_max, nullptr); + ERR_FAIL_COND_V(entry_array[entry].check != check, nullptr); + ERR_FAIL_COND_V(entry_array[entry].len == 0, nullptr); + + return &entry_array[entry]; +} + +const PoolAllocator::Entry *PoolAllocator::get_entry(ID p_mem) const { + unsigned int check = p_mem & CHECK_MASK; + int entry = p_mem >> CHECK_BITS; + ERR_FAIL_INDEX_V(entry, entry_max, nullptr); + ERR_FAIL_COND_V(entry_array[entry].check != check, nullptr); + ERR_FAIL_COND_V(entry_array[entry].len == 0, nullptr); + + return &entry_array[entry]; +} + +void PoolAllocator::free(ID p_mem) { + mt_lock(); + Entry *e = get_entry(p_mem); + if (!e) { + mt_unlock(); + ERR_PRINT("!e"); + return; + } + if (e->lock) { + mt_unlock(); + ERR_PRINT("e->lock"); + return; + } + + EntryIndicesPos entry_indices_pos; + + bool index_found = find_entry_index(&entry_indices_pos, e); + if (!index_found) { + mt_unlock(); + ERR_FAIL_COND(!index_found); + } + + for (int i = entry_indices_pos; i < (entry_count - 1); i++) { + entry_indices[i] = entry_indices[i + 1]; + } + + entry_count--; + free_mem += aligned(e->len); + e->clear(); + mt_unlock(); +} + +int PoolAllocator::get_size(ID p_mem) const { + int size; + mt_lock(); + + const Entry *e = get_entry(p_mem); + if (!e) { + mt_unlock(); + ERR_PRINT("!e"); + return 0; + } + + size = e->len; + + mt_unlock(); + + return size; +} + +Error PoolAllocator::resize(ID p_mem, int p_new_size) { + mt_lock(); + Entry *e = get_entry(p_mem); + + if (!e) { + mt_unlock(); + ERR_FAIL_COND_V(!e, ERR_INVALID_PARAMETER); + } + + if (needs_locking && e->lock) { + mt_unlock(); + ERR_FAIL_COND_V(e->lock, ERR_ALREADY_IN_USE); + } + + uint32_t alloc_size = aligned(p_new_size); + + if ((uint32_t)aligned(e->len) == alloc_size) { + e->len = p_new_size; + mt_unlock(); + return OK; + } else if (e->len > (uint32_t)p_new_size) { + free_mem += aligned(e->len); + free_mem -= alloc_size; + e->len = p_new_size; + mt_unlock(); + return OK; + } + + //p_new_size = align(p_new_size) + int _free = free_mem; // - static_area_size; + + if (uint32_t(_free + aligned(e->len)) < alloc_size) { + mt_unlock(); + ERR_FAIL_V(ERR_OUT_OF_MEMORY); + } + + EntryIndicesPos entry_indices_pos; + + bool index_found = find_entry_index(&entry_indices_pos, e); + + if (!index_found) { + mt_unlock(); + ERR_FAIL_COND_V(!index_found, ERR_BUG); + } + + //no need to move stuff around, it fits before the next block + uint32_t next_pos; + if (entry_indices_pos + 1 == entry_count) { + next_pos = pool_size; // - static_area_size; + } else { + next_pos = entry_array[entry_indices[entry_indices_pos + 1]].pos; + } + + if ((next_pos - e->pos) > alloc_size) { + free_mem += aligned(e->len); + e->len = p_new_size; + free_mem -= alloc_size; + mt_unlock(); + return OK; + } + //it doesn't fit, compact around BEFORE current index (make room behind) + + compact(entry_indices_pos + 1); + + if ((next_pos - e->pos) > alloc_size) { + //now fits! hooray! + free_mem += aligned(e->len); + e->len = p_new_size; + free_mem -= alloc_size; + mt_unlock(); + if (free_mem < free_mem_peak) { + free_mem_peak = free_mem; + } + return OK; + } + + //STILL doesn't fit, compact around AFTER current index (make room after) + + compact_up(entry_indices_pos + 1); + + if ((entry_array[entry_indices[entry_indices_pos + 1]].pos - e->pos) > alloc_size) { + //now fits! hooray! + free_mem += aligned(e->len); + e->len = p_new_size; + free_mem -= alloc_size; + mt_unlock(); + if (free_mem < free_mem_peak) { + free_mem_peak = free_mem; + } + return OK; + } + + mt_unlock(); + ERR_FAIL_V(ERR_OUT_OF_MEMORY); +} + +Error PoolAllocator::lock(ID p_mem) { + if (!needs_locking) { + return OK; + } + mt_lock(); + Entry *e = get_entry(p_mem); + if (!e) { + mt_unlock(); + ERR_PRINT("!e"); + return ERR_INVALID_PARAMETER; + } + e->lock++; + mt_unlock(); + return OK; +} + +bool PoolAllocator::is_locked(ID p_mem) const { + if (!needs_locking) { + return false; + } + + mt_lock(); + const Entry *e = ((PoolAllocator *)(this))->get_entry(p_mem); + if (!e) { + mt_unlock(); + ERR_PRINT("!e"); + return false; + } + bool locked = e->lock; + mt_unlock(); + return locked; +} + +const void *PoolAllocator::get(ID p_mem) const { + if (!needs_locking) { + const Entry *e = get_entry(p_mem); + ERR_FAIL_COND_V(!e, nullptr); + return &pool[e->pos]; + } + + mt_lock(); + const Entry *e = get_entry(p_mem); + + if (!e) { + mt_unlock(); + ERR_FAIL_COND_V(!e, nullptr); + } + if (e->lock == 0) { + mt_unlock(); + ERR_PRINT("e->lock == 0"); + return nullptr; + } + + if ((int)e->pos >= pool_size) { + mt_unlock(); + ERR_PRINT("e->pos<0 || e->pos>=pool_size"); + return nullptr; + } + const void *ptr = &pool[e->pos]; + + mt_unlock(); + + return ptr; +} + +void *PoolAllocator::get(ID p_mem) { + if (!needs_locking) { + Entry *e = get_entry(p_mem); + ERR_FAIL_COND_V(!e, nullptr); + return &pool[e->pos]; + } + + mt_lock(); + Entry *e = get_entry(p_mem); + + if (!e) { + mt_unlock(); + ERR_FAIL_COND_V(!e, nullptr); + } + if (e->lock == 0) { + //assert(0); + mt_unlock(); + ERR_PRINT("e->lock == 0"); + return nullptr; + } + + if ((int)e->pos >= pool_size) { + mt_unlock(); + ERR_PRINT("e->pos<0 || e->pos>=pool_size"); + return nullptr; + } + void *ptr = &pool[e->pos]; + + mt_unlock(); + + return ptr; +} + +void PoolAllocator::unlock(ID p_mem) { + if (!needs_locking) { + return; + } + mt_lock(); + Entry *e = get_entry(p_mem); + if (!e) { + mt_unlock(); + ERR_FAIL_COND(!e); + } + if (e->lock == 0) { + mt_unlock(); + ERR_PRINT("e->lock == 0"); + return; + } + e->lock--; + mt_unlock(); +} + +int PoolAllocator::get_used_mem() const { + return pool_size - free_mem; +} + +int PoolAllocator::get_free_peak() { + return free_mem_peak; +} + +int PoolAllocator::get_free_mem() { + return free_mem; +} + +void PoolAllocator::create_pool(void *p_mem, int p_size, int p_max_entries) { + pool = (uint8_t *)p_mem; + pool_size = p_size; + + entry_array = memnew_arr(Entry, p_max_entries); + entry_indices = memnew_arr(int, p_max_entries); + entry_max = p_max_entries; + entry_count = 0; + + free_mem = p_size; + free_mem_peak = p_size; + + check_count = 0; +} + +PoolAllocator::PoolAllocator(int p_size, bool p_needs_locking, int p_max_entries) { + mem_ptr = memalloc(p_size); + ERR_FAIL_COND(!mem_ptr); + align = 1; + create_pool(mem_ptr, p_size, p_max_entries); + needs_locking = p_needs_locking; +} + +PoolAllocator::PoolAllocator(void *p_mem, int p_size, int p_align, bool p_needs_locking, int p_max_entries) { + if (p_align > 1) { + uint8_t *mem8 = (uint8_t *)p_mem; + uint64_t ofs = (uint64_t)mem8; + if (ofs % p_align) { + int dif = p_align - (ofs % p_align); + mem8 += p_align - (ofs % p_align); + p_size -= dif; + p_mem = (void *)mem8; + } + } + + create_pool(p_mem, p_size, p_max_entries); + needs_locking = p_needs_locking; + align = p_align; + mem_ptr = nullptr; +} + +PoolAllocator::PoolAllocator(int p_align, int p_size, bool p_needs_locking, int p_max_entries) { + ERR_FAIL_COND(p_align < 1); + mem_ptr = Memory::alloc_static(p_size + p_align, true); + uint8_t *mem8 = (uint8_t *)mem_ptr; + uint64_t ofs = (uint64_t)mem8; + if (ofs % p_align) { + mem8 += p_align - (ofs % p_align); + } + create_pool(mem8, p_size, p_max_entries); + needs_locking = p_needs_locking; + align = p_align; +} + +PoolAllocator::~PoolAllocator() { + if (mem_ptr) { + memfree(mem_ptr); + } + + memdelete_arr(entry_array); + memdelete_arr(entry_indices); +} diff --git a/core/os/pool_allocator.h b/core/os/pool_allocator.h new file mode 100644 index 0000000000..15e50dac90 --- /dev/null +++ b/core/os/pool_allocator.h @@ -0,0 +1,149 @@ +/*************************************************************************/ +/* pool_allocator.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 POOL_ALLOCATOR_H +#define POOL_ALLOCATOR_H + +#include "core/typedefs.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> + * Generic Pool Allocator. + * This is a generic memory pool allocator, with locking, compacting and alignment. (@TODO alignment) + * It used as a standard way to manage alloction in a specific region of memory, such as texture memory, + * audio sample memory, or just any kind of memory overall. + * (@TODO) abstraction should be greater, because in many platforms, you need to manage a nonreachable memory. +*/ + +enum { + POOL_ALLOCATOR_INVALID_ID = -1 ///< default invalid value. use INVALID_ID( id ) to test +}; + +class PoolAllocator { +public: + typedef int ID; + +private: + enum { + CHECK_BITS = 8, + CHECK_LEN = (1 << CHECK_BITS), + CHECK_MASK = CHECK_LEN - 1 + + }; + + struct Entry { + unsigned int pos = 0; + unsigned int len = 0; + unsigned int lock = 0; + unsigned int check = 0; + + inline void clear() { + pos = 0; + len = 0; + lock = 0; + check = 0; + } + Entry() {} + }; + + typedef int EntryArrayPos; + typedef int EntryIndicesPos; + + Entry *entry_array; + int *entry_indices; + int entry_max; + int entry_count; + + uint8_t *pool; + void *mem_ptr; + int pool_size; + + int free_mem; + int free_mem_peak; + + unsigned int check_count; + int align; + + bool needs_locking; + + inline int entry_end(const Entry &p_entry) const { + return p_entry.pos + aligned(p_entry.len); + } + inline int aligned(int p_size) const { + int rem = p_size % align; + if (rem) { + p_size += align - rem; + } + + return p_size; + } + + void compact(int p_up_to = -1); + void compact_up(int p_from = 0); + bool get_free_entry(EntryArrayPos *p_pos); + bool find_hole(EntryArrayPos *p_pos, int p_for_size); + bool find_entry_index(EntryIndicesPos *p_map_pos, Entry *p_entry); + Entry *get_entry(ID p_mem); + const Entry *get_entry(ID p_mem) const; + + void create_pool(void *p_mem, int p_size, int p_max_entries); + +protected: + virtual void mt_lock() const; ///< Reimplement for custom mt locking + virtual void mt_unlock() const; ///< Reimplement for custom mt locking + +public: + enum { + DEFAULT_MAX_ALLOCS = 4096, + }; + + ID alloc(int p_size); ///< Alloc memory, get an ID on success, POOL_ALOCATOR_INVALID_ID on failure + void free(ID p_mem); ///< Free allocated memory + Error resize(ID p_mem, int p_new_size); ///< resize a memory chunk + int get_size(ID p_mem) const; + + int get_free_mem(); ///< get free memory + int get_used_mem() const; + int get_free_peak(); ///< get free memory + + Error lock(ID p_mem); //@todo move this out + void *get(ID p_mem); + const void *get(ID p_mem) const; + void unlock(ID p_mem); + bool is_locked(ID p_mem) const; + + PoolAllocator(int p_size, bool p_needs_locking = false, int p_max_entries = DEFAULT_MAX_ALLOCS); + PoolAllocator(void *p_mem, int p_size, int p_align = 1, bool p_needs_locking = false, int p_max_entries = DEFAULT_MAX_ALLOCS); + PoolAllocator(int p_align, int p_size, bool p_needs_locking = false, int p_max_entries = DEFAULT_MAX_ALLOCS); + + virtual ~PoolAllocator(); +}; + +#endif // POOL_ALLOCATOR_H diff --git a/core/os/rw_lock.cpp b/core/os/rw_lock.cpp index 1dd2c3bccb..26db0aab30 100644 --- a/core/os/rw_lock.cpp +++ b/core/os/rw_lock.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -30,18 +30,14 @@ #include "rw_lock.h" -#include "core/error_macros.h" +#include "core/error/error_macros.h" #include <stddef.h> RWLock *(*RWLock::create_func)() = nullptr; RWLock *RWLock::create() { - ERR_FAIL_COND_V(!create_func, nullptr); return create_func(); } - -RWLock::~RWLock() { -} diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h index 64dfbef20c..ff6ad3cc4a 100644 --- a/core/os/rw_lock.h +++ b/core/os/rw_lock.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,7 +31,7 @@ #ifndef RW_LOCK_H #define RW_LOCK_H -#include "core/error_list.h" +#include "core/error/error_list.h" class RWLock { protected: @@ -48,34 +48,40 @@ public: static RWLock *create(); ///< Create a rwlock - virtual ~RWLock(); + virtual ~RWLock() {} }; class RWLockRead { - RWLock *lock; public: RWLockRead(const RWLock *p_lock) { lock = const_cast<RWLock *>(p_lock); - if (lock) lock->read_lock(); + if (lock) { + lock->read_lock(); + } } ~RWLockRead() { - if (lock) lock->read_unlock(); + if (lock) { + lock->read_unlock(); + } } }; class RWLockWrite { - RWLock *lock; public: RWLockWrite(RWLock *p_lock) { lock = p_lock; - if (lock) lock->write_lock(); + if (lock) { + lock->write_lock(); + } } ~RWLockWrite() { - if (lock) lock->write_unlock(); + if (lock) { + lock->write_unlock(); + } } }; diff --git a/core/os/semaphore.h b/core/os/semaphore.h index 3d9d1ab984..01ae7a3c65 100644 --- a/core/os/semaphore.h +++ b/core/os/semaphore.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,7 +31,7 @@ #ifndef SEMAPHORE_H #define SEMAPHORE_H -#include "core/error_list.h" +#include "core/error/error_list.h" #include "core/typedefs.h" #if !defined(NO_THREADS) @@ -54,8 +54,9 @@ public: _ALWAYS_INLINE_ void wait() const { std::unique_lock<decltype(mutex_)> lock(mutex_); - while (!count_) // Handle spurious wake-ups. + while (!count_) { // Handle spurious wake-ups. condition_.wait(lock); + } --count_; } diff --git a/core/os/semaphore.cpp b/core/os/spin_lock.h index 93f1e2dff4..929e8b9a58 100644 --- a/core/os/semaphore.cpp +++ b/core/os/spin_lock.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* semaphore.cpp */ +/* spin_lock.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -28,4 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "semaphore.h" +#ifndef SPIN_LOCK_H +#define SPIN_LOCK_H + +#include "core/typedefs.h" + +#include <atomic> + +class SpinLock { + std::atomic_flag locked = ATOMIC_FLAG_INIT; + +public: + _ALWAYS_INLINE_ void lock() { + while (locked.test_and_set(std::memory_order_acquire)) { + ; + } + } + _ALWAYS_INLINE_ void unlock() { + locked.clear(std::memory_order_release); + } +}; +#endif // SPIN_LOCK_H diff --git a/core/os/thread.cpp b/core/os/thread.cpp index 294b52f00c..0ed8825452 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -38,37 +38,29 @@ Error (*Thread::set_name_func)(const String &) = nullptr; Thread::ID Thread::_main_thread_id = 0; Thread::ID Thread::get_caller_id() { - - if (get_thread_id_func) + if (get_thread_id_func) { return get_thread_id_func(); + } return 0; } 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); } return nullptr; } void Thread::wait_to_finish(Thread *p_thread) { - - if (wait_to_finish_func) + if (wait_to_finish_func) { wait_to_finish_func(p_thread); + } } 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() { } diff --git a/core/os/thread.h b/core/os/thread.h index 76d296bcf7..993c7ad33d 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -31,22 +31,20 @@ #ifndef THREAD_H #define THREAD_H +#include "core/string/ustring.h" #include "core/typedefs.h" -#include "core/ustring.h" typedef void (*ThreadCreateCallback)(void *p_userdata); class Thread { public: enum Priority { - PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH }; struct Settings { - Priority priority; Settings() { priority = PRIORITY_NORMAL; } }; @@ -63,7 +61,7 @@ protected: static ID _main_thread_id; - Thread(); + Thread() {} public: virtual ID get_id() const = 0; @@ -74,7 +72,7 @@ public: static void wait_to_finish(Thread *p_thread); ///< waits until thread is finished, and deallocates it. 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(); + virtual ~Thread() {} }; #endif // THREAD_H diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp index 9dcddcae11..006757b8e4 100644 --- a/core/os/thread_dummy.cpp +++ b/core/os/thread_dummy.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -34,16 +34,16 @@ 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; -}; +} RWLock *RWLockDummy::create() { return memnew(RWLockDummy); -}; +} void RWLockDummy::make_default() { RWLock::create_func = &RWLockDummy::create; -}; +} diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h index 066ee498ac..35e19732bf 100644 --- a/core/os/thread_dummy.h +++ b/core/os/thread_dummy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -36,7 +36,6 @@ #include "core/os/thread.h" class ThreadDummy : public Thread { - static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings()); public: @@ -46,7 +45,6 @@ public: }; class RWLockDummy : public RWLock { - static RWLock *create(); public: diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h index 670ee8b125..81de079bf3 100644 --- a/core/os/thread_safe.h +++ b/core/os/thread_safe.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h index 00dc53286e..57f3de20bf 100644 --- a/core/os/threaded_array_processor.h +++ b/core/os/threaded_array_processor.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* 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 */ @@ -35,7 +35,7 @@ #include "core/os/os.h" #include "core/os/thread.h" #include "core/os/thread_safe.h" -#include "core/safe_refcount.h" +#include "core/templates/safe_refcount.h" template <class C, class U> struct ThreadArrayProcessData { @@ -54,19 +54,18 @@ struct ThreadArrayProcessData { template <class T> void process_array_thread(void *ud) { - T &data = *(T *)ud; while (true) { uint32_t index = atomic_increment(&data.index); - if (index >= data.elements) + if (index >= data.elements) { break; + } data.process(index); } } template <class C, class M, class U> void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { - ThreadArrayProcessData<C, U> data; data.method = p_method; data.instance = p_instance; @@ -93,7 +92,6 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us template <class C, class M, class U> void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { - ThreadArrayProcessData<C, U> data; data.method = p_method; data.instance = p_instance; |