<div dir="ltr">Thanks again for the reply.<div><br></div><div>I am aware that with a series of async calls that 'cancellation' as an idea is questionable. What does it even mean?, etc...</div><div><br></div><div>Part of my confusion was running the following (to test cancellation) and the bearer was still created.</div><div><br></div><div>        mm_modem_create_bearer<br>            (this->peek_modem(),<br>             props,<br>             cancellable,<br>             cb,</div><div>             this);<br>        g_cancellable_cancel (cancellable);<br></div><div><br></div><div>This code was executed in a scheduled task run by the glib event loop, and all of the code ran in the same iteration of the event loop. I expected that the bearer creation logic would start in the next event loop iteration, but now I see that the mm_modem_create_bearer call immediately instructs MM to start creating the bearer, so by the time the next line of my code is executed, it is too late to stop the creation. This is fine, and I can deal with an extra bearer that I have to clean up later.</div><div><br></div><div>The real issue that is leading me through all of these tests is improving my understanding of lifecycles when working with async MM functions. I want to make sure that there is no possible scenario where I destroy one of my C++ objects that tracks a MMModem, in the destructor I cancel and unref the cancellable, the object is deleted, and then a callback comes through with the user_data set to my freed object and I get a use after free. But it is likely that this will just require me doing some more reading and experimentation. If you know any good practices to prevent these kinds of use after free issues, I would greatly appreciate any links or suggestions. (And thanks for not minding me changing the topic).</div><div><br></div><div>Jessy Diamond Exum</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Oct 5, 2020 at 1:20 AM Aleksander Morgado <<a href="mailto:aleksander@aleksander.es">aleksander@aleksander.es</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hey!<br>
<br>
><br>
> Now I just need to understand why even when I call mm_modem_create_bearer and immediately cancel the GCancellable, My callback is called with the error "Operation was cancelled", but the bearer is still created. This is an unrelated issue, so I can create a new email thread on this question if I can't figure it out.<br>
><br>
<br>
That's easy to explain I think.<br>
<br>
Internally, all the async operations are implemented using GTasks.<br>
When the async operation starts, the GTask is created with the input<br>
GCancellable associated, and (by default) that means that if the<br>
cancellable is ever cancelled, the GTask is ALWAYS going to return a<br>
G_IO_ERROR_CANCELLED, even if the actual async operation may have<br>
finished successfully. So it may happen that the internal async method<br>
finished with a g_task_return_boolean(TRUE) or similar, but the actual<br>
g_task_propagate_boolean() called in the _finish() ends up returning a<br>
cancelled error instead of TRUE, because the GCancellable was<br>
cancelled meanwhile. See the docs for g_task_set_check_cancellable()<br>
which is the method that could be used to disable the default<br>
behavior.<br>
<br>
Now, another thing is the rationale of when this logic should be<br>
applied, or if it even makes sense to do that in certain operations<br>
like mm_modem_create_bearer(). You could argue that if this method<br>
fails with whatever reason, it must mean that the bearer object wasn't<br>
created, and I could probably agree with you. There would be two ways<br>
to solve this: make sure that internally the async method handles the<br>
cancellation gracefully and so we make sure the bearer is destroyed if<br>
it was created but the operation was cancelled; or otherwise make the<br>
operation not cancellable at all (ignoring the input cancellable).<br>
<br>
This is some thinking that we should put in all APIs I'm afraid; I'm<br>
sure there are some that already can be considered safe, but lots of<br>
others that change state or create objects probably aren't.<br>
<br>
-- <br>
Aleksander<br>
<a href="https://aleksander.es" rel="noreferrer" target="_blank">https://aleksander.es</a><br>
</blockquote></div>