Merge pull request #31932 from huisedenanhai/master

make core/Reference thread safe
This commit is contained in:
Rémi Verschelde 2019-09-26 11:26:05 +02:00 committed by GitHub
commit 202440acce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 13 deletions

View file

@ -36,12 +36,7 @@ bool Reference::init_ref() {
if (reference()) { if (reference()) {
// this may fail in the scenario of two threads assigning the pointer for the FIRST TIME if (!is_referenced() && refcount_init.unref()) {
// 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();
unreference(); // first referencing is already 1, so compensate for the ref above 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 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()) { if (get_script_instance()) {
get_script_instance()->refcount_incremented(); get_script_instance()->refcount_incremented();
} }
@ -84,9 +81,10 @@ bool Reference::reference() {
bool Reference::unreference() { 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()) { if (get_script_instance()) {
bool script_ret = get_script_instance()->refcount_decremented(); bool script_ret = get_script_instance()->refcount_decremented();
die = die && script_ret; die = die && script_ret;

View file

@ -47,7 +47,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: 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 init_ref();
bool reference(); // returns false if refcount is at zero and didn't get increased bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference(); bool unreference();

View file

@ -177,12 +177,12 @@ struct SafeRefCount {
public: public:
// destroy() is called when weak_count_ drops to zero. // 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; 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); return atomic_conditional_increment(&count);
} }
@ -192,6 +192,11 @@ public:
return atomic_decrement(&count) == 0; 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 _ALWAYS_INLINE_ uint32_t get() const { // nothrow
return count; return count;