Make sure we know when deleting an emitting object
We used a lock signals in the signal_map while emitting, because it was not allowed to disconnect them while being emitted. We used that lock to check if we where deleting an object during signal emission. Now that we allow to disconnect signals while they are being emitted, if an object first disconnects, then gets deleted we can't know that a signal was being emitted during the destructor. This commit adds a new `_emitting` boolean member to Object to be set while emitting and checked in the destructor, while removing the old signal lock which is now unused.
This commit is contained in:
parent
5127afa812
commit
41f59ecfca
2 changed files with 10 additions and 9 deletions
|
@ -1213,9 +1213,9 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
|
|||
MessageQueue::get_singleton()->push_call(target->get_instance_id(), c.method, args, argc, true);
|
||||
} else {
|
||||
Variant::CallError ce;
|
||||
s->lock++;
|
||||
_emitting = true;
|
||||
target->call(c.method, args, argc, ce);
|
||||
s->lock--;
|
||||
_emitting = false;
|
||||
|
||||
if (ce.error != Variant::CallError::CALL_OK) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
@ -1920,6 +1920,7 @@ Object::Object() {
|
|||
_instance_id = ObjectDB::add_instance(this);
|
||||
_can_translate = true;
|
||||
_is_queued_for_deletion = false;
|
||||
_emitting = false;
|
||||
instance_binding_count = 0;
|
||||
memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
|
||||
script_instance = NULL;
|
||||
|
@ -1942,15 +1943,15 @@ Object::~Object() {
|
|||
|
||||
const StringName *S = NULL;
|
||||
|
||||
if (_emitting) {
|
||||
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
|
||||
ERR_PRINTS("Object " + to_string() + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes.");
|
||||
}
|
||||
|
||||
while ((S = signal_map.next(NULL))) {
|
||||
|
||||
Signal *s = &signal_map[*S];
|
||||
|
||||
if (s->lock > 0) {
|
||||
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
|
||||
ERR_PRINTS("Object was freed or unreferenced while signal '" + String(*S) + "' is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes.");
|
||||
}
|
||||
|
||||
//brute force disconnect for performance
|
||||
int slot_count = s->slot_map.size();
|
||||
const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array();
|
||||
|
|
|
@ -465,8 +465,7 @@ private:
|
|||
|
||||
MethodInfo user;
|
||||
VMap<Target, Slot> slot_map;
|
||||
int lock;
|
||||
Signal() { lock = 0; }
|
||||
Signal() {}
|
||||
};
|
||||
|
||||
HashMap<StringName, Signal> signal_map;
|
||||
|
@ -481,6 +480,7 @@ private:
|
|||
bool _predelete();
|
||||
void _postinitialize();
|
||||
bool _can_translate;
|
||||
bool _emitting;
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool _edited;
|
||||
uint32_t _edited_version;
|
||||
|
|
Loading…
Reference in a new issue