koffi 2.2.2-beta.2 → 2.2.2-beta.3
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/doc/callbacks.md +8 -0
- package/package.json +1 -1
- package/src/koffi/build/2.2.2-beta.3/koffi_darwin_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_darwin_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_freebsd_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_freebsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_freebsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_linux_arm32hf.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_linux_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_linux_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_linux_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_openbsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_openbsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_win32_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_win32_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.3/koffi_win32_x64.tar.gz +0 -0
- package/src/koffi/src/abi_arm32.cc +5 -5
- package/src/koffi/src/abi_arm64.cc +5 -5
- package/src/koffi/src/abi_riscv64.cc +5 -5
- package/src/koffi/src/abi_x64_sysv.cc +5 -5
- package/src/koffi/src/abi_x64_win.cc +5 -5
- package/src/koffi/src/abi_x86.cc +5 -5
- package/src/koffi/src/call.cc +35 -18
- package/src/koffi/src/call.hh +7 -11
- package/src/koffi/src/ffi.cc +82 -35
- package/src/koffi/src/ffi.hh +19 -13
- package/src/koffi/test/callbacks.js +11 -0
- package/src/koffi/test/misc.c +57 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_darwin_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_darwin_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_freebsd_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_freebsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_freebsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_linux_arm32hf.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_linux_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_linux_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_linux_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_openbsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_openbsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_win32_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_win32_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.2/koffi_win32_x64.tar.gz +0 -0
package/doc/callbacks.md
CHANGED
|
@@ -168,6 +168,14 @@ qsort(koffi.as(array, 'char **'), array.length, koffi.sizeof('void *'), (ptr1, p
|
|
|
168
168
|
console.log(array); // Prints ['123', 'bar', 'foo', 'foobar']
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
+
## Asynchronous callbacks
|
|
172
|
+
|
|
173
|
+
*New in Koffi 2.2.2*
|
|
174
|
+
|
|
175
|
+
In Koffi, [asynchronous native calls](functions.md#asynchronous-calls) happen on a secondary thread. However, JS execution is inherently single-threaded, callbacks must run on the main thread.
|
|
176
|
+
|
|
177
|
+
Koffi deals with this by running the JS callback function in the Node.js event loop. This means the callback cannot run while the engine is busy running synchronous code.
|
|
178
|
+
|
|
171
179
|
## Handling of exceptions
|
|
172
180
|
|
|
173
181
|
If an exception happens inside the JS callback, the C API will receive 0 or NULL (depending on the return value type).
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -252,7 +252,7 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
|
|
|
252
252
|
return true;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
255
|
+
bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
256
256
|
{
|
|
257
257
|
uint32_t *args_ptr = nullptr;
|
|
258
258
|
uint32_t *gpr_ptr = nullptr;
|
|
@@ -491,7 +491,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
491
491
|
return true;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
void CallData::Execute()
|
|
494
|
+
void CallData::Execute(const FunctionInfo *func)
|
|
495
495
|
{
|
|
496
496
|
#define PERFORM_CALL(Suffix) \
|
|
497
497
|
([&]() { \
|
|
@@ -540,7 +540,7 @@ void CallData::Execute()
|
|
|
540
540
|
#undef PERFORM_CALL
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
-
Napi::Value CallData::Complete()
|
|
543
|
+
Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
544
544
|
{
|
|
545
545
|
RG_DEFER {
|
|
546
546
|
PopOutArguments();
|
|
@@ -597,12 +597,12 @@ Napi::Value CallData::Complete()
|
|
|
597
597
|
RG_UNREACHABLE();
|
|
598
598
|
}
|
|
599
599
|
|
|
600
|
-
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
600
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
|
|
601
601
|
{
|
|
602
602
|
if (RG_UNLIKELY(env.IsExceptionPending()))
|
|
603
603
|
return;
|
|
604
604
|
|
|
605
|
-
const TrampolineInfo &trampoline =
|
|
605
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
606
606
|
|
|
607
607
|
const FunctionInfo *proto = trampoline.proto;
|
|
608
608
|
Napi::Function func = trampoline.func.Value();
|
|
@@ -267,7 +267,7 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
|
|
|
267
267
|
return true;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
270
|
+
bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
271
271
|
{
|
|
272
272
|
uint64_t *args_ptr = nullptr;
|
|
273
273
|
uint64_t *gpr_ptr = nullptr;
|
|
@@ -559,7 +559,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
559
559
|
return true;
|
|
560
560
|
}
|
|
561
561
|
|
|
562
|
-
void CallData::Execute()
|
|
562
|
+
void CallData::Execute(const FunctionInfo *func)
|
|
563
563
|
{
|
|
564
564
|
#define PERFORM_CALL(Suffix) \
|
|
565
565
|
([&]() { \
|
|
@@ -611,7 +611,7 @@ void CallData::Execute()
|
|
|
611
611
|
#undef PERFORM_CALL
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
-
Napi::Value CallData::Complete()
|
|
614
|
+
Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
615
615
|
{
|
|
616
616
|
RG_DEFER {
|
|
617
617
|
PopOutArguments();
|
|
@@ -673,12 +673,12 @@ Napi::Value CallData::Complete()
|
|
|
673
673
|
RG_UNREACHABLE();
|
|
674
674
|
}
|
|
675
675
|
|
|
676
|
-
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
676
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
|
|
677
677
|
{
|
|
678
678
|
if (RG_UNLIKELY(env.IsExceptionPending()))
|
|
679
679
|
return;
|
|
680
680
|
|
|
681
|
-
const TrampolineInfo &trampoline =
|
|
681
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
682
682
|
|
|
683
683
|
const FunctionInfo *proto = trampoline.proto;
|
|
684
684
|
Napi::Function func = trampoline.func.Value();
|
|
@@ -196,7 +196,7 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
|
|
|
196
196
|
return true;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
199
|
+
bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
200
200
|
{
|
|
201
201
|
uint64_t *args_ptr = nullptr;
|
|
202
202
|
uint64_t *gpr_ptr = nullptr;
|
|
@@ -406,7 +406,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
406
406
|
return true;
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
-
void CallData::Execute()
|
|
409
|
+
void CallData::Execute(const FunctionInfo *func)
|
|
410
410
|
{
|
|
411
411
|
#define PERFORM_CALL(Suffix) \
|
|
412
412
|
([&]() { \
|
|
@@ -462,7 +462,7 @@ void CallData::Execute()
|
|
|
462
462
|
#undef PERFORM_CALL
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
-
Napi::Value CallData::Complete()
|
|
465
|
+
Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
466
466
|
{
|
|
467
467
|
RG_DEFER {
|
|
468
468
|
PopOutArguments();
|
|
@@ -524,12 +524,12 @@ Napi::Value CallData::Complete()
|
|
|
524
524
|
RG_UNREACHABLE();
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
-
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
527
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
|
|
528
528
|
{
|
|
529
529
|
if (RG_UNLIKELY(env.IsExceptionPending()))
|
|
530
530
|
return;
|
|
531
531
|
|
|
532
|
-
const TrampolineInfo &trampoline =
|
|
532
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
533
533
|
|
|
534
534
|
const FunctionInfo *proto = trampoline.proto;
|
|
535
535
|
Napi::Function func = trampoline.func.Value();
|
|
@@ -284,7 +284,7 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
|
|
|
284
284
|
return true;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
287
|
+
bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
288
288
|
{
|
|
289
289
|
uint64_t *args_ptr = nullptr;
|
|
290
290
|
uint64_t *gpr_ptr = nullptr;
|
|
@@ -470,7 +470,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
470
470
|
return true;
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
void CallData::Execute()
|
|
473
|
+
void CallData::Execute(const FunctionInfo *func)
|
|
474
474
|
{
|
|
475
475
|
#define PERFORM_CALL(Suffix) \
|
|
476
476
|
([&]() { \
|
|
@@ -526,7 +526,7 @@ void CallData::Execute()
|
|
|
526
526
|
#undef PERFORM_CALL
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
-
Napi::Value CallData::Complete()
|
|
529
|
+
Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
530
530
|
{
|
|
531
531
|
RG_DEFER {
|
|
532
532
|
PopOutArguments();
|
|
@@ -583,12 +583,12 @@ Napi::Value CallData::Complete()
|
|
|
583
583
|
RG_UNREACHABLE();
|
|
584
584
|
}
|
|
585
585
|
|
|
586
|
-
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
586
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
|
|
587
587
|
{
|
|
588
588
|
if (RG_UNLIKELY(env.IsExceptionPending()))
|
|
589
589
|
return;
|
|
590
590
|
|
|
591
|
-
const TrampolineInfo &trampoline =
|
|
591
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
592
592
|
|
|
593
593
|
const FunctionInfo *proto = trampoline.proto;
|
|
594
594
|
Napi::Function func = trampoline.func.Value();
|
|
@@ -121,7 +121,7 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
|
|
|
121
121
|
return true;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
124
|
+
bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
125
125
|
{
|
|
126
126
|
uint64_t *args_ptr = nullptr;
|
|
127
127
|
|
|
@@ -281,7 +281,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
281
281
|
return true;
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
-
void CallData::Execute()
|
|
284
|
+
void CallData::Execute(const FunctionInfo *func)
|
|
285
285
|
{
|
|
286
286
|
#define PERFORM_CALL(Suffix) \
|
|
287
287
|
([&]() { \
|
|
@@ -322,7 +322,7 @@ void CallData::Execute()
|
|
|
322
322
|
#undef PERFORM_CALL
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
Napi::Value CallData::Complete()
|
|
325
|
+
Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
326
326
|
{
|
|
327
327
|
RG_DEFER {
|
|
328
328
|
PopOutArguments();
|
|
@@ -379,12 +379,12 @@ Napi::Value CallData::Complete()
|
|
|
379
379
|
RG_UNREACHABLE();
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
382
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
|
|
383
383
|
{
|
|
384
384
|
if (RG_UNLIKELY(env.IsExceptionPending()))
|
|
385
385
|
return;
|
|
386
386
|
|
|
387
|
-
const TrampolineInfo &trampoline =
|
|
387
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
388
388
|
|
|
389
389
|
const FunctionInfo *proto = trampoline.proto;
|
|
390
390
|
Napi::Function func = trampoline.func.Value();
|
package/src/koffi/src/abi_x86.cc
CHANGED
|
@@ -172,7 +172,7 @@ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
|
|
|
172
172
|
return true;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
175
|
+
bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
176
176
|
{
|
|
177
177
|
uint32_t *args_ptr = nullptr;
|
|
178
178
|
uint32_t *fast_ptr = nullptr;
|
|
@@ -362,7 +362,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
362
362
|
return true;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
void CallData::Execute()
|
|
365
|
+
void CallData::Execute(const FunctionInfo *func)
|
|
366
366
|
{
|
|
367
367
|
#define PERFORM_CALL(Suffix) \
|
|
368
368
|
([&]() { \
|
|
@@ -404,7 +404,7 @@ void CallData::Execute()
|
|
|
404
404
|
#undef PERFORM_CALL
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
-
Napi::Value CallData::Complete()
|
|
407
|
+
Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
408
408
|
{
|
|
409
409
|
RG_DEFER {
|
|
410
410
|
PopOutArguments();
|
|
@@ -461,12 +461,12 @@ Napi::Value CallData::Complete()
|
|
|
461
461
|
RG_UNREACHABLE();
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
-
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
464
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
|
|
465
465
|
{
|
|
466
466
|
if (RG_UNLIKELY(env.IsExceptionPending()))
|
|
467
467
|
return;
|
|
468
468
|
|
|
469
|
-
const TrampolineInfo &trampoline =
|
|
469
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
470
470
|
|
|
471
471
|
const FunctionInfo *proto = trampoline.proto;
|
|
472
472
|
Napi::Function func = trampoline.func.Value();
|
package/src/koffi/src/call.cc
CHANGED
|
@@ -33,10 +33,9 @@ struct RelayContext {
|
|
|
33
33
|
bool done = false;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
CallData::CallData(Napi::Env env, InstanceData *instance,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap), async(async)
|
|
36
|
+
CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
|
|
37
|
+
: env(env), instance(instance),
|
|
38
|
+
mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
|
|
40
39
|
{
|
|
41
40
|
mem->generation += !mem->depth;
|
|
42
41
|
mem->depth++;
|
|
@@ -54,7 +53,21 @@ CallData::~CallData()
|
|
|
54
53
|
mem->stack = old_stack_mem;
|
|
55
54
|
mem->heap = old_heap_mem;
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
if (used_trampolines) {
|
|
57
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
58
|
+
|
|
59
|
+
for (Size i = 0; i < MaxTrampolines; i++) {
|
|
60
|
+
if (used_trampolines & (1u << i)) {
|
|
61
|
+
TrampolineInfo *trampoline = &shared.trampolines[i];
|
|
62
|
+
|
|
63
|
+
trampoline->func.Reset();
|
|
64
|
+
trampoline->recv.Reset();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
shared.temp_trampolines ^= used_trampolines;
|
|
69
|
+
}
|
|
70
|
+
|
|
58
71
|
instance->temporaries -= mem->temporary;
|
|
59
72
|
|
|
60
73
|
if (!--mem->depth && mem->temporary) {
|
|
@@ -66,7 +79,7 @@ CallData::~CallData()
|
|
|
66
79
|
|
|
67
80
|
void CallData::RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
68
81
|
{
|
|
69
|
-
if (
|
|
82
|
+
if (std::this_thread::get_id() != instance->main_thread_id) {
|
|
70
83
|
RelayContext ctx;
|
|
71
84
|
|
|
72
85
|
ctx.call = this;
|
|
@@ -83,7 +96,7 @@ void CallData::RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegi
|
|
|
83
96
|
ctx.cv.wait(lock);
|
|
84
97
|
}
|
|
85
98
|
} else {
|
|
86
|
-
Relay(idx, own_sp, caller_sp, out_reg);
|
|
99
|
+
Relay(idx, own_sp, caller_sp, false, out_reg);
|
|
87
100
|
}
|
|
88
101
|
}
|
|
89
102
|
|
|
@@ -91,7 +104,7 @@ void CallData::RelayAsync(napi_env, napi_value, void *, void *udata)
|
|
|
91
104
|
{
|
|
92
105
|
RelayContext *ctx = (RelayContext *)udata;
|
|
93
106
|
|
|
94
|
-
ctx->call->Relay(ctx->idx, ctx->own_sp, ctx->caller_sp, ctx->out_reg);
|
|
107
|
+
ctx->call->Relay(ctx->idx, ctx->own_sp, ctx->caller_sp, true, ctx->out_reg);
|
|
95
108
|
|
|
96
109
|
// We're done!
|
|
97
110
|
std::lock_guard<std::mutex> lock(ctx->mutex);
|
|
@@ -1012,18 +1025,22 @@ void CallData::PopOutArguments()
|
|
|
1012
1025
|
|
|
1013
1026
|
void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
|
|
1014
1027
|
{
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
}
|
|
1028
|
+
int idx;
|
|
1029
|
+
{
|
|
1030
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1019
1031
|
|
|
1020
|
-
|
|
1032
|
+
idx = CountTrailingZeros(~shared.temp_trampolines);
|
|
1021
1033
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1034
|
+
if (RG_UNLIKELY(idx >= MaxTrampolines)) {
|
|
1035
|
+
ThrowError<Napi::Error>(env, "Too many temporary callbacks are in use (max = %1)", MaxTrampolines);
|
|
1036
|
+
return env.Null();
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
shared.temp_trampolines |= 1u << idx;
|
|
1040
|
+
used_trampolines |= 1u << idx;
|
|
1041
|
+
}
|
|
1025
1042
|
|
|
1026
|
-
TrampolineInfo *trampoline = &
|
|
1043
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1027
1044
|
|
|
1028
1045
|
trampoline->proto = proto;
|
|
1029
1046
|
trampoline->func.Reset(func, 1);
|
|
@@ -1034,7 +1051,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
|
|
|
1034
1051
|
return ptr;
|
|
1035
1052
|
}
|
|
1036
1053
|
|
|
1037
|
-
void CallData::DumpForward() const
|
|
1054
|
+
void CallData::DumpForward(const FunctionInfo *func) const
|
|
1038
1055
|
{
|
|
1039
1056
|
PrintLn(stderr, "%!..+---- %1 (%2) ----%!0", func->name, CallConventionNames[(int)func->convention]);
|
|
1040
1057
|
|
package/src/koffi/src/call.hh
CHANGED
|
@@ -36,15 +36,12 @@ class alignas(8) CallData {
|
|
|
36
36
|
|
|
37
37
|
Napi::Env env;
|
|
38
38
|
InstanceData *instance;
|
|
39
|
-
const FunctionInfo *func;
|
|
40
39
|
|
|
41
40
|
InstanceMemory *mem;
|
|
42
41
|
Span<uint8_t> old_stack_mem;
|
|
43
42
|
Span<uint8_t> old_heap_mem;
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
int16_t used_trampolines = 0;
|
|
44
|
+
uint32_t used_trampolines = 0;
|
|
48
45
|
|
|
49
46
|
LocalArray<OutArgument, MaxOutParameters> out_arguments;
|
|
50
47
|
|
|
@@ -70,8 +67,7 @@ class alignas(8) CallData {
|
|
|
70
67
|
BlockAllocator call_alloc;
|
|
71
68
|
|
|
72
69
|
public:
|
|
73
|
-
CallData(Napi::Env env, InstanceData *instance,
|
|
74
|
-
const FunctionInfo *func, InstanceMemory *mem, bool async);
|
|
70
|
+
CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem);
|
|
75
71
|
~CallData();
|
|
76
72
|
|
|
77
73
|
#ifdef UNITY_BUILD
|
|
@@ -84,17 +80,17 @@ public:
|
|
|
84
80
|
#define INLINE_IF_UNITY
|
|
85
81
|
#endif
|
|
86
82
|
|
|
87
|
-
INLINE_IF_UNITY bool Prepare(const Napi::CallbackInfo &info);
|
|
88
|
-
INLINE_IF_UNITY void Execute();
|
|
89
|
-
INLINE_IF_UNITY Napi::Value Complete();
|
|
83
|
+
INLINE_IF_UNITY bool Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info);
|
|
84
|
+
INLINE_IF_UNITY void Execute(const FunctionInfo *func);
|
|
85
|
+
INLINE_IF_UNITY Napi::Value Complete(const FunctionInfo *func);
|
|
90
86
|
|
|
91
87
|
#undef INLINE_IF_UNITY
|
|
92
88
|
|
|
93
|
-
void Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg);
|
|
89
|
+
void Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg);
|
|
94
90
|
void RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg);
|
|
95
91
|
static void RelayAsync(napi_env, napi_value, void *, void *udata);
|
|
96
92
|
|
|
97
|
-
void DumpForward() const;
|
|
93
|
+
void DumpForward(const FunctionInfo *func) const;
|
|
98
94
|
|
|
99
95
|
private:
|
|
100
96
|
template <typename T>
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
|
|
41
41
|
namespace RG {
|
|
42
42
|
|
|
43
|
+
SharedData shared;
|
|
44
|
+
|
|
43
45
|
// Value does not matter, the tag system uses memory addresses
|
|
44
46
|
const int TypeInfoMarker = 0xDEADBEEF;
|
|
45
47
|
const int CastMarker = 0xDEADBEEF;
|
|
@@ -1059,16 +1061,16 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
|
|
|
1059
1061
|
}
|
|
1060
1062
|
|
|
1061
1063
|
InstanceMemory *mem = instance->memories[0];
|
|
1062
|
-
CallData call(env, instance,
|
|
1064
|
+
CallData call(env, instance, mem);
|
|
1063
1065
|
|
|
1064
1066
|
RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
|
|
1065
1067
|
exec_call = &call;
|
|
1066
1068
|
|
|
1067
|
-
if (!RG_UNLIKELY(call.Prepare(info)))
|
|
1069
|
+
if (!RG_UNLIKELY(call.Prepare(func, info)))
|
|
1068
1070
|
return env.Null();
|
|
1069
1071
|
|
|
1070
1072
|
if (instance->debug) {
|
|
1071
|
-
call.DumpForward();
|
|
1073
|
+
call.DumpForward(func);
|
|
1072
1074
|
}
|
|
1073
1075
|
|
|
1074
1076
|
// Execute call
|
|
@@ -1076,10 +1078,10 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
|
|
|
1076
1078
|
RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
|
|
1077
1079
|
exec_call = &call;
|
|
1078
1080
|
|
|
1079
|
-
call.Execute();
|
|
1081
|
+
call.Execute(func);
|
|
1080
1082
|
}
|
|
1081
1083
|
|
|
1082
|
-
return call.Complete();
|
|
1084
|
+
return call.Complete(func);
|
|
1083
1085
|
}
|
|
1084
1086
|
|
|
1085
1087
|
static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
@@ -1136,13 +1138,13 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
1136
1138
|
return env.Null();
|
|
1137
1139
|
|
|
1138
1140
|
InstanceMemory *mem = instance->memories[0];
|
|
1139
|
-
CallData call(env, instance,
|
|
1141
|
+
CallData call(env, instance, mem);
|
|
1140
1142
|
|
|
1141
|
-
if (!RG_UNLIKELY(call.Prepare(info)))
|
|
1143
|
+
if (!RG_UNLIKELY(call.Prepare(&func, info)))
|
|
1142
1144
|
return env.Null();
|
|
1143
1145
|
|
|
1144
1146
|
if (instance->debug) {
|
|
1145
|
-
call.DumpForward();
|
|
1147
|
+
call.DumpForward(&func);
|
|
1146
1148
|
}
|
|
1147
1149
|
|
|
1148
1150
|
// Execute call
|
|
@@ -1150,10 +1152,10 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
1150
1152
|
RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
|
|
1151
1153
|
exec_call = &call;
|
|
1152
1154
|
|
|
1153
|
-
call.Execute();
|
|
1155
|
+
call.Execute(&func);
|
|
1154
1156
|
}
|
|
1155
1157
|
|
|
1156
|
-
return call.Complete();
|
|
1158
|
+
return call.Complete(&func);
|
|
1157
1159
|
}
|
|
1158
1160
|
|
|
1159
1161
|
class AsyncCall: public Napi::AsyncWorker {
|
|
@@ -1167,11 +1169,11 @@ public:
|
|
|
1167
1169
|
AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
|
|
1168
1170
|
InstanceMemory *mem, Napi::Function &callback)
|
|
1169
1171
|
: Napi::AsyncWorker(callback), env(env), func(func->Ref()),
|
|
1170
|
-
call(env, instance,
|
|
1172
|
+
call(env, instance, mem) {}
|
|
1171
1173
|
~AsyncCall() { func->Unref(); }
|
|
1172
1174
|
|
|
1173
1175
|
bool Prepare(const Napi::CallbackInfo &info) {
|
|
1174
|
-
prepared = call.Prepare(info);
|
|
1176
|
+
prepared = call.Prepare(func, info);
|
|
1175
1177
|
|
|
1176
1178
|
if (!prepared) {
|
|
1177
1179
|
Napi::Error err = env.GetAndClearPendingException();
|
|
@@ -1180,7 +1182,7 @@ public:
|
|
|
1180
1182
|
|
|
1181
1183
|
return prepared;
|
|
1182
1184
|
}
|
|
1183
|
-
void DumpForward() { call.DumpForward(); }
|
|
1185
|
+
void DumpForward() { call.DumpForward(func); }
|
|
1184
1186
|
|
|
1185
1187
|
void Execute() override;
|
|
1186
1188
|
void OnOK() override;
|
|
@@ -1192,7 +1194,7 @@ void AsyncCall::Execute()
|
|
|
1192
1194
|
RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
|
|
1193
1195
|
exec_call = &call;
|
|
1194
1196
|
|
|
1195
|
-
call.Execute();
|
|
1197
|
+
call.Execute(func);
|
|
1196
1198
|
}
|
|
1197
1199
|
}
|
|
1198
1200
|
|
|
@@ -1205,7 +1207,7 @@ void AsyncCall::OnOK()
|
|
|
1205
1207
|
Napi::Value self = env.Null();
|
|
1206
1208
|
napi_value args[] = {
|
|
1207
1209
|
env.Null(),
|
|
1208
|
-
call.Complete()
|
|
1210
|
+
call.Complete(func)
|
|
1209
1211
|
};
|
|
1210
1212
|
|
|
1211
1213
|
callback.Call(self, RG_LEN(args), args);
|
|
@@ -1434,18 +1436,22 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
1434
1436
|
return env.Null();
|
|
1435
1437
|
}
|
|
1436
1438
|
|
|
1439
|
+
int idx;
|
|
1440
|
+
{
|
|
1441
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1437
1442
|
|
|
1438
|
-
|
|
1443
|
+
idx = CountTrailingZeros(~shared.registered_trampolines);
|
|
1439
1444
|
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1445
|
+
if (RG_UNLIKELY(idx >= MaxTrampolines)) {
|
|
1446
|
+
ThrowError<Napi::Error>(env, "Too many registered callbacks are in use (max = %1)", MaxTrampolines);
|
|
1447
|
+
return env.Null();
|
|
1448
|
+
}
|
|
1444
1449
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1450
|
+
shared.registered_trampolines |= 1u << idx;
|
|
1451
|
+
idx += MaxTrampolines;
|
|
1452
|
+
}
|
|
1447
1453
|
|
|
1448
|
-
TrampolineInfo *trampoline = &
|
|
1454
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1449
1455
|
|
|
1450
1456
|
trampoline->proto = type->ref.proto;
|
|
1451
1457
|
trampoline->func.Reset(func, 1);
|
|
@@ -1481,19 +1487,26 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
|
1481
1487
|
Napi::External<void> external = info[0].As<Napi::External<void>>();
|
|
1482
1488
|
void *ptr = external.Data();
|
|
1483
1489
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1490
|
+
// Release shared trampoline safely
|
|
1491
|
+
{
|
|
1492
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1493
|
+
|
|
1494
|
+
for (Size i = 0; i < MaxTrampolines; i++) {
|
|
1495
|
+
Size idx = i + MaxTrampolines;
|
|
1496
|
+
|
|
1497
|
+
if (!(shared.registered_trampolines & (1u << i)))
|
|
1498
|
+
continue;
|
|
1486
1499
|
|
|
1487
|
-
|
|
1488
|
-
continue;
|
|
1500
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1489
1501
|
|
|
1490
|
-
|
|
1502
|
+
if (GetTrampoline(idx, trampoline->proto) == ptr) {
|
|
1503
|
+
shared.registered_trampolines &= ~(1u << i);
|
|
1491
1504
|
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
trampoline->recv.Reset();
|
|
1505
|
+
trampoline->func.Reset();
|
|
1506
|
+
trampoline->recv.Reset();
|
|
1495
1507
|
|
|
1496
|
-
|
|
1508
|
+
return env.Undefined();
|
|
1509
|
+
}
|
|
1497
1510
|
}
|
|
1498
1511
|
}
|
|
1499
1512
|
|
|
@@ -1696,6 +1709,25 @@ InstanceData::~InstanceData()
|
|
|
1696
1709
|
delete mem;
|
|
1697
1710
|
}
|
|
1698
1711
|
|
|
1712
|
+
// Clean-up leftover registered trampolines
|
|
1713
|
+
{
|
|
1714
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1715
|
+
|
|
1716
|
+
for (Size i = 0; i < MaxTrampolines; i++) {
|
|
1717
|
+
Size idx = i + MaxTrampolines;
|
|
1718
|
+
|
|
1719
|
+
if (!(shared.registered_trampolines & (1u << i)))
|
|
1720
|
+
continue;
|
|
1721
|
+
|
|
1722
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1723
|
+
|
|
1724
|
+
if (trampoline->func.Env().GetInstanceData<InstanceData>() == this) {
|
|
1725
|
+
trampoline->func.Reset();
|
|
1726
|
+
trampoline->recv.Reset();
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1699
1731
|
if (broker) {
|
|
1700
1732
|
napi_release_threadsafe_function(broker, napi_tsfn_abort);
|
|
1701
1733
|
}
|
|
@@ -1856,7 +1888,21 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
|
|
|
1856
1888
|
|
|
1857
1889
|
extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
1858
1890
|
{
|
|
1859
|
-
exec_call
|
|
1891
|
+
if (RG_LIKELY(exec_call)) {
|
|
1892
|
+
exec_call->RelaySafe(idx, own_sp, caller_sp, out_reg);
|
|
1893
|
+
} else {
|
|
1894
|
+
Napi::Env env = shared.trampolines[idx].func.Env();
|
|
1895
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1896
|
+
|
|
1897
|
+
InstanceMemory *mem = AllocateMemory(instance, instance->async_stack_size, instance->async_heap_size);
|
|
1898
|
+
if (RG_UNLIKELY(!mem)) {
|
|
1899
|
+
ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
CallData call(env, instance, mem);
|
|
1904
|
+
call.RelaySafe(idx, own_sp, caller_sp, out_reg);
|
|
1905
|
+
}
|
|
1860
1906
|
}
|
|
1861
1907
|
|
|
1862
1908
|
static InstanceData *CreateInstance(Napi::Env env)
|
|
@@ -1864,9 +1910,10 @@ static InstanceData *CreateInstance(Napi::Env env)
|
|
|
1864
1910
|
InstanceData *instance = new InstanceData();
|
|
1865
1911
|
RG_DEFER_N(err_guard) { delete instance; };
|
|
1866
1912
|
|
|
1867
|
-
|
|
1913
|
+
instance->main_thread_id = std::this_thread::get_id();
|
|
1868
1914
|
|
|
1869
|
-
if (napi_create_threadsafe_function(env, nullptr, nullptr,
|
|
1915
|
+
if (napi_create_threadsafe_function(env, nullptr, nullptr,
|
|
1916
|
+
Napi::String::New(env, "Koffi Async Callback Broker"),
|
|
1870
1917
|
0, 1, nullptr, nullptr, nullptr,
|
|
1871
1918
|
CallData::RelayAsync, &instance->broker) != napi_ok) {
|
|
1872
1919
|
LogError("Failed to create async callback broker");
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -233,14 +233,6 @@ struct InstanceMemory {
|
|
|
233
233
|
bool temporary;
|
|
234
234
|
};
|
|
235
235
|
|
|
236
|
-
struct TrampolineInfo {
|
|
237
|
-
const FunctionInfo *proto;
|
|
238
|
-
Napi::FunctionReference func;
|
|
239
|
-
Napi::Reference<Napi::Value> recv;
|
|
240
|
-
|
|
241
|
-
int32_t generation;
|
|
242
|
-
};
|
|
243
|
-
|
|
244
236
|
struct InstanceData {
|
|
245
237
|
~InstanceData();
|
|
246
238
|
|
|
@@ -258,11 +250,7 @@ struct InstanceData {
|
|
|
258
250
|
LocalArray<InstanceMemory *, 9> memories;
|
|
259
251
|
int temporaries = 0;
|
|
260
252
|
|
|
261
|
-
|
|
262
|
-
int16_t next_trampoline = 0;
|
|
263
|
-
int16_t temp_trampolines = 0;
|
|
264
|
-
uint32_t registered_trampolines = 0;
|
|
265
|
-
|
|
253
|
+
std::thread::id main_thread_id;
|
|
266
254
|
napi_threadsafe_function broker = nullptr;
|
|
267
255
|
|
|
268
256
|
BlockAllocator str_alloc;
|
|
@@ -280,4 +268,22 @@ RG_STATIC_ASSERT(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
|
|
|
280
268
|
RG_STATIC_ASSERT(MaxAsyncCalls >= DefaultMaxAsyncCalls);
|
|
281
269
|
RG_STATIC_ASSERT(MaxTrampolines <= 16);
|
|
282
270
|
|
|
271
|
+
struct TrampolineInfo {
|
|
272
|
+
const FunctionInfo *proto;
|
|
273
|
+
Napi::FunctionReference func;
|
|
274
|
+
Napi::Reference<Napi::Value> recv;
|
|
275
|
+
|
|
276
|
+
int32_t generation;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
struct SharedData {
|
|
280
|
+
std::mutex mutex;
|
|
281
|
+
|
|
282
|
+
TrampolineInfo trampolines[MaxTrampolines * 2];
|
|
283
|
+
uint32_t temp_trampolines = 0;
|
|
284
|
+
uint32_t registered_trampolines = 0;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
extern SharedData shared;
|
|
288
|
+
|
|
283
289
|
}
|
|
@@ -75,6 +75,7 @@ async function test() {
|
|
|
75
75
|
const ApplyStruct = lib.func('int ApplyStruct(int x, StructCallbacks callbacks)');
|
|
76
76
|
const SetCallback = lib.func('void SetCallback(IntCallback *func)');
|
|
77
77
|
const CallCallback = lib.func('int CallCallback(int x)');
|
|
78
|
+
const CallFromThread = lib.func('int CallFromThread(int x)');
|
|
78
79
|
const MakeVectors = lib.func('int MakeVectors(int len, VectorCallback *func)');
|
|
79
80
|
const CallQSort = lib.func('void CallQSort(_Inout_ void *base, size_t nmemb, size_t size, SortCallback *cb)');
|
|
80
81
|
const CallMeChar = lib.func('int CallMeChar(CharCallback *func)');
|
|
@@ -260,4 +261,14 @@ async function test() {
|
|
|
260
261
|
|
|
261
262
|
assert.equal(ret, 97 + 2 * 98);
|
|
262
263
|
}
|
|
264
|
+
|
|
265
|
+
// Use callback from secondary thread
|
|
266
|
+
for (let i = 0; i < 128; i++) {
|
|
267
|
+
let cb = koffi.register(x => -x - 2, koffi.pointer(IntCallback));
|
|
268
|
+
|
|
269
|
+
SetCallback(cb);
|
|
270
|
+
assert.equal(await util.promisify(CallFromThread.async)(27), -29);
|
|
271
|
+
|
|
272
|
+
koffi.unregister(cb);
|
|
273
|
+
}
|
|
263
274
|
}
|
package/src/koffi/test/misc.c
CHANGED
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
typedef uint16_t char16_t;
|
|
23
23
|
typedef uint32_t char32_t;
|
|
24
24
|
#endif
|
|
25
|
+
#ifdef _WIN32
|
|
26
|
+
#define NOMINMAX
|
|
27
|
+
#define WIN32_LEAN_AND_MEAN
|
|
28
|
+
#include <windows.h>
|
|
29
|
+
#else
|
|
30
|
+
#include <errno.h>
|
|
31
|
+
#include <pthread.h>
|
|
32
|
+
#endif
|
|
25
33
|
|
|
26
34
|
#ifdef _WIN32
|
|
27
35
|
#define EXPORT __declspec(dllexport)
|
|
@@ -671,6 +679,55 @@ EXPORT int CallCallback(int x)
|
|
|
671
679
|
return callback(x);
|
|
672
680
|
}
|
|
673
681
|
|
|
682
|
+
#ifdef _WIN32
|
|
683
|
+
|
|
684
|
+
static DWORD WINAPI CallFromThreadFunc(void *udata)
|
|
685
|
+
{
|
|
686
|
+
int *ptr = (int *)udata;
|
|
687
|
+
*ptr = callback(*ptr);
|
|
688
|
+
|
|
689
|
+
return 0;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
EXPORT int CallFromThread(int x)
|
|
693
|
+
{
|
|
694
|
+
HANDLE h = CreateThread(NULL, 0, CallFromThreadFunc, &x, 0, NULL);
|
|
695
|
+
if (!h) {
|
|
696
|
+
perror("CreateThread");
|
|
697
|
+
exit(1);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
WaitForSingleObject(h, INFINITE);
|
|
701
|
+
|
|
702
|
+
return x;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
#else
|
|
706
|
+
|
|
707
|
+
static void *CallFromThreadFunc(void *udata)
|
|
708
|
+
{
|
|
709
|
+
int *ptr = (int *)udata;
|
|
710
|
+
*ptr = callback(*ptr);
|
|
711
|
+
|
|
712
|
+
return NULL;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
EXPORT int CallFromThread(int x)
|
|
716
|
+
{
|
|
717
|
+
pthread_t thread;
|
|
718
|
+
|
|
719
|
+
if (pthread_create(&thread, NULL, CallFromThreadFunc, &x)) {
|
|
720
|
+
perror("pthread_create");
|
|
721
|
+
exit(1);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
pthread_join(thread, NULL);
|
|
725
|
+
|
|
726
|
+
return x;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
#endif
|
|
730
|
+
|
|
674
731
|
EXPORT void ReverseBytes(void *p, int len)
|
|
675
732
|
{
|
|
676
733
|
uint8_t *bytes = (uint8_t *)p;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|