forked from node-ffi/node-ffi
-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathffi.h
148 lines (119 loc) · 3.9 KB
/
ffi.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <limits.h>
#include <errno.h>
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS true
#endif
#include <stdint.h>
#include <queue>
#ifdef WIN32
#include "win32-dlfcn.h"
#else
#include <dlfcn.h>
#endif
/* define FFI_BUILDING before including ffi.h to workaround a libffi bug on Windows */
#define FFI_BUILDING
#include <ffi.h>
#include <uv.h>
#include <node_object_wrap.h>
#include <node.h>
#include <nan.h>
#if __OBJC__ || __OBJC2__
#include <objc/objc.h>
#endif
#define THROW_ERROR_EXCEPTION(x) Nan::ThrowError(x)
#define THROW_ERROR_EXCEPTION_WITH_STATUS_CODE(x, y) Nan::ThrowError(x)
#define FFI_ASYNC_ERROR (ffi_status)1
using namespace v8;
using namespace node;
/*
* Converts an arbitrary pointer to a node Buffer with 0-length
*/
void wrap_pointer_cb(char *data, void *hint);
inline Local<Value> WrapPointer(char *ptr, size_t length) {
Nan::EscapableHandleScope scope;
return scope.Escape(Nan::NewBuffer(ptr, length, wrap_pointer_cb, NULL).ToLocalChecked());
}
inline Local<Value> WrapPointer(char *ptr) {
return WrapPointer(ptr, 0);
}
/*
* Class used to store stuff during async ffi_call() invokations.
*/
class AsyncCallParams {
public:
ffi_status result;
char *err;
char *cif;
char *fn;
char *res;
char *argv;
Nan::Callback *callback;
};
class FFI {
public:
static NAN_MODULE_INIT(InitializeStaticFunctions);
static NAN_MODULE_INIT(InitializeBindings);
protected:
static NAN_METHOD(FFIPrepCif);
static NAN_METHOD(FFIPrepCifVar);
static NAN_METHOD(FFICall);
static NAN_METHOD(FFICallAsync);
static void AsyncFFICall(uv_work_t *req);
static void FinishAsyncFFICall(uv_work_t *req);
static NAN_METHOD(Strtoul);
};
/*
* One of these structs gets created for each `ffi.Callback()` invokation in
* JavaScript-land. It contains all the necessary information when invoking the
* pointer to proxy back to JS-land properly. It gets created by
* `ffi_closure_alloc()`, and free'd in the closure_pointer_cb function.
*/
typedef struct _callback_info {
ffi_closure closure; // the actual `ffi_closure` instance get inlined
void *code; // the executable function pointer
Nan::Callback* errorFunction; // JS callback function for reporting catched exceptions for the process' event loop
Nan::Callback* function; // JS callback function the closure represents
// these two are required for creating proper sized WrapPointer buffer instances
int argc; // the number of arguments this function expects
size_t resultSize; // the size of the result pointer
} callback_info;
class ThreadedCallbackInvokation;
class CallbackInfo {
public:
static NAN_MODULE_INIT(Initialize);
static void WatcherCallback(uv_async_t *w, int revents);
protected:
static void DispatchToV8(callback_info *self, void *retval, void **parameters, bool dispatched = false);
static void Invoke(ffi_cif *cif, void *retval, void **parameters, void *user_data);
static NAN_METHOD(Callback);
private:
#ifdef WIN32
static DWORD g_threadID;
#else
static uv_thread_t g_mainthread;
#endif // WIN32
static uv_mutex_t g_queue_mutex;
static std::queue<ThreadedCallbackInvokation *> g_queue;
static uv_async_t g_async;
};
/**
* Synchronization object to ensure following order of execution:
* -> WaitForExecution() invoked
* -> SignalDoneExecuting() returned
* -> WaitForExecution() returned
*
* ^WaitForExecution() must always be called from the thread which owns the object
*/
class ThreadedCallbackInvokation {
public:
ThreadedCallbackInvokation(callback_info *cbinfo, void *retval, void **parameters);
~ThreadedCallbackInvokation();
void SignalDoneExecuting();
void WaitForExecution();
void *m_retval;
void **m_parameters;
callback_info *m_cbinfo;
private:
uv_cond_t m_cond;
uv_mutex_t m_mutex;
};