-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Core] Disconnect one-shot signals before calling callbacks #89451
Conversation
7557126
to
1802e2e
Compare
I'd say if anything it should be opened as a separate PR anyway, it seems a separate thing to the disconnecting change. Also if this gets approved as us (just the disconnecting part) then I think we should be careful with cherry-picking it to 4.2, I'd say that's a change which is likely to introduce some regressions we haven't thought about. I'm not sure if the change is safe. It's core-core so I'd say it needs to be assesed by reduz anyway, so let's wait for such assesment. 🙂 |
Thanks for looking into this! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some notes on making the implementation more efficient
Will update tomorrow, thank you! |
b46309e
to
018d792
Compare
There, updated:
Still disconnecting all signals before emitting, to handle this: signal my_signal
func foo():
print("Foo")
my_signal.emit()
func bar():
print("Bar")
func _ready():
my_signal.connect(foo, CONNECT_ONE_SHOT)
my_signal.connect(bar, CONNECT_ONE_SHOT)
my_signal.emit() Without disconnecting all signals at once before emitting this will fire This cleans up a bunch of inefficiencies in this code, like storing the name of the signal in the disconnect data (not needed, only used in a single signal) and copying the whole |
uint32_t slot_count = 0; | ||
|
||
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) { | ||
memnew_placement(&slot_callables[slot_count], Callable(slot_kv.value.conn.callable)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memnew
is required here to handle the uninitialized memory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotta fix memory management here
Edit: Resolved, had to destroy them properly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's a better way to handle the lifetime here do tell, I don't have an asan setup at the moment so can't test efficiently for leaks
if (!c.callable.is_valid()) { | ||
for (uint32_t i = 0; i < slot_count; ++i) { | ||
const Callable &callable = slot_callables[i]; | ||
const uint32_t &flags = slot_flags[i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added these for convenience, I ended up changing all the code below anyway as c
went away but still neater
Gonna add a GDScript test for this case and will push after CI has finished |
018d792
to
0bfae38
Compare
While at it probably good idea to also add some test specifically for the fixed |
Will test out writing one! |
0bfae38
to
6ae6f28
Compare
And done, that test will fail with errors on the unchanged branch, and behaves nicely now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fantastic, great work!
Thank you! |
This prevents infinite recursion with one-shot connections emitting themselves
6ae6f28
to
db455e5
Compare
[Core] Disconnect one-shot signals before calling callbacks
06abc86
Thanks! |
Thank you! |
Edit: Removed the recursion fix and can add it back in separately if desired, I still think it's an improvement but it makes this easier to merge and cherry-pick, keeping things as simple as possible for this case
This solves the issue, though I'd say some of the handling of
await
needs to be improved, see for example, so some further fixing of that side is likely needed: