koffi 1.3.9 → 1.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ChangeLog.md +24 -0
- package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
- package/doc/benchmarks.md +2 -2
- package/doc/conf.py +1 -1
- package/doc/contribute.md +1 -1
- package/doc/dist/doctrees/benchmarks.doctree +0 -0
- package/doc/dist/doctrees/changes.doctree +0 -0
- package/doc/dist/doctrees/contribute.doctree +0 -0
- package/doc/dist/doctrees/environment.pickle +0 -0
- package/doc/dist/doctrees/functions.doctree +0 -0
- package/doc/dist/doctrees/index.doctree +0 -0
- package/doc/dist/doctrees/memory.doctree +0 -0
- package/doc/dist/doctrees/types.doctree +0 -0
- package/doc/dist/html/.buildinfo +1 -1
- package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
- package/doc/dist/html/_sources/contribute.md.txt +1 -2
- package/doc/dist/html/_sources/functions.md.txt +137 -15
- package/doc/dist/html/_sources/index.rst.txt +2 -0
- package/doc/dist/html/_sources/memory.md.txt +1 -1
- package/doc/dist/html/_sources/types.md.txt +27 -11
- package/doc/dist/html/_static/basic.css +14 -12
- package/doc/dist/html/_static/pygments.css +54 -54
- package/doc/dist/html/benchmarks.html +3 -3
- package/doc/dist/html/changes.html +1 -1
- package/doc/dist/html/contribute.html +2 -3
- package/doc/dist/html/functions.html +206 -86
- package/doc/dist/html/genindex.html +1 -1
- package/doc/dist/html/index.html +6 -7
- package/doc/dist/html/memory.html +4 -4
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +2 -2
- package/doc/dist/html/search.html +1 -1
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +55 -55
- package/doc/dist/html/types.html +172 -159
- package/doc/functions.md +9 -7
- package/doc/index.rst +2 -0
- package/doc/memory.md +1 -1
- package/doc/poetry.lock +692 -0
- package/doc/pyproject.toml +18 -0
- package/doc/{_static → static}/bench_linux.png +0 -0
- package/doc/{_static → static}/bench_windows.png +0 -0
- package/doc/{_static → static}/custom.css +0 -0
- package/doc/{_static → static}/perf_linux_20220623.png +0 -0
- package/doc/{_static → static}/perf_linux_20220623_2.png +0 -0
- package/doc/{_static → static}/perf_linux_20220627.png +0 -0
- package/doc/{_static → static}/perf_linux_20220628.png +0 -0
- package/doc/{_static → static}/perf_windows_20220623.png +0 -0
- package/doc/{_static → static}/perf_windows_20220623_2.png +0 -0
- package/doc/{_static → static}/perf_windows_20220627.png +0 -0
- package/doc/{_static → static}/perf_windows_20220628.png +0 -0
- package/doc/types.md +1 -1
- package/package.json +9 -7
- package/qemu/qemu.js +3 -3
- package/src/abi_arm32.cc +3 -3
- package/src/abi_riscv64.cc +1 -1
- package/src/abi_x64_sysv.cc +1 -1
- package/src/abi_x64_win.cc +1 -1
- package/src/abi_x64_win_fwd.asm +2 -2
- package/src/abi_x86.cc +5 -5
- package/src/parser.cc +2 -1
- package/test/misc.c +1 -1
- package/test/sync.js +2 -2
- package/build/qemu/1.3.9/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.9/koffi_win32_x64.tar.gz +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
|
|
6
6
|
<link rel="index" title="Index" href="genindex" /><link rel="search" title="Search" href="search" /><link rel="next" title="Memory usage" href="memory" /><link rel="prev" title="Data types" href="types" />
|
|
7
7
|
|
|
8
|
-
<meta name="generator" content="sphinx-5.0.
|
|
8
|
+
<meta name="generator" content="sphinx-5.0.1, furo 2022.06.04.1"/>
|
|
9
9
|
<title>Function calls - Koffi</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=40978830699223671f4072448e654b5958f38b89" />
|
|
@@ -208,8 +208,8 @@
|
|
|
208
208
|
<section id="function-definitions">
|
|
209
209
|
<h2>Function definitions<a class="headerlink" href="#function-definitions" title="Permalink to this heading">#</a></h2>
|
|
210
210
|
<p>To declare functions, start by loading the shared library with <code class="docutils literal notranslate"><span class="pre">koffi.load(filename)</span></code>.</p>
|
|
211
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span
|
|
212
|
-
<span class="linenos">2</span><span class="kd">const</span
|
|
211
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
212
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'/path/to/shared/library'</span><span class="p">);</span> <span class="c1">// File extension depends on platforms: .so, .dll, .dylib, etc.</span>
|
|
213
213
|
</pre></div>
|
|
214
214
|
</div>
|
|
215
215
|
<p>You can use the returned object to load C functions from the library. To do so, you can use two syntaxes:</p>
|
|
@@ -220,24 +220,26 @@
|
|
|
220
220
|
<section id="classic-syntax">
|
|
221
221
|
<h3>Classic syntax<a class="headerlink" href="#classic-syntax" title="Permalink to this heading">#</a></h3>
|
|
222
222
|
<p>To declare a function, you need to specify its non-mangled name, its return type, and its parameters. Use an ellipsis as the last parameter for variadic functions.</p>
|
|
223
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span
|
|
224
|
-
<span class="linenos">2</span><span class="kd">const</span
|
|
223
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">printf</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'printf'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'str'</span><span class="p">,</span> <span class="s1">'...'</span><span class="p">]);</span>
|
|
224
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">atoi</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'atoi'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'str'</span><span class="p">]);</span>
|
|
225
225
|
</pre></div>
|
|
226
226
|
</div>
|
|
227
|
-
<p>Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section <a class="reference internal" href="#
|
|
227
|
+
<p>Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section on <a class="reference internal" href="#calling-conventions"><span class="std std-doc">calling conventions</span></a> for more information on this subject.</p>
|
|
228
228
|
</section>
|
|
229
229
|
<section id="c-like-prototypes">
|
|
230
230
|
<h3>C-like prototypes<a class="headerlink" href="#c-like-prototypes" title="Permalink to this heading">#</a></h3>
|
|
231
231
|
<p>If you prefer, you can declare functions using simple C-like prototype strings, as shown below:</p>
|
|
232
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span
|
|
233
|
-
<span class="linenos">2</span><span class="kd">const</span
|
|
232
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">printf</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'int printf(const char *fmt, ...)'</span><span class="p">);</span>
|
|
233
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">atoi</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'int atoi(str)'</span><span class="p">);</span> <span class="c1">// The parameter name is not used by Koffi, and optional</span>
|
|
234
234
|
</pre></div>
|
|
235
235
|
</div>
|
|
236
236
|
<p>You can use <code class="docutils literal notranslate"><span class="pre">()</span></code> or <code class="docutils literal notranslate"><span class="pre">(void)</span></code> for functions that take no argument.</p>
|
|
237
237
|
</section>
|
|
238
238
|
</section>
|
|
239
|
-
<section id="
|
|
240
|
-
<h2>
|
|
239
|
+
<section id="id1">
|
|
240
|
+
<h2>Function calls<a class="headerlink" href="#id1" title="Permalink to this heading">#</a></h2>
|
|
241
|
+
<section id="calling-conventions">
|
|
242
|
+
<h3>Calling conventions<a class="headerlink" href="#calling-conventions" title="Permalink to this heading">#</a></h3>
|
|
241
243
|
<p>By default, calling a C function happens synchronously.</p>
|
|
242
244
|
<p>Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi supports several x86 conventions:</p>
|
|
243
245
|
<div class="table-wrapper colwidths-auto docutils container">
|
|
@@ -275,31 +277,31 @@
|
|
|
275
277
|
</div>
|
|
276
278
|
<p>You can safely use these on non-x86 platforms, they are simply ignored.</p>
|
|
277
279
|
<p>Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:</p>
|
|
278
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span
|
|
279
|
-
<span class="linenos">2</span><span class="kd">const</span
|
|
280
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
281
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'user32.dll'</span><span class="p">);</span>
|
|
280
282
|
<span class="linenos">3</span>
|
|
281
|
-
<span class="linenos">4</span><span class="c1">// The following two declarations are equivalent, and use
|
|
282
|
-
<span class="linenos">5</span><span class="kd">const</span
|
|
283
|
-
<span class="linenos">6</span><span class="kd">const</span
|
|
283
|
+
<span class="linenos">4</span><span class="c1">// The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)</span>
|
|
284
|
+
<span class="linenos">5</span><span class="kd">const</span> <span class="nx">MessageBoxA_1</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">stdcall</span><span class="p">(</span><span class="s1">'MessageBoxA'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'void *'</span><span class="p">,</span> <span class="s1">'str'</span><span class="p">,</span> <span class="s1">'str'</span><span class="p">,</span> <span class="s1">'uint'</span><span class="p">]);</span>
|
|
285
|
+
<span class="linenos">6</span><span class="kd">const</span> <span class="nx">MessageBoxA_2</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)'</span><span class="p">);</span>
|
|
284
286
|
</pre></div>
|
|
285
287
|
</div>
|
|
286
288
|
</section>
|
|
287
289
|
<section id="asynchronous-calls">
|
|
288
|
-
<
|
|
290
|
+
<h3>Asynchronous calls<a class="headerlink" href="#asynchronous-calls" title="Permalink to this heading">#</a></h3>
|
|
289
291
|
<p>You can issue asynchronous calls by calling the function through its async member. In this case, you need to provide a callback function as the last argument, with <code class="docutils literal notranslate"><span class="pre">(err,</span> <span class="pre">res)</span></code> parameters.</p>
|
|
290
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span
|
|
291
|
-
<span class="linenos"> 2</span><span class="kd">const</span
|
|
292
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
293
|
+
<span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'libc.so.6'</span><span class="p">);</span>
|
|
292
294
|
<span class="linenos"> 3</span>
|
|
293
|
-
<span class="linenos"> 4</span><span class="kd">const</span
|
|
295
|
+
<span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">atoi</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'int atoi(const char *str)'</span><span class="p">);</span>
|
|
294
296
|
<span class="linenos"> 5</span>
|
|
295
|
-
<span class="linenos"> 6</span><span class="nx">atoi</span><span class="p">.</span><span class="k">async</span><span class="p">(</span><span class="s1">'1257'</span><span class="p">,</span
|
|
296
|
-
<span class="linenos"> 7</span
|
|
297
|
-
<span class="linenos"> 8</span><span class="p">})</span
|
|
298
|
-
<span class="linenos"> 9</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'Hello World!'</span><span class="p">);</span
|
|
297
|
+
<span class="linenos"> 6</span><span class="nx">atoi</span><span class="p">.</span><span class="k">async</span><span class="p">(</span><span class="s1">'1257'</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=></span> <span class="p">{</span>
|
|
298
|
+
<span class="linenos"> 7</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'Result:'</span><span class="p">,</span> <span class="nx">res</span><span class="p">);</span>
|
|
299
|
+
<span class="linenos"> 8</span><span class="p">})</span>
|
|
300
|
+
<span class="linenos"> 9</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'Hello World!'</span><span class="p">);</span>
|
|
299
301
|
<span class="linenos">10</span>
|
|
300
|
-
<span class="linenos">11</span><span class="c1">// This program will print:</span
|
|
301
|
-
<span class="linenos">12</span><span class="c1">// Hello World!</span
|
|
302
|
-
<span class="linenos">13</span><span class="c1">// Result: 1257</span
|
|
302
|
+
<span class="linenos">11</span><span class="c1">// This program will print:</span>
|
|
303
|
+
<span class="linenos">12</span><span class="c1">// Hello World!</span>
|
|
304
|
+
<span class="linenos">13</span><span class="c1">// Result: 1257</span>
|
|
303
305
|
</pre></div>
|
|
304
306
|
</div>
|
|
305
307
|
<p>These calls are executed by worker threads. It is <strong>your responsibility to deal with data sharing issues</strong> in the native code that may be caused by multi-threading.</p>
|
|
@@ -307,19 +309,22 @@
|
|
|
307
309
|
<p>Variadic functions cannot be called asynchronously.</p>
|
|
308
310
|
</section>
|
|
309
311
|
<section id="variadic-functions">
|
|
310
|
-
<
|
|
312
|
+
<h3>Variadic functions<a class="headerlink" href="#variadic-functions" title="Permalink to this heading">#</a></h3>
|
|
311
313
|
<p>Variadic functions are declared with an ellipsis as the last argument.</p>
|
|
312
314
|
<p>In order to call a variadic function, you must provide two Javascript arguments for each additional C parameter, the first one is the expected type and the second one is the value.</p>
|
|
313
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span
|
|
315
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">printf</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'printf'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'str'</span><span class="p">,</span> <span class="s1">'...'</span><span class="p">]);</span>
|
|
314
316
|
<span class="linenos">2</span>
|
|
315
|
-
<span class="linenos">3</span><span class="c1">// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)</span
|
|
316
|
-
<span class="linenos">4</span><span class="nx">printf</span><span class="p">(</span><span class="s1">'Integer %d, double %g, str %s'</span><span class="p">,</span
|
|
317
|
+
<span class="linenos">3</span><span class="c1">// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)</span>
|
|
318
|
+
<span class="linenos">4</span><span class="nx">printf</span><span class="p">(</span><span class="s1">'Integer %d, double %g, str %s'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="mf">6</span><span class="p">,</span> <span class="s1">'double'</span><span class="p">,</span> <span class="mf">8.5</span><span class="p">,</span> <span class="s1">'str'</span><span class="p">,</span> <span class="s1">'THE END'</span><span class="p">);</span>
|
|
317
319
|
</pre></div>
|
|
318
320
|
</div>
|
|
319
321
|
<p>On x86 platforms, only the Cdecl convention can be used for variadic functions.</p>
|
|
320
322
|
</section>
|
|
323
|
+
</section>
|
|
324
|
+
<section id="c-to-js-conversion-gotchas">
|
|
325
|
+
<h2>C to JS conversion gotchas<a class="headerlink" href="#c-to-js-conversion-gotchas" title="Permalink to this heading">#</a></h2>
|
|
321
326
|
<section id="output-parameters">
|
|
322
|
-
<
|
|
327
|
+
<h3>Output parameters<a class="headerlink" href="#output-parameters" title="Permalink to this heading">#</a></h3>
|
|
323
328
|
<p>By default, Koffi will only forward arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.</p>
|
|
324
329
|
<p>For simplicity, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) two types of parameters:</p>
|
|
325
330
|
<ul class="simple">
|
|
@@ -337,67 +342,123 @@
|
|
|
337
342
|
<li><p><code class="docutils literal notranslate"><span class="pre">_Inout_</span></code> for dual input/output parameters</p></li>
|
|
338
343
|
</ul>
|
|
339
344
|
<section id="struct-example">
|
|
340
|
-
<
|
|
345
|
+
<h4>Struct example<a class="headerlink" href="#struct-example" title="Permalink to this heading">#</a></h4>
|
|
341
346
|
<p>This example calls the POSIX function <code class="docutils literal notranslate"><span class="pre">gettimeofday()</span></code>, and uses the prototype-like syntax.</p>
|
|
342
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span
|
|
343
|
-
<span class="linenos"> 2</span><span class="kd">const</span
|
|
347
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
348
|
+
<span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'libc.so.6'</span><span class="p">);</span>
|
|
344
349
|
<span class="linenos"> 3</span>
|
|
345
|
-
<span class="linenos"> 4</span><span class="kd">const</span
|
|
346
|
-
<span class="linenos"> 5</span
|
|
347
|
-
<span class="linenos"> 6</span
|
|
348
|
-
<span class="linenos"> 7</span><span class="p">});</span
|
|
349
|
-
<span class="linenos"> 8</span><span class="kd">const</span
|
|
350
|
-
<span class="linenos"> 9</span
|
|
351
|
-
<span class="linenos">10</span
|
|
352
|
-
<span class="linenos">11</span><span class="p">});</span
|
|
350
|
+
<span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">timeval</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">struct</span><span class="p">(</span><span class="s1">'timeval'</span><span class="p">,</span> <span class="p">{</span>
|
|
351
|
+
<span class="linenos"> 5</span> <span class="nx">tv_sec</span><span class="o">:</span> <span class="s1">'unsigned int'</span><span class="p">,</span>
|
|
352
|
+
<span class="linenos"> 6</span> <span class="nx">tv_usec</span><span class="o">:</span> <span class="s1">'unsigned int'</span>
|
|
353
|
+
<span class="linenos"> 7</span><span class="p">});</span>
|
|
354
|
+
<span class="linenos"> 8</span><span class="kd">const</span> <span class="nx">timezone</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">struct</span><span class="p">(</span><span class="s1">'timezone'</span><span class="p">,</span> <span class="p">{</span>
|
|
355
|
+
<span class="linenos"> 9</span> <span class="nx">tz_minuteswest</span><span class="o">:</span> <span class="s1">'int'</span><span class="p">,</span>
|
|
356
|
+
<span class="linenos">10</span> <span class="nx">tz_dsttime</span><span class="o">:</span> <span class="s1">'int'</span>
|
|
357
|
+
<span class="linenos">11</span><span class="p">});</span>
|
|
353
358
|
<span class="linenos">12</span>
|
|
354
|
-
<span class="linenos">13</span><span class="c1">// The _Out_ qualifiers instruct Koffi to marshal out the values</span
|
|
355
|
-
<span class="linenos">14</span><span class="kd">const</span
|
|
359
|
+
<span class="linenos">13</span><span class="c1">// The _Out_ qualifiers instruct Koffi to marshal out the values</span>
|
|
360
|
+
<span class="linenos">14</span><span class="kd">const</span> <span class="nx">gettimeofday</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'int gettimeofday(_Out_ timeval *tv, _Out_ timezone *tz)'</span><span class="p">);</span>
|
|
356
361
|
<span class="linenos">15</span>
|
|
357
|
-
<span class="linenos">16</span><span class="kd">let</span
|
|
358
|
-
<span class="linenos">17</span><span class="nx">gettimeofday</span><span class="p">(</span><span class="nx">tv</span><span class="p">,</span
|
|
362
|
+
<span class="linenos">16</span><span class="kd">let</span> <span class="nx">tv</span> <span class="o">=</span> <span class="p">{};</span>
|
|
363
|
+
<span class="linenos">17</span><span class="nx">gettimeofday</span><span class="p">(</span><span class="nx">tv</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
|
|
359
364
|
<span class="linenos">18</span>
|
|
360
|
-
<span class="linenos">19</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">tv</span><span class="p">);</span
|
|
365
|
+
<span class="linenos">19</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">tv</span><span class="p">);</span>
|
|
361
366
|
</pre></div>
|
|
362
367
|
</div>
|
|
363
368
|
</section>
|
|
364
369
|
<section id="opaque-handle-example">
|
|
365
|
-
<
|
|
370
|
+
<h4>Opaque handle example<a class="headerlink" href="#opaque-handle-example" title="Permalink to this heading">#</a></h4>
|
|
366
371
|
<p>This example opens an in-memory SQLite database, and uses the node-ffi-style function declaration syntax.</p>
|
|
367
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span
|
|
368
|
-
<span class="linenos"> 2</span><span class="kd">const</span
|
|
372
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
373
|
+
<span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'sqlite.so'</span><span class="p">);</span>
|
|
369
374
|
<span class="linenos"> 3</span>
|
|
370
|
-
<span class="linenos"> 4</span><span class="kd">const</span
|
|
375
|
+
<span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">sqlite3_db</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">handle</span><span class="p">(</span><span class="s1">'sqlite3_db'</span><span class="p">);</span>
|
|
371
376
|
<span class="linenos"> 5</span>
|
|
372
|
-
<span class="linenos"> 6</span><span class="c1">// Use koffi.out() on a pointer to copy out (from C to JS) after the call</span
|
|
373
|
-
<span class="linenos"> 7</span><span class="kd">const</span
|
|
374
|
-
<span class="linenos"> 8</span><span class="kd">const</span
|
|
377
|
+
<span class="linenos"> 6</span><span class="c1">// Use koffi.out() on a double pointer to copy out (from C to JS) after the call</span>
|
|
378
|
+
<span class="linenos"> 7</span><span class="kd">const</span> <span class="nx">sqlite3_open_v2</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'sqlite3_open_v2'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'str'</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">out</span><span class="p">(</span><span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="nx">sqlite3_db</span><span class="p">,</span> <span class="mf">2</span><span class="p">)),</span> <span class="s1">'int'</span><span class="p">,</span> <span class="s1">'str'</span><span class="p">]);</span>
|
|
379
|
+
<span class="linenos"> 8</span><span class="kd">const</span> <span class="nx">sqlite3_close_v2</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'sqlite3_close_v2'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="nx">sqlite3_db</span><span class="p">)]);</span>
|
|
375
380
|
<span class="linenos"> 9</span>
|
|
376
|
-
<span class="linenos">10</span><span class="kd">const</span
|
|
377
|
-
<span class="linenos">11</span><span class="kd">const</span
|
|
381
|
+
<span class="linenos">10</span><span class="kd">const</span> <span class="nx">SQLITE_OPEN_READWRITE</span> <span class="o">=</span> <span class="mh">0x2</span><span class="p">;</span>
|
|
382
|
+
<span class="linenos">11</span><span class="kd">const</span> <span class="nx">SQLITE_OPEN_CREATE</span> <span class="o">=</span> <span class="mh">0x4</span><span class="p">;</span>
|
|
378
383
|
<span class="linenos">12</span>
|
|
379
|
-
<span class="linenos">13</span><span class="kd">let</span
|
|
380
|
-
<span class="linenos">14</span><span class="k">if</span
|
|
381
|
-
<span class="linenos">15</span
|
|
382
|
-
<span class="linenos">16</span><span class="nx">sqlite3_close_v2</span><span class="p">(</span><span class="nx">db</span><span class="p">);</span
|
|
384
|
+
<span class="linenos">13</span><span class="kd">let</span> <span class="nx">db</span> <span class="o">=</span> <span class="p">{};</span>
|
|
385
|
+
<span class="linenos">14</span><span class="k">if</span> <span class="p">(</span><span class="nx">sqlite3_open_v2</span><span class="p">(</span><span class="s1">':memory:'</span><span class="p">,</span> <span class="nx">db</span><span class="p">,</span> <span class="nx">SQLITE_OPEN_READWRITE</span> <span class="o">|</span> <span class="nx">SQLITE_OPEN_CREATE</span><span class="p">,</span> <span class="kc">null</span><span class="p">)</span> <span class="o">!=</span> <span class="mf">0</span><span class="p">)</span>
|
|
386
|
+
<span class="linenos">15</span> <span class="k">throw</span> <span class="ow">new</span> <span class="ne">Error</span><span class="p">(</span><span class="s1">'Failed to open database'</span><span class="p">);</span>
|
|
387
|
+
<span class="linenos">16</span><span class="nx">sqlite3_close_v2</span><span class="p">(</span><span class="nx">db</span><span class="p">);</span>
|
|
388
|
+
</pre></div>
|
|
389
|
+
</div>
|
|
390
|
+
</section>
|
|
391
|
+
</section>
|
|
392
|
+
<section id="heap-allocated-values">
|
|
393
|
+
<h3>Heap-allocated values<a class="headerlink" href="#heap-allocated-values" title="Permalink to this heading">#</a></h3>
|
|
394
|
+
<p>Some C functions return heap-allocated values directly or through output parameters. While Koffi automatically converts values from C to JS (to a string or an object), it does not know when something needs to be freed, or how.</p>
|
|
395
|
+
<p>For opaque handles, such as FILE, this does not matter because you will explicitly call <code class="docutils literal notranslate"><span class="pre">fclose()</span></code> on them. But some values (such as strings) get implicitly converted by Koffi, and you lose access to the original pointer. This creates a leak if the string is heap-allocated.</p>
|
|
396
|
+
<p>To avoid this, you can instruct Koffi to call a function on the original pointer once the conversion is done, by creating a disposable type with <code class="docutils literal notranslate"><span class="pre">koffi.dispose(name,</span> <span class="pre">type,</span> <span class="pre">func)</span></code>. This creates a type derived from another type, the only difference being that <em>func</em> gets called with the original pointer once the value has been converted and is not needed anymore.</p>
|
|
397
|
+
<p>The <em>name</em> can be omitted to create an anonymous disposable type. If <em>func</em> is omitted or is null, Koffi will use <code class="docutils literal notranslate"><span class="pre">koffi.free(ptr)</span></code> (which calls the standard C library <em>free</em> function under the hood).</p>
|
|
398
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">AnonHeapStr</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">disposable</span><span class="p">(</span><span class="s1">'str'</span><span class="p">);</span> <span class="c1">// Anonymous type (cannot be used in function prototypes)</span>
|
|
399
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">NamedHeapStr</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">disposable</span><span class="p">(</span><span class="s1">'HeapStr'</span><span class="p">,</span> <span class="s1">'str'</span><span class="p">);</span> <span class="c1">// Same thing, but named so usable in function prototypes</span>
|
|
400
|
+
<span class="linenos">3</span><span class="kd">const</span> <span class="nx">ExplicitFree</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">disposable</span><span class="p">(</span><span class="s1">'HeapStr16'</span><span class="p">,</span> <span class="s1">'str16'</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">free</span><span class="p">);</span> <span class="c1">// You can specify any other JS function</span>
|
|
401
|
+
</pre></div>
|
|
402
|
+
</div>
|
|
403
|
+
<p>The following example illustrates the use of a disposable type derived from <em>str</em>.</p>
|
|
404
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
405
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'libc.so.6'</span><span class="p">);</span>
|
|
406
|
+
<span class="linenos">3</span>
|
|
407
|
+
<span class="linenos">4</span><span class="c1">// You can also use: const strdup = lib.func('const char *! asprintf(const char *str)')</span>
|
|
408
|
+
<span class="linenos">5</span><span class="kd">const</span> <span class="nx">HeapStr</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">disposable</span><span class="p">(</span><span class="s1">'str'</span><span class="p">);</span>
|
|
409
|
+
<span class="linenos">6</span><span class="kd">const</span> <span class="nx">strdup</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">cdecl</span><span class="p">(</span><span class="s1">'strdup'</span><span class="p">,</span> <span class="nx">HeapStr</span><span class="p">,</span> <span class="p">[</span><span class="s1">'str'</span><span class="p">]);</span>
|
|
410
|
+
<span class="linenos">7</span>
|
|
411
|
+
<span class="linenos">8</span><span class="kd">let</span> <span class="nx">copy</span> <span class="o">=</span> <span class="nx">strdup</span><span class="p">(</span><span class="s1">'Hello!'</span><span class="p">);</span>
|
|
412
|
+
<span class="linenos">9</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">copy</span><span class="p">);</span> <span class="c1">// Prints Hello!</span>
|
|
413
|
+
</pre></div>
|
|
414
|
+
</div>
|
|
415
|
+
<p>When you declare functions with the <a class="reference internal" href="#c-like-prototypes"><span class="std std-doc">prototype-like syntax</span></a>, you can either use named disposables types or use the ‘!’ shortcut qualifier with compatibles types, as shown in the example below. This qualifier creates an anonymous disposable type that calls <code class="docutils literal notranslate"><span class="pre">koffi.free(ptr)</span></code>.</p>
|
|
416
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
417
|
+
<span class="linenos">2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'libc.so.6'</span><span class="p">);</span>
|
|
418
|
+
<span class="linenos">3</span>
|
|
419
|
+
<span class="linenos">4</span><span class="c1">// You can also use: const strdup = lib.func('const char *! strdup(const char *str)')</span>
|
|
420
|
+
<span class="linenos">5</span><span class="kd">const</span> <span class="nx">strdup</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'str! strdup(const char *str)'</span><span class="p">);</span>
|
|
421
|
+
<span class="linenos">6</span>
|
|
422
|
+
<span class="linenos">7</span><span class="kd">let</span> <span class="nx">copy</span> <span class="o">=</span> <span class="nx">strdup</span><span class="p">(</span><span class="s1">'World!'</span><span class="p">);</span>
|
|
423
|
+
<span class="linenos">8</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">copy</span><span class="p">);</span> <span class="c1">// Prints World!</span>
|
|
383
424
|
</pre></div>
|
|
384
425
|
</div>
|
|
426
|
+
<p>Disposable types can only be created from pointer or string types.</p>
|
|
427
|
+
<div class="admonition warning">
|
|
428
|
+
<p class="admonition-title">Warning</p>
|
|
429
|
+
<p>Be careful on Windows: if your shared library uses a different CRT (such as msvcrt), the memory could have been allocated by a different malloc/free implementation or heap, resulting in undefined behavior if you use <code class="docutils literal notranslate"><span class="pre">koffi.free()</span></code>.</p>
|
|
430
|
+
</div>
|
|
385
431
|
</section>
|
|
386
432
|
</section>
|
|
387
433
|
<section id="javascript-callbacks">
|
|
388
434
|
<h2>Javascript callbacks<a class="headerlink" href="#javascript-callbacks" title="Permalink to this heading">#</a></h2>
|
|
389
435
|
<p>In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.</p>
|
|
390
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span
|
|
436
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
391
437
|
<span class="linenos">2</span>
|
|
392
|
-
<span class="linenos">3</span><span class="c1">// With the classic syntax, this callback expects an integer and returns nothing</span
|
|
393
|
-
<span class="linenos">4</span><span class="kd">const</span
|
|
438
|
+
<span class="linenos">3</span><span class="c1">// With the classic syntax, this callback expects an integer and returns nothing</span>
|
|
439
|
+
<span class="linenos">4</span><span class="kd">const</span> <span class="nx">ExampleCallback</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">callback</span><span class="p">(</span><span class="s1">'ExampleCallback'</span><span class="p">,</span> <span class="s1">'void'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'int'</span><span class="p">]);</span>
|
|
394
440
|
<span class="linenos">5</span>
|
|
395
|
-
<span class="linenos">6</span><span class="c1">// With the prototype parser, this callback expects a double and float, and returns the sum as a double</span
|
|
396
|
-
<span class="linenos">7</span><span class="kd">const</span
|
|
441
|
+
<span class="linenos">6</span><span class="c1">// With the prototype parser, this callback expects a double and float, and returns the sum as a double</span>
|
|
442
|
+
<span class="linenos">7</span><span class="kd">const</span> <span class="nx">AddDoubleFloat</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">callback</span><span class="p">(</span><span class="s1">'double AddDoubleFloat(double d, float f)'</span><span class="p">);</span>
|
|
397
443
|
</pre></div>
|
|
398
444
|
</div>
|
|
399
|
-
<p>Once your callback type is declared, you can use it in struct definitions, or as function
|
|
400
|
-
<
|
|
445
|
+
<p>Once your callback type is declared, you can use a pointer to it in struct definitions, or as function parameters and/or return types.</p>
|
|
446
|
+
<div class="admonition note">
|
|
447
|
+
<p class="admonition-title">Note</p>
|
|
448
|
+
<p>Callbacks <strong>have changed in version 2.0</strong>.</p>
|
|
449
|
+
<p>In Koffi 1.x, callbacks were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.</p>
|
|
450
|
+
<p>Now, you must use them through a pointer: <code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">CallIt(CallbackType</span> <span class="pre">func)</span></code> in Koffi 1.x becomes <code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">CallIt(CallbackType</span> <span class="pre">*func)</span></code> in version 2.0 and newer.</p>
|
|
451
|
+
</div>
|
|
452
|
+
<p>Koffi only uses predefined static trampolines, and does not need to generate code at runtime, which makes it compatible with platforms with hardened W^X migitations (such as PaX mprotect). However, this imposes some restrictions on the maximum number of callbacks, and their duration.</p>
|
|
453
|
+
<p>Thus, Koffi distinguishes two callback modes:</p>
|
|
454
|
+
<ul class="simple">
|
|
455
|
+
<li><p><a class="reference internal" href="#transient-callbacks"><span class="std std-doc">Transient callbacks</span></a> can only be called while the C function they are passed to is running, and are invalidated when it returns. If the C function calls the callback later, the behavior is undefined, though Koffi tries to detect such cases. If it does, an exception will be thrown, but this is no guaranteed. However, they are simple to use, and don’t require any special handling.</p></li>
|
|
456
|
+
<li><p><a class="reference internal" href="#registered-callbacks"><span class="std std-doc">Registered callbacks</span></a> can be called at any time, but they must be manually registered and unregistered. A limited number of registered callbacks can exist at the same time.</p></li>
|
|
457
|
+
</ul>
|
|
458
|
+
<p>You need to specify the correct <a class="reference internal" href="#calling-conventions"><span class="std std-doc">calling convention</span></a> on x86 platforms, or the behavior is undefined (Node will probably crash). Only <em>cdecl</em> and <em>stdcall</em> callbacks are supported.</p>
|
|
459
|
+
<section id="transient-callbacks">
|
|
460
|
+
<h3>Transient callbacks<a class="headerlink" href="#transient-callbacks" title="Permalink to this heading">#</a></h3>
|
|
461
|
+
<p>Use transient callbacks when the native C function only needs to call them while it runs (e.g. qsort, progress callback, <code class="docutils literal notranslate"><span class="pre">sqlite3_exec</span></code>). Here is a small example with the C part and the JS part.</p>
|
|
401
462
|
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="linenos">1</span><span class="cp">#include</span><span class="w"> </span><span class="cpf"><string.h></span><span class="cp"></span>
|
|
402
463
|
<span class="linenos">2</span>
|
|
403
464
|
<span class="linenos">3</span><span class="kt">int</span><span class="w"> </span><span class="nf">TransferToJS</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">age</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">cb</span><span class="p">)(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">str</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">age</span><span class="p">))</span><span class="w"></span>
|
|
@@ -408,26 +469,73 @@
|
|
|
408
469
|
<span class="linenos">8</span><span class="p">}</span><span class="w"></span>
|
|
409
470
|
</pre></div>
|
|
410
471
|
</div>
|
|
411
|
-
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span
|
|
412
|
-
<span class="linenos"> 2</span>
|
|
413
|
-
<span class="linenos"> 3</span
|
|
414
|
-
<span class="linenos"> 4</span>
|
|
415
|
-
<span class="linenos"> 5</span
|
|
472
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
473
|
+
<span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'./callbacks.so'</span><span class="p">);</span> <span class="c1">// Fake path</span>
|
|
474
|
+
<span class="linenos"> 3</span>
|
|
475
|
+
<span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">TransferCallback</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">callback</span><span class="p">(</span><span class="s1">'int TransferCallback(const char *str, int age)'</span><span class="p">);</span>
|
|
476
|
+
<span class="linenos"> 5</span>
|
|
477
|
+
<span class="linenos"> 6</span><span class="kd">const</span> <span class="nx">TransferToJS</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'TransferToJS'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'str'</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="nx">TransferCallback</span><span class="p">)]);</span>
|
|
478
|
+
<span class="linenos"> 7</span>
|
|
479
|
+
<span class="linenos"> 8</span><span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="nx">TransferToJS</span><span class="p">(</span><span class="s1">'Niels'</span><span class="p">,</span> <span class="mf">27</span><span class="p">,</span> <span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">age</span><span class="p">)</span> <span class="p">=></span> <span class="p">{</span>
|
|
480
|
+
<span class="linenos"> 9</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">str</span><span class="p">);</span>
|
|
481
|
+
<span class="linenos">10</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'Your age is:'</span><span class="p">,</span> <span class="nx">age</span><span class="p">);</span>
|
|
482
|
+
<span class="linenos">11</span> <span class="k">return</span> <span class="mf">42</span><span class="p">;</span>
|
|
483
|
+
<span class="linenos">12</span><span class="p">});</span>
|
|
484
|
+
<span class="linenos">13</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">ret</span><span class="p">);</span>
|
|
485
|
+
<span class="linenos">14</span>
|
|
486
|
+
<span class="linenos">15</span><span class="c1">// This example prints:</span>
|
|
487
|
+
<span class="linenos">16</span><span class="c1">// Hello Niels!</span>
|
|
488
|
+
<span class="linenos">17</span><span class="c1">// Your age is: 27</span>
|
|
489
|
+
<span class="linenos">18</span><span class="c1">// 42</span>
|
|
490
|
+
</pre></div>
|
|
491
|
+
</div>
|
|
492
|
+
</section>
|
|
493
|
+
<section id="registered-callbacks">
|
|
494
|
+
<h3>Registered callbacks<a class="headerlink" href="#registered-callbacks" title="Permalink to this heading">#</a></h3>
|
|
495
|
+
<p>Use registered callbacks when the function needs to be called at a later time (e.g. log handler, event handler, <code class="docutils literal notranslate"><span class="pre">fopencookie/funopen</span></code>). Call <code class="docutils literal notranslate"><span class="pre">koffi.register(func,</span> <span class="pre">type)</span></code> to register a callback function, with two arguments: the JS function, and the callback type.</p>
|
|
496
|
+
<p>When you are done, call <code class="docutils literal notranslate"><span class="pre">koffi.unregister()</span></code> (with the value returned by <code class="docutils literal notranslate"><span class="pre">koffi.register()</span></code>) to release the slot. A maximum of 16 registered callbacks can exist at the same time. Failure to do so will leak the slot, and subsequent registrations may fail (with an exception) once all slots are used.</p>
|
|
497
|
+
<p>The example below shows how to register and unregister delayed callbacks.</p>
|
|
498
|
+
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">g_cb1</span><span class="p">)(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</span><span class="p">);</span><span class="w"></span>
|
|
499
|
+
<span class="linenos"> 2</span><span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">g_cb2</span><span class="p">)(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">str</span><span class="p">);</span><span class="w"></span>
|
|
500
|
+
<span class="linenos"> 3</span>
|
|
501
|
+
<span class="linenos"> 4</span><span class="kt">void</span><span class="w"> </span><span class="nf">RegisterFunctions</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">cb1</span><span class="p">)(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</span><span class="p">),</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">cb2</span><span class="p">)(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">str</span><span class="p">))</span><span class="w"></span>
|
|
502
|
+
<span class="linenos"> 5</span><span class="p">{</span><span class="w"></span>
|
|
503
|
+
<span class="linenos"> 6</span><span class="w"> </span><span class="n">g_cb1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cb1</span><span class="p">;</span><span class="w"></span>
|
|
504
|
+
<span class="linenos"> 7</span><span class="w"> </span><span class="n">g_cb2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cb2</span><span class="p">;</span><span class="w"></span>
|
|
505
|
+
<span class="linenos"> 8</span><span class="p">}</span><span class="w"></span>
|
|
506
|
+
<span class="linenos"> 9</span>
|
|
507
|
+
<span class="linenos">10</span><span class="kt">void</span><span class="w"> </span><span class="nf">SayIt</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</span><span class="p">)</span><span class="w"></span>
|
|
508
|
+
<span class="linenos">11</span><span class="p">{</span><span class="w"></span>
|
|
509
|
+
<span class="linenos">12</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_cb1</span><span class="p">(</span><span class="n">name</span><span class="p">);</span><span class="w"></span>
|
|
510
|
+
<span class="linenos">13</span><span class="w"> </span><span class="n">g_cb2</span><span class="p">(</span><span class="n">str</span><span class="p">);</span><span class="w"></span>
|
|
511
|
+
<span class="linenos">14</span><span class="p">}</span><span class="w"></span>
|
|
512
|
+
</pre></div>
|
|
513
|
+
</div>
|
|
514
|
+
<div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="kd">const</span> <span class="nx">koffi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'koffi'</span><span class="p">);</span>
|
|
515
|
+
<span class="linenos"> 2</span><span class="kd">const</span> <span class="nx">lib</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'./callbacks.so'</span><span class="p">);</span> <span class="c1">// Fake path</span>
|
|
516
|
+
<span class="linenos"> 3</span>
|
|
517
|
+
<span class="linenos"> 4</span><span class="kd">const</span> <span class="nx">GetCallback</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">callback</span><span class="p">(</span><span class="s1">'const char *GetCallback(const char *name)'</span><span class="p">);</span>
|
|
518
|
+
<span class="linenos"> 5</span><span class="kd">const</span> <span class="nx">PrintCallback</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">callback</span><span class="p">(</span><span class="s1">'void PrintCallback(const char *str)'</span><span class="p">);</span>
|
|
416
519
|
<span class="linenos"> 6</span>
|
|
417
|
-
<span class="linenos"> 7</span><span class="kd">
|
|
418
|
-
<span class="linenos"> 8</span><span class="
|
|
419
|
-
<span class="linenos"> 9</span
|
|
420
|
-
<span class="linenos">10</span><span class="
|
|
421
|
-
<span class="linenos">11</span><span class="p">
|
|
422
|
-
<span class="linenos">12</span
|
|
423
|
-
<span class="linenos">13</span>
|
|
424
|
-
<span class="linenos">14</span><span class="
|
|
425
|
-
<span class="linenos">15</span
|
|
426
|
-
<span class="linenos">16</span><span class="
|
|
427
|
-
<span class="linenos">17</span><span class="
|
|
520
|
+
<span class="linenos"> 7</span><span class="kd">const</span> <span class="nx">RegisterFunctions</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'void RegisterFunctions(GetCallback *cb1, PrintCallback *cb2)'</span><span class="p">);</span>
|
|
521
|
+
<span class="linenos"> 8</span><span class="kd">const</span> <span class="nx">SayIt</span> <span class="o">=</span> <span class="nx">lib</span><span class="p">.</span><span class="nx">func</span><span class="p">(</span><span class="s1">'void SayIt(const char *name)'</span><span class="p">);</span>
|
|
522
|
+
<span class="linenos"> 9</span>
|
|
523
|
+
<span class="linenos">10</span><span class="kd">let</span> <span class="nx">cb1</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">register</span><span class="p">(</span><span class="nx">name</span> <span class="p">=></span> <span class="s1">'Hello '</span> <span class="o">+</span> <span class="nx">name</span> <span class="o">+</span> <span class="s1">'!'</span><span class="p">,</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">pointer</span><span class="p">(</span><span class="nx">GetCallback</span><span class="p">));</span>
|
|
524
|
+
<span class="linenos">11</span><span class="kd">let</span> <span class="nx">cb2</span> <span class="o">=</span> <span class="nx">koffi</span><span class="p">.</span><span class="nx">register</span><span class="p">(</span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">,</span> <span class="s1">'PrintCallback *'</span><span class="p">);</span>
|
|
525
|
+
<span class="linenos">12</span>
|
|
526
|
+
<span class="linenos">13</span><span class="nx">RegisterFunctions</span><span class="p">(</span><span class="nx">cb1</span><span class="p">,</span> <span class="nx">cb2</span><span class="p">);</span>
|
|
527
|
+
<span class="linenos">14</span><span class="nx">SayIt</span><span class="p">(</span><span class="s1">'Kyoto'</span><span class="p">);</span> <span class="c1">// Prints Hello Kyoto!</span>
|
|
528
|
+
<span class="linenos">15</span>
|
|
529
|
+
<span class="linenos">16</span><span class="nx">koffi</span><span class="p">.</span><span class="nx">unregister</span><span class="p">(</span><span class="nx">cb1</span><span class="p">);</span>
|
|
530
|
+
<span class="linenos">17</span><span class="nx">koffi</span><span class="p">.</span><span class="nx">unregister</span><span class="p">(</span><span class="nx">cb2</span><span class="p">);</span>
|
|
428
531
|
</pre></div>
|
|
429
532
|
</div>
|
|
430
|
-
|
|
533
|
+
</section>
|
|
534
|
+
<section id="handling-of-exceptions">
|
|
535
|
+
<h3>Handling of exceptions<a class="headerlink" href="#handling-of-exceptions" title="Permalink to this heading">#</a></h3>
|
|
536
|
+
<p>If an exception happens inside the JS callback, the C API will receive 0 or NULL (depending on the return value type).</p>
|
|
537
|
+
<p>Handle the exception yourself (with try/catch) if you need to handle exceptions differently.</p>
|
|
538
|
+
</section>
|
|
431
539
|
</section>
|
|
432
540
|
<section id="thread-safety">
|
|
433
541
|
<h2>Thread safety<a class="headerlink" href="#thread-safety" title="Permalink to this heading">#</a></h2>
|
|
@@ -499,15 +607,27 @@
|
|
|
499
607
|
<li><a class="reference internal" href="#c-like-prototypes">C-like prototypes</a></li>
|
|
500
608
|
</ul>
|
|
501
609
|
</li>
|
|
502
|
-
<li><a class="reference internal" href="#
|
|
610
|
+
<li><a class="reference internal" href="#id1">Function calls</a><ul>
|
|
611
|
+
<li><a class="reference internal" href="#calling-conventions">Calling conventions</a></li>
|
|
503
612
|
<li><a class="reference internal" href="#asynchronous-calls">Asynchronous calls</a></li>
|
|
504
613
|
<li><a class="reference internal" href="#variadic-functions">Variadic functions</a></li>
|
|
614
|
+
</ul>
|
|
615
|
+
</li>
|
|
616
|
+
<li><a class="reference internal" href="#c-to-js-conversion-gotchas">C to JS conversion gotchas</a><ul>
|
|
505
617
|
<li><a class="reference internal" href="#output-parameters">Output parameters</a><ul>
|
|
506
618
|
<li><a class="reference internal" href="#struct-example">Struct example</a></li>
|
|
507
619
|
<li><a class="reference internal" href="#opaque-handle-example">Opaque handle example</a></li>
|
|
508
620
|
</ul>
|
|
509
621
|
</li>
|
|
510
|
-
<li><a class="reference internal" href="#
|
|
622
|
+
<li><a class="reference internal" href="#heap-allocated-values">Heap-allocated values</a></li>
|
|
623
|
+
</ul>
|
|
624
|
+
</li>
|
|
625
|
+
<li><a class="reference internal" href="#javascript-callbacks">Javascript callbacks</a><ul>
|
|
626
|
+
<li><a class="reference internal" href="#transient-callbacks">Transient callbacks</a></li>
|
|
627
|
+
<li><a class="reference internal" href="#registered-callbacks">Registered callbacks</a></li>
|
|
628
|
+
<li><a class="reference internal" href="#handling-of-exceptions">Handling of exceptions</a></li>
|
|
629
|
+
</ul>
|
|
630
|
+
</li>
|
|
511
631
|
<li><a class="reference internal" href="#thread-safety">Thread safety</a></li>
|
|
512
632
|
</ul>
|
|
513
633
|
</li>
|