<div dir="ltr"><div dir="ltr">Hello Aleksander,<div><br></div><div>Thanks for the reply. You probably just saw my email I sent right before I got your email.</div><div><br></div><div>I had never actually seen a memory leak. I didn't understand that the callback would be ALWAYS called, so I assumed that there would be a leak (mistakes made when working past midnight). Comparing the libmm-glib API to other GObject based APIs made me feel like MM was missing a feature instead of me just misunderstanding the behavior. </div><div><br></div><div>I attempted the 'solution' I described in the first email (listening for a cancellation event). When I triggered a cancel, I deleted my object in the cancel signal, and then the callback I registered with the MM function call was triggered (as you just described). That caused a core dump :). </div><div><br></div><div>So the only thing wrong was me not understanding the guarantees of the API.</div><div><br></div><div>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.</div></div><div><br></div><div>Thanks for the excellent support,</div><div>Jessy Diamond Exum.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Oct 5, 2020 at 12:51 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 Jessy,<br>
<br>
><br>
> I am using MM in a C++ project, but my question won't be related to C++ besides a very high level description of what I did.<br>
><br>
> To get MM functions to invoke bound C++ functions as callbacks, I had to generate a small structure for each MM function call that automatically destroys itself once the callback fires. This works perfectly (mostly)!<br>
><br>
> Except! If the MM function is cancelled, my wrapping structure is never invoked, never freed, and I get a memory leak. My current solution is to use g_cancellable_connect to trigger the struct's destruction when I cancel the MM operation. That is when I saw that g_cancellable_connect accepts an optional GDestroyNotify* callback, and I started thinking about how much more flexible the libmm-glib API would be if functions that accepted a GCancellable, callback, and userdata ALSO supported a GDestroyNotify style callback for freeing userdata.<br>
><br>
> I know I can't expect a massive API change to a mature project because it would be convenient to one guy who is working in a different language, but I wanted to bring the idea up in case anyone else likes the idea, or knows why it was not implemented.<br>
><br>
<br>
>From the point of view of the user of libmm-glib APIs, you MUST assume<br>
that if you provide a GCallback to *any* async method, the GCallback<br>
will *always* be called for you. And always means always, when the<br>
async operation finishes successfully, when it fails, or when it's<br>
cancelled. This is a guarantee that the library gives you, and<br>
therefore if it doesn't happen, it's a bug in the library. Therefore,<br>
if you pass a GCallback with a user_data that you have allocated in<br>
heap, you're responsible for calling whatever free method that<br>
user_data requires once the GCallback has been called. If you're<br>
getting a memory leak, it could mean you're not doing this. Also, if<br>
you pass a GCallback, you should call the corresponding _finish()<br>
method of the async operation. This is not strictly needed in all<br>
cases, but I'd suggest to always call finish() unconditionally.<br>
<br>
If you look at the above, you'll see why you don't really need a<br>
GDestroyNotify in the async methods. Actually, none of the usual GIO<br>
async methods will ask you to provide a GDestroyNotify, because the<br>
guarantee that the callback is called always lets you run whatever<br>
free() you need yourself in the callback itself.<br>
<br>
The GDestroyNotify in g_cancellable_connect() is required so that you<br>
can safely assume the user_data is freed whenever the handler is<br>
disconnected (because you're really adding a signal handler) or the<br>
cancellation has happened (as this is a single-time event). This logic<br>
doesn't really apply to normal async methods like the ones we have in<br>
libmm-glib.<br>
<br>
So now, you say the GCallback is not being called if the operation is<br>
cancelled. Could you send a short tester to show this issue? Does the<br>
issue happen always with the same async method or with all that you've<br>
tried?<br>
<br>
-- <br>
Aleksander<br>
<a href="https://aleksander.es" rel="noreferrer" target="_blank">https://aleksander.es</a><br>
</blockquote></div></div>