7
7
#include < sys/types.h>
8
8
#include < v8-debug.h>
9
9
#include < time.h>
10
+ #include < node.h>
11
+ #include < uv.h>
10
12
11
13
#ifdef _WIN32
12
14
#include " ../includes/StackWalker.h"
20
22
#include < signal.h>
21
23
#include < stdarg.h>
22
24
#include < unistd.h>
25
+ #include < pthread.h>
23
26
#endif
24
27
25
28
using namespace v8 ;
@@ -49,6 +52,121 @@ using namespace Nan;
49
52
50
53
#define BUFF_SIZE 128
51
54
55
+ #ifndef _WIN32
56
+ struct callback_helper {
57
+
58
+ struct callback_args {
59
+
60
+ v8::Persistent<Function, v8::CopyablePersistentTraits<Function> >* callback;
61
+ char **stack;
62
+ size_t stack_size;
63
+ int signo;
64
+ long addr;
65
+ pthread_mutex_t mutex;
66
+ pthread_cond_t cond;
67
+
68
+ callback_args (v8::Persistent<Function, v8::CopyablePersistentTraits<Function> >* callback, void * const * stack, size_t stack_size, int signo, long addr) :
69
+ callback (callback), stack(backtrace_symbols(stack, stack_size)), stack_size(stack_size), signo(signo), addr(addr) {
70
+ pthread_mutex_init (&mutex, NULL );
71
+ pthread_cond_init (&cond, NULL );
72
+ }
73
+
74
+ ~callback_args () {
75
+ free (stack);
76
+ pthread_mutex_destroy (&mutex);
77
+ pthread_cond_destroy (&cond);
78
+ }
79
+ };
80
+
81
+ uv_async_t * handle;
82
+ v8::Persistent<Function, v8::CopyablePersistentTraits<Function> > callback;
83
+
84
+ callback_helper (Handle <Function> func) {
85
+ Isolate* isolate = Isolate::GetCurrent ();
86
+ // set the function reference
87
+ callback.Reset (isolate, func);
88
+
89
+ // create the callback handle
90
+ handle = (uv_async_t *) malloc (sizeof (uv_async_t ));
91
+
92
+ // initialize the handle
93
+ uv_async_init (uv_default_loop (), handle, make_callback);
94
+ }
95
+
96
+ ~callback_helper () {
97
+ // reset the function reference
98
+ callback.Reset ();
99
+
100
+ // close the callback handle
101
+ uv_close ((uv_handle_t *) handle, close_callback);
102
+ }
103
+
104
+ void send (void * const * stack, size_t stack_size, int signo, long addr) {
105
+ // create the callback arguments
106
+ callback_args* args = new callback_args (&callback, stack, stack_size, signo, addr);
107
+
108
+ // set the handle data so these args are accessible to make_callback
109
+ handle->data = (void *) args;
110
+
111
+ // directly execute the callback if we're on the main thread,
112
+ // otherwise have uv send it and await the mutex
113
+ if (Isolate::GetCurrent ()) {
114
+ make_callback (handle);
115
+ } else {
116
+ // lock the callback mutex
117
+ pthread_mutex_lock (&args->mutex );
118
+
119
+ // trigger the async callback
120
+ uv_async_send (handle);
121
+
122
+ // wait for it to finish
123
+ pthread_cond_wait (&args->cond , &args->mutex );
124
+
125
+ // unlock the callback mutex
126
+ pthread_mutex_unlock (&args->mutex );
127
+ }
128
+
129
+ // free the callback args
130
+ delete args;
131
+ }
132
+
133
+ static void close_callback (uv_handle_t * handle) {
134
+ // free the callback handle
135
+ free (handle);
136
+ }
137
+
138
+ static void make_callback (uv_async_t * handle) {
139
+ Isolate* isolate = Isolate::GetCurrent ();
140
+ v8::HandleScope scope (isolate);
141
+
142
+ struct callback_args * args = (struct callback_args *) handle->data ;
143
+
144
+ // lock the mutex
145
+ pthread_mutex_lock (&args->mutex );
146
+
147
+ // build the stack arguments
148
+ Local<Array> argStack = Array::New (isolate, args->stack_size );
149
+ for (size_t i = 0 ; i < args->stack_size ; i++) {
150
+ argStack->Set (i, String::NewFromUtf8 (isolate, args->stack [i]));
151
+ }
152
+
153
+ // collect all callback arguments
154
+ Local<Value> argv[3 ] = {Number::New (isolate, args->signo ), Number::New (isolate, args->addr ), argStack};
155
+
156
+ // execute the callback function on the main threaod
157
+ Local<Function>::New (isolate, *args->callback )->Call (isolate->GetCurrentContext ()->Global (), 3 , argv);
158
+
159
+ // broadcast that we're done with the callback
160
+ pthread_cond_broadcast (&args->cond );
161
+
162
+ // unlock the mutex
163
+ pthread_mutex_unlock (&args->mutex );
164
+ }
165
+ };
166
+
167
+ struct callback_helper * callback;
168
+ #endif
169
+
52
170
char logPath[BUFF_SIZE];
53
171
54
172
static void buildFileName (char sbuff[BUFF_SIZE], int pid) {
@@ -112,9 +230,17 @@ SEGFAULT_HANDLER {
112
230
backtrace_symbols_fd (array, size, STDERR_FD);
113
231
#endif
114
232
115
- // Exit violently
116
233
CLOSE (fd);
117
- exit (-1 );
234
+
235
+ #ifndef _WIN32
236
+ if (callback) {
237
+ // execute the callback and wait until it has completed
238
+ callback->send (array, size, si->si_signo , (long )si->si_addr );
239
+
240
+ // release the callback
241
+ delete callback;
242
+ }
243
+ #endif
118
244
119
245
#ifdef _WIN32
120
246
return EXCEPTION_EXECUTE_HANDLER;
@@ -162,19 +288,31 @@ NAN_METHOD(RegisterHandler) {
162
288
// if passed a path, we'll set the log name to whatever is provided
163
289
// this will allow users to use the logs in error reporting without redirecting
164
290
// sdterr
165
- logPath[0 ] = ' \0 ' ;
166
- if (info.Length () == 1 ) {
167
- if (info[0 ]->IsString ()) {
168
- v8::String::Utf8Value utf8Value (info[0 ]->ToString ());
291
+
292
+ if (info.Length () > 0 ) {
293
+ for (int i = 0 ; i < info.Length (); i++) {
294
+ if (info[i]->IsString ()) {
295
+ String::Utf8Value utf8Value (info[i]->ToString ());
169
296
170
297
// need to do a copy to make sure the string doesn't become a dangling pointer
171
298
int len = utf8Value.length ();
172
299
len = len > BUFF_SIZE ? BUFF_SIZE : len;
173
300
174
301
strncpy (logPath, *utf8Value, len);
175
302
logPath[127 ] = ' \0 ' ;
176
- } else {
177
- return ThrowError (" First argument must be a string." );
303
+
304
+ #ifndef _WIN32
305
+ } else if (info[i]->IsFunction ()) {
306
+ if (callback) {
307
+ // release previous callback
308
+ delete callback;
309
+ }
310
+
311
+ // create the new callback object
312
+ callback = new callback_helper (Handle <Function>::Cast (info[i]));
313
+ #endif
314
+
315
+ }
178
316
}
179
317
}
180
318
@@ -185,7 +323,7 @@ NAN_METHOD(RegisterHandler) {
185
323
memset (&sa, 0 , sizeof (struct sigaction ));
186
324
sigemptyset (&sa.sa_mask );
187
325
sa.sa_sigaction = segfault_handler;
188
- sa.sa_flags = SA_SIGINFO;
326
+ sa.sa_flags = SA_SIGINFO | SA_RESETHAND ;
189
327
sigaction (SIGSEGV, &sa, NULL );
190
328
#endif
191
329
}
0 commit comments