<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
Mark,<br>
<br>
yes, I needed that persistence for the HTTP and VFS classes, but I
also needed to be able to couple a dynamic C++ instance with a JS
object and have a mechanism to prevent garbage collection while the
C++ side is still in use. If the C++ side is no longer needed, the
JS finalizer also needs to imply the C++ instance can be deleted.<br>
<br>
That is all implemented by DuktapeObject. DuktapeObject also
provides JS method invocation on the coupled JS object and a mutex
for concurrency protection.<br>
<br>
We probably need some more framework documentation than the header
comments (applies to all of our framework classes…):<br>
<br>
<tt>/***************************************************************************************************</tt><tt><br>
</tt><tt> * DuktapeObject: coupled C++ / JS object</tt><tt><br>
</tt><tt> * </tt><tt><br>
</tt><tt> * Intended for API methods to attach internal API state
to a JS object and provide</tt><tt><br>
</tt><tt> * a standard callback invocation interface for JS
objects in local scopes.</tt><tt><br>
</tt><tt> * </tt><tt><br>
</tt><tt> * - Override CallMethod() to implement specific method
calls</tt><tt><br>
</tt><tt> * - Override Finalize() for specific destruction in JS
context (garbage collection)</tt><tt><br>
</tt><tt> * - call Register() to prevent normal garbage collection
(but not heap destruction)</tt><tt><br>
</tt><tt> * - call Ref() to protect against deletion (reference
count)</tt><tt><br>
</tt><tt> * - call Lock() to protect concurrent access (recursive
mutex)</tt><tt><br>
</tt><tt> * </tt><tt><br>
</tt><tt> * - GetInstance() retrieves the DuktapeObject associated
with a JS object if any</tt><tt><br>
</tt><tt> * - Push() pushes the JS object onto the Duktape stack</tt><tt><br>
</tt><tt> * </tt><tt><br>
</tt><tt> * Note: the DuktapeObject may persist after the JS object
has been finalized, e.g.</tt><tt><br>
</tt><tt> * if some callbacks are pending after the Duktape heap
has been destroyed.</tt><tt><br>
</tt><tt> * Use IsCoupled() to check if the JS object is still
available.</tt><tt><br>
</tt><tt> * </tt><tt><br>
</tt><tt> * Ref/Unref:</tt><tt><br>
</tt><tt> * Normal life cycle is from construction to
finalization. Pending callbacks extend</tt><tt><br>
</tt><tt> * the life until the last callback has been processed.
A subclass may extend the life</tt><tt><br>
</tt><tt> * by calling Ref(), which increases the reference
count. Unref() deletes the instance</tt><tt><br>
</tt><tt> * if no references are left.</tt><tt><br>
</tt><tt> */</tt><tt><br>
</tt><br>
You normally just need to use Register/Deregister & Ref/Unref,
and to implement the constructor and CallMethod. Coupling of the
instances normally is done on construction, as a JS object is
normally already needed for the parameters and can simply be
attached to.<br>
<br>
Have a look at DuktapeHTTPRequest, DuktapeVFSLoad and
DuktapeVFSSave, these are the current subclasses using this.<br>
<br>
For the command registration I would probably couple the OvmsCommand
instance with a JS command object providing an execution method.<br>
<br>
Tell me if you need more info.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div class="moz-cite-prefix">Am 15.07.20 um 08:12 schrieb Mark
Webb-Johnson:<br>
</div>
<blockquote type="cite"
cite="mid:B291C8AF-8382-4F45-87E3-3DA555E068BE@webb-johnson.net">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<div class=""><br class="">
</div>
<div class="">@Michael this is probably for you.</div>
<div class=""><br class="">
</div>
<div class="">I am trying to implement javascript command
registration. The idea is that a javascript module can call
something like:</div>
<div class=""><br class="">
</div>
<div class="">
<blockquote style="caret-color: rgb(0, 0, 0); color: rgb(0, 0,
0); margin: 0px 0px 0px 40px; border: none; padding: 0px;"
class="">OvmsCommand.Register(basecommand, name, title,
callbackfn, usage, min, max)</blockquote>
<div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class=""><br class="">
</div>
</div>
<div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class="">Then we reflect that into MyCommandApp.RegisterCommand,
and keep a track of which command is for which javascript
callbackfn. When the command is executed, we pass it into
duktape.</div>
<div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class=""><br class="">
</div>
<div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class="">I also have tracking for javascript module loading and
unloading, so I can DeregisterCommand() if duktape is reloaded
(and also protected against commands being registered in
short-lived scripts run from the command line).</div>
<div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class=""><br class="">
</div>
<div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class="">To implement this, I need to store the callbackfn as a
persistent reference to a duktape javascript function.</div>
<div class=""><br class="">
</div>
<div class="">The issue with callback function references in
duktape is summarised here:</div>
<div class=""><br class="">
</div>
<blockquote style="margin: 0 0 0 40px; border: none; padding:
0px;" class="">
<div class=""><a
href="https://wiki.duktape.org/howtonativepersistentreferences"
class="" moz-do-not-send="true">https://wiki.duktape.org/howtonativepersistentreferences</a></div>
<div class=""><br class="">
</div>
<div class=""><i class="">When a Duktape/C function is called,
Duktape places the call arguments on the value stack. While
the arguments are on the value stack, they're guaranteed to
be reachable and the Duktape/C function can safely work with
the arguments.<br class="">
<br class="">
However, when the Duktape/C function returns, the value
stack is unwound and references in the function's value
stack frame are lost. If the last reference to a particular
value was in the function's value stack frame, the value
will be garbage collected when the function return is
processed.</i></div>
</blockquote>
<div class=""><br class="">
</div>
<div class="">The standard approach is to store the reference back
in the duktape duk_push_global_stash so it won’t get
garbage-collected. But, that seems messy.</div>
<div class=""><br class="">
</div>
<div class="">I see that Michael has already implemented something
that seems similar in ovms_script.{h, cpp}, for the async http
callbacks. Presumably to avoid this issue. But, the approach
seems very different, and I am not sure if it is stopping _all_
garbage collection for the duration of the async query, or just
that particular object being garbage collected. The work seems
extensive (quite a few objects involved).</div>
<div class=""><br class="">
</div>
<div class="">So @Michael, any suggestions for this? I don’t want
to reinvent the wheel...</div>
<div class=""><br class="">
</div>
<div class="">Regards, Mark.</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<pre class="moz-quote-pre" wrap="">_______________________________________________
OvmsDev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:OvmsDev@lists.openvehicles.com">OvmsDev@lists.openvehicles.com</a>
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br>
<pre class="moz-signature" cols="72">--
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
</pre>
</body>
</html>