[quickjs-devel] Re: Asynchronous finalizers?

  • From: Saúl Ibarra Corretgé <s@xxxxxxxxxx>
  • To: quickjs-devel@xxxxxxxxxxxxx
  • Date: Tue, 20 Aug 2019 23:23:07 +0200

On 20/08/2019 22:50, Ondřej Jirman wrote:

Hi,

On Tue, Aug 20, 2019 at 09:57:22PM +0200, Saúl Ibarra Corretgé wrote:
Hey there,

While working on integrating libuv I ran into the following situation:
libuv handles (a TCP socket for example) are not closed synchronously,
that is, the libuv provided close function (uv_close) takes a callback
and it's not safe to free the memory until the callback is called (it's
safe to free the handle in the callback).

I'm embedding libuv handles in a structure which I then set as the
opaque for some JS objects. If the handle wasn't closed when the
finalizer runs, I close it and free the opaque data in the close callback.

This has been working great, until I tried to be tidy and cleanup all
handles on shutdown. Handles which are destroyed when the JSContext is
going away (because JS_FreeContext was called) get their finalizrs run,
but I can no longer touch the context in the handle close callback
because it was freed already (I've allocated these structures with
js_malloc).

The only way forward I see is to allocate the opaque structures with
plan malloc so there is no dependency in the JSContext.

If QuickJS runtime doesn't own the opaque data completely, and it may outlive
the runtime, you probably shouldn't be using js_malloc that is tied to the
runtime. So that sounds like a way to go.

Just mark the data as released from quickjs in the finalizer, and then
free it in the close callback.


Yeah, that's what I'm leaning towards.

Another option would be for QuickJS to provide a way to destroy a
context without freeing its memory, so there is time for me to cleanup
in between. Would this make sense in the grand scheme of things?

There would not be any time. If you destroy the runtime (and as part of that
run all the finalizers), all of its memory must be gone. There's no after.

QuickJS would have to be changed, so that each JSValue object would own
a reference to the runtime, for this to work at all. And it would also go
against the memory leak check that can be done while freeing the runtime.


I was thinking of something like JS_CleanContext, which would do pretty
much what JS_FreeContext does, but without freeing the context itself.
Then I could run the libuv loop one last time, get the close callbacks
called, then actually free the context.

Now, to be honest, after writing it makes even less sense :-) It would
be pretty bug prone.

Thanks for confirming my suspicions!


Cheers,

-- 
Saúl

Other related posts: