Skip to content

Commit 3f15fa6

Browse files
committed
fix ISR crash on node >=0.11.x
1 parent 98d2adc commit 3f15fa6

1 file changed

Lines changed: 75 additions & 81 deletions

File tree

src/wiringPiISR.cc

Lines changed: 75 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,71 @@
11
#include "wiringPiISR.h"
22
#include <wiringPi.h>
3-
#include <iostream>
4-
#include <map>
53
#include <uv.h>
64

75
using namespace v8;
86

9-
typedef struct js_work_t {
10-
uv_work_t req;
11-
int pin;
12-
unsigned int delta;
13-
} js_work_t;
7+
typedef struct interrupt_t {
8+
int pin;
9+
unsigned int delta;
10+
unsigned long int previous_timestamp;
11+
} interrupt_t;
1412

13+
#if NODE_VERSION_AT_LEAST(0, 11, 0)
14+
typedef v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function> > CopyablePersistentFunction;
15+
#else
16+
typedef v8::Persistent<v8::Function> CopyablePersistentFunction;
17+
#endif
1518
typedef void (*NATIVE_INTERRUPT_HANDLER_T)(void);
1619

17-
static NATIVE_INTERRUPT_HANDLER_T nativeInterruptHandlers[64];
18-
static unsigned long int lastInterruptMicroseconds[64];
19-
static std::map<int, v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function> > > interruptCallbackMapping;
20-
static uv_async_t asyncHandlers[64];
20+
static uv_async_t async_handlers[64];
21+
static interrupt_t interrupt_data[64];
22+
static NATIVE_INTERRUPT_HANDLER_T interrupt_handlers[64];
23+
static CopyablePersistentFunction interrupt_callbacks[64];
2124

2225
#define DEFINE_NATIVE_INTERRUPT_HANDLER(pin) \
2326
static void nativeInterruptHandler##pin(void) { \
2427
processNativeInterrupt(pin); \
2528
}
26-
27-
#define REGISTER_NATIVE_INTERRUPT_HANDLER(pin) nativeInterruptHandlers[pin] = &nativeInterruptHandler##pin
28-
29-
#define GET_NATIVE_INTERRUPT_HANDLER(pin) nativeInterruptHandlers[pin]
30-
31-
static void processInterrupt(uv_work_t* req, int status) {
32-
js_work_t* work = static_cast<js_work_t*>(req->data);
33-
34-
#if NODE_VERSION_AT_LEAST(0, 11, 0)
35-
v8::Isolate* isolate = v8::Isolate::GetCurrent();
36-
Local<Function> callback = Local<Function>::New(isolate, interruptCallbackMapping[work->pin]);
37-
#else
38-
Persistent<Function> callback = interruptCallbackMapping[work->pin];
39-
#endif
40-
41-
Local<Value> argv[] = {
42-
#if NODE_VERSION_AT_LEAST(0, 11, 0)
43-
Local<Value>::New(isolate, UINT32(work->delta))
44-
#else
45-
Local<Value>::New(UINT32(work->delta))
46-
#endif
47-
};
48-
49-
#if NODE_VERSION_AT_LEAST(0, 11, 0)
50-
callback->Call(isolate->GetCurrentContext()->Global(), 1, argv);
51-
#else
52-
callback->Call(Context::GetCurrent()->Global(), 1, argv);
53-
#endif
54-
55-
delete work;
56-
}
5729

58-
static void UV_NOP(uv_work_t*) {}
59-
static void UV_ASYNC_NOP(uv_async_t* handler) {}
30+
#define REGISTER_NATIVE_INTERRUPT_HANDLER(pin) interrupt_handlers[pin] = &nativeInterruptHandler##pin
6031

6132
void processNativeInterrupt(int pin) {
6233
unsigned int now = ::micros();
63-
64-
js_work_t* work = new js_work_t;
65-
work->req.data = work;
66-
work->pin = pin;
67-
work->delta = now - lastInterruptMicroseconds[pin];
68-
69-
int r = uv_queue_work(uv_default_loop(), &work->req, &UV_NOP, &processInterrupt);
70-
if (r != 0) {
71-
delete work;
72-
}
73-
74-
lastInterruptMicroseconds[pin] = now;
34+
35+
uv_async_t* handle = &async_handlers[pin];
36+
interrupt_t* data = &interrupt_data[pin];
37+
data->pin = pin;
38+
data->delta = now - data->previous_timestamp;
39+
handle->data = (void*)data;
40+
41+
uv_async_send(handle);
42+
43+
data->previous_timestamp = now;
44+
}
45+
46+
#if NODE_VERSION_AT_LEAST(0, 11, 0)
47+
static void dispatchInterrupt(uv_async_t* handle) {
48+
#else
49+
static void dispatchInterrupt(uv_async_t* handle, int status) {
50+
#endif
51+
interrupt_t* data = (interrupt_t*)handle->data;
52+
53+
#if NODE_VERSION_AT_LEAST(0, 11, 0)
54+
v8::Isolate* isolate = v8::Isolate::GetCurrent();
55+
v8::Local<Function> callback = v8::Local<Function>::New(isolate, interrupt_callbacks[data->pin]);
56+
#else
57+
v8::Local<Function> callback = v8::Local<Function>::New(interrupt_callbacks[data->pin]);
58+
#endif
59+
60+
Local<Value> argv[] = {
61+
UINT32(data->delta)
62+
};
63+
64+
#if NODE_VERSION_AT_LEAST(0, 11, 0)
65+
callback->Call(isolate->GetCurrentContext()->Global(), 1, argv);
66+
#else
67+
callback->Call(Context::GetCurrent()->Global(), 1, argv);
68+
#endif
7569
}
7670

7771
DEFINE_NATIVE_INTERRUPT_HANDLER(0);
@@ -142,54 +136,54 @@ DEFINE_NATIVE_INTERRUPT_HANDLER(63);
142136
DECLARE(wiringPiISR);
143137
IMPLEMENT(wiringPiISR) {
144138
SCOPE_OPEN();
145-
139+
146140
SET_ARGUMENT_NAME(0, pin);
147141
SET_ARGUMENT_NAME(1, edgeType);
148142
SET_ARGUMENT_NAME(2, callback);
149-
143+
150144
CHECK_ARGUMENTS_LENGTH_EQUAL(3);
151-
145+
152146
CHECK_ARGUMENT_TYPE_INT32(0);
153147
CHECK_ARGUMENT_TYPE_INT32(1);
154148
CHECK_ARGUMENT_TYPE_FUNCTION(2);
155-
149+
156150
int pin = GET_ARGUMENT_AS_INT32(0);
157151
int edgeType = GET_ARGUMENT_AS_INT32(1);
158-
152+
159153
#if NODE_VERSION_AT_LEAST(0, 11, 0)
160154
Persistent<Function> callback(isolate, GET_ARGUMENT_AS_LOCAL_FUNCTION(2));
161155
#else
162156
Persistent<Function> callback = GET_ARGUMENT_AS_PERSISTENT_FUNCTION(2);
163157
#endif
164-
158+
165159
CHECK_ARGUMENT_IN_INTS(1, edgeType, (INT_EDGE_FALLING, INT_EDGE_RISING, INT_EDGE_BOTH, INT_EDGE_SETUP));
166-
167-
interruptCallbackMapping.insert(std::pair<int, v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function> > >(pin, callback));
168-
lastInterruptMicroseconds[pin] = ::micros();
169-
170-
::wiringPiISR(pin, edgeType, GET_NATIVE_INTERRUPT_HANDLER(pin));
171-
172-
uv_async_init(uv_default_loop(), &asyncHandlers[pin], &UV_ASYNC_NOP);
173-
uv_ref((uv_handle_t*)&asyncHandlers[pin]);
174-
160+
161+
interrupt_callbacks[pin] = callback;
162+
interrupt_data[pin].previous_timestamp = ::micros();
163+
164+
::wiringPiISR(pin, edgeType, interrupt_handlers[pin]);
165+
166+
uv_async_init(uv_default_loop(), &async_handlers[pin], &dispatchInterrupt);
167+
uv_ref((uv_handle_t*)&async_handlers[pin]);
168+
175169
SCOPE_CLOSE(UNDEFINED());
176170
}
177171

178172
DECLARE(wiringPiISRCancel);
179173
IMPLEMENT(wiringPiISRCancel) {
180174
SCOPE_OPEN();
181-
175+
182176
SET_ARGUMENT_NAME(0, pin);
183-
177+
184178
CHECK_ARGUMENTS_LENGTH_EQUAL(1);
185-
179+
186180
CHECK_ARGUMENT_TYPE_INT32(0);
187-
181+
188182
int pin = GET_ARGUMENT_AS_INT32(0);
189-
183+
190184
::wiringPiISRCancel(pin);
191-
uv_close((uv_handle_t*)&asyncHandlers[pin], NULL);
192-
185+
uv_close((uv_handle_t*)&async_handlers[pin], NULL);
186+
193187
SCOPE_CLOSE(UNDEFINED());
194188
}
195189

@@ -258,12 +252,12 @@ IMPLEMENT_EXPORT_INIT(wiringPiISR) {
258252
REGISTER_NATIVE_INTERRUPT_HANDLER(61);
259253
REGISTER_NATIVE_INTERRUPT_HANDLER(62);
260254
REGISTER_NATIVE_INTERRUPT_HANDLER(63);
261-
255+
262256
EXPORT_FUNCTION(wiringPiISR);
263257
EXPORT_FUNCTION(wiringPiISRCancel);
264-
258+
265259
EXPORT_CONSTANT_INT(INT_EDGE_FALLING);
266260
EXPORT_CONSTANT_INT(INT_EDGE_RISING);
267261
EXPORT_CONSTANT_INT(INT_EDGE_BOTH);
268262
EXPORT_CONSTANT_INT(INT_EDGE_SETUP);
269-
}
263+
}

0 commit comments

Comments
 (0)