diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/bind/core_bind.cpp | 5 | ||||
-rw-r--r-- | core/io/stream_peer_tcp.cpp | 11 | ||||
-rw-r--r-- | core/oa_hash_map.h | 47 | ||||
-rw-r--r-- | core/reference.cpp | 18 | ||||
-rw-r--r-- | core/reference.h | 2 | ||||
-rw-r--r-- | core/safe_refcount.h | 9 |
6 files changed, 39 insertions, 53 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 30aaa0e646..d07ba44788 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -481,15 +481,18 @@ Error _OS::shell_open(String p_uri) { int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) { OS::ProcessID pid = -2; + int exitcode = 0; List<String> args; for (int i = 0; i < p_arguments.size(); i++) args.push_back(p_arguments[i]); String pipe; - Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, NULL, p_read_stderr); + Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, &exitcode, p_read_stderr); p_output.clear(); p_output.push_back(pipe); if (err != OK) return -1; + else if (p_blocking) + return exitcode; else return pid; } diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp index 310bb12bc0..b9c5896b24 100644 --- a/core/io/stream_peer_tcp.cpp +++ b/core/io/stream_peer_tcp.cpp @@ -248,16 +248,7 @@ void StreamPeerTCP::set_no_delay(bool p_enabled) { bool StreamPeerTCP::is_connected_to_host() const { - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return false; - } - - if (status != STATUS_CONNECTED) { - return true; - } - - return _sock.is_valid() && _sock->is_open(); + return _sock.is_valid() && _sock->is_open() && (status == STATUS_CONNECTED || status == STATUS_CONNECTING); } StreamPeerTCP::Status StreamPeerTCP::get_status() { diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index 5ea6d8b0d4..1a466e57f4 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -37,10 +37,11 @@ #include "core/os/memory.h" /** - * A HashMap implementation that uses open addressing with robinhood hashing. - * Robinhood hashing swaps out entries that have a smaller probing distance + * A HashMap implementation that uses open addressing with Robin Hood hashing. + * Robin Hood hashing swaps out entries that have a smaller probing distance * than the to-be-inserted entry, that evens out the average probing distance - * and enables faster lookups. + * and enables faster lookups. Backward shift deletion is employed to further + * improve the performance and to avoid infinite loops in rare cases. * * The entries are stored inplace, so huge keys or values might fill cache lines * a lot faster. @@ -60,25 +61,20 @@ private: uint32_t num_elements; static const uint32_t EMPTY_HASH = 0; - static const uint32_t DELETED_HASH_BIT = 1 << 31; _FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const { uint32_t hash = Hasher::hash(p_key); if (hash == EMPTY_HASH) { hash = EMPTY_HASH + 1; - } else if (hash & DELETED_HASH_BIT) { - hash &= ~DELETED_HASH_BIT; } return hash; } _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash) const { - p_hash = p_hash & ~DELETED_HASH_BIT; // we don't care if it was deleted or not - uint32_t original_pos = p_hash % capacity; - return (p_pos - original_pos) % capacity; + return (p_pos - original_pos + capacity) % capacity; } _FORCE_INLINE_ void _construct(uint32_t p_pos, uint32_t p_hash, const TKey &p_key, const TValue &p_value) { @@ -132,14 +128,6 @@ private: // not an empty slot, let's check the probing length of the existing one uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos]); if (existing_probe_len < distance) { - - if (hashes[pos] & DELETED_HASH_BIT) { - // we found a place where we can fit in! - _construct(pos, hash, key, value); - - return; - } - SWAP(hash, hashes[pos]); SWAP(key, keys[pos]); SWAP(value, values[pos]); @@ -173,9 +161,6 @@ private: if (old_hashes[i] == EMPTY_HASH) { continue; } - if (old_hashes[i] & DELETED_HASH_BIT) { - continue; - } _insert_with_hash(old_hashes[i], old_keys[i], old_values[i]); } @@ -205,10 +190,6 @@ public: continue; } - if (hashes[i] & DELETED_HASH_BIT) { - continue; - } - hashes[i] = EMPTY_HASH; values[i].~TValue(); keys[i].~TKey(); @@ -219,7 +200,7 @@ public: void insert(const TKey &p_key, const TValue &p_value) { - if ((float)num_elements / (float)capacity > 0.9) { + if (num_elements + 1 > 0.9 * capacity) { _resize_and_rehash(); } @@ -272,9 +253,20 @@ public: return; } - hashes[pos] |= DELETED_HASH_BIT; + uint32_t next_pos = (pos + 1) % capacity; + while (hashes[next_pos] != EMPTY_HASH && + _get_probe_length(next_pos, hashes[next_pos]) != 0) { + SWAP(hashes[next_pos], hashes[pos]); + SWAP(keys[next_pos], keys[pos]); + SWAP(values[next_pos], values[pos]); + pos = next_pos; + next_pos = (pos + 1) % capacity; + } + + hashes[pos] = EMPTY_HASH; values[pos].~TValue(); keys[pos].~TKey(); + num_elements--; } @@ -326,9 +318,6 @@ public: if (hashes[i] == EMPTY_HASH) { continue; } - if (hashes[i] & DELETED_HASH_BIT) { - continue; - } it.valid = true; it.key = &keys[i]; diff --git a/core/reference.cpp b/core/reference.cpp index 1984af9a34..92bbdacd5d 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -36,12 +36,7 @@ bool Reference::init_ref() { if (reference()) { - // this may fail in the scenario of two threads assigning the pointer for the FIRST TIME - // at the same time, which is never likely to happen (would be crazy to do) - // so don't do it. - - if (refcount_init.get() > 0) { - refcount_init.unref(); + if (!is_referenced() && refcount_init.unref()) { unreference(); // first referencing is already 1, so compensate for the ref above } @@ -64,9 +59,11 @@ int Reference::reference_get_count() const { } bool Reference::reference() { - bool success = refcount.ref(); - if (success && refcount.get() <= 2 /* higher is not relevant */) { + uint32_t rc_val = refcount.refval(); + bool success = rc_val != 0; + + if (success && rc_val <= 2 /* higher is not relevant */) { if (get_script_instance()) { get_script_instance()->refcount_incremented(); } @@ -84,9 +81,10 @@ bool Reference::reference() { bool Reference::unreference() { - bool die = refcount.unref(); + uint32_t rc_val = refcount.unrefval(); + bool die = rc_val == 0; - if (refcount.get() <= 1 /* higher is not relevant */) { + if (rc_val <= 1 /* higher is not relevant */) { if (get_script_instance()) { bool script_ret = get_script_instance()->refcount_decremented(); die = die && script_ret; diff --git a/core/reference.h b/core/reference.h index 20ee22ddfc..b8d00a94ad 100644 --- a/core/reference.h +++ b/core/reference.h @@ -47,7 +47,7 @@ protected: static void _bind_methods(); public: - _FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() < 1; } + _FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() != 1; } bool init_ref(); bool reference(); // returns false if refcount is at zero and didn't get increased bool unreference(); diff --git a/core/safe_refcount.h b/core/safe_refcount.h index 54f540b0c7..47161eed57 100644 --- a/core/safe_refcount.h +++ b/core/safe_refcount.h @@ -177,12 +177,12 @@ struct SafeRefCount { public: // destroy() is called when weak_count_ drops to zero. - _ALWAYS_INLINE_ bool ref() { //true on success + _ALWAYS_INLINE_ bool ref() { // true on success return atomic_conditional_increment(&count) != 0; } - _ALWAYS_INLINE_ uint32_t refval() { //true on success + _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success return atomic_conditional_increment(&count); } @@ -192,6 +192,11 @@ public: return atomic_decrement(&count) == 0; } + _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of + + return atomic_decrement(&count); + } + _ALWAYS_INLINE_ uint32_t get() const { // nothrow return count; |