summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/bind/core_bind.cpp5
-rw-r--r--core/io/stream_peer_tcp.cpp11
-rw-r--r--core/oa_hash_map.h47
-rw-r--r--core/reference.cpp18
-rw-r--r--core/reference.h2
-rw-r--r--core/safe_refcount.h9
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;