Hello Aleksander, Thanks for the reply. You probably just saw my email I sent right before I got your email.
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. 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 :). So the only thing wrong was me not understanding the guarantees of the API. 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. Thanks for the excellent support, Jessy Diamond Exum. On Mon, Oct 5, 2020 at 12:51 AM Aleksander Morgado <aleksan...@aleksander.es> wrote: > Hey Jessy, > > > > > 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. > > > > 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)! > > > > 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. > > > > 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. > > > > From the point of view of the user of libmm-glib APIs, you MUST assume > that if you provide a GCallback to *any* async method, the GCallback > will *always* be called for you. And always means always, when the > async operation finishes successfully, when it fails, or when it's > cancelled. This is a guarantee that the library gives you, and > therefore if it doesn't happen, it's a bug in the library. Therefore, > if you pass a GCallback with a user_data that you have allocated in > heap, you're responsible for calling whatever free method that > user_data requires once the GCallback has been called. If you're > getting a memory leak, it could mean you're not doing this. Also, if > you pass a GCallback, you should call the corresponding _finish() > method of the async operation. This is not strictly needed in all > cases, but I'd suggest to always call finish() unconditionally. > > If you look at the above, you'll see why you don't really need a > GDestroyNotify in the async methods. Actually, none of the usual GIO > async methods will ask you to provide a GDestroyNotify, because the > guarantee that the callback is called always lets you run whatever > free() you need yourself in the callback itself. > > The GDestroyNotify in g_cancellable_connect() is required so that you > can safely assume the user_data is freed whenever the handler is > disconnected (because you're really adding a signal handler) or the > cancellation has happened (as this is a single-time event). This logic > doesn't really apply to normal async methods like the ones we have in > libmm-glib. > > So now, you say the GCallback is not being called if the operation is > cancelled. Could you send a short tester to show this issue? Does the > issue happen always with the same async method or with all that you've > tried? > > -- > Aleksander > https://aleksander.es >
_______________________________________________ ModemManager-devel mailing list ModemManager-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel