Multi-use callback in Vala?

I’ve been debugging an issue with my app and I think I’ve come to a conclusion, but I wanted to check something.

Are Vala callbacks intended to be single use?

Context: I’m using librest in a Vala app. I want to upload a file to an OAuth endpoint, so I’m using the Rest.ProxyCall.upload function. That takes a callback that gets invoked every time libsoup notifies it of upload progress. The old C code that I’m replacing handles it fine and you get nice granular progress updates. But the Vala code crashes.

From debugging and examining the valac compiled C code, it looks like rest_proxy_call_upload gets called with ____lambda67__rest_proxy_call_upload_callback passed as a callback and block64_data_ref(…) passed as the user data.

____lambda67__rest_proxy_call_upload_callback does two things. 1) call ___lambda67_; and 2) block64_data_unref() the user data.

Based on that, it looks like the callback assumes it only gets called once and can unref its data once it is done. Which means subsequent calls will be using unref’d data (give or take a few calls of the callback where it unrefs someone else’s ref as if it were its own, before getting to zero and being freed).

Is my understanding right? And is there a way to make a callback run multiple times (as upload needs it to do) or do I need to keep detaching and attaching them? (Which feels like it risks missing events)

Ah. I’ve just realised that as this is a callback and not a signal then I can’t keep disconnecting and reconnecting the same function.

I might have fixed this by using a helper object. Rather than relying on the closure (which gets freed) I manually put the closure in to the object and then pass a function of the object as the callback. That way I’ve still got this available when the callback gets called, so I’ve got all of the objects.

I thought I’d tried something like this before, but the latest implementation appears to be working from initial testing.

I don’t know if there’s a better way to do it.

This looks like a bug: if you look at the bindings, the callback does have a scope = "async" CCode anotation, which means it can be only called once.

Since the annotation is present in the librest source code it is a bug that needs to be reported to the librest issue tracker (You’ll have to live with the workaround until a fixed version is released).

I’ve reported it now. It could be worse. At least there is a workaround! Thanks.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.