77#include < sys/types.h>
88#include < v8-debug.h>
99#include < time.h>
10+ #include < node.h>
11+ #include < uv.h>
1012
1113#ifdef _WIN32
1214#include " ../includes/StackWalker.h"
2022#include < signal.h>
2123#include < stdarg.h>
2224#include < unistd.h>
25+ #include < pthread.h>
2326#endif
2427
2528using namespace v8 ;
@@ -49,6 +52,121 @@ using namespace Nan;
4952
5053#define BUFF_SIZE 128
5154
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+
52170char logPath[BUFF_SIZE];
53171
54172static void buildFileName (char sbuff[BUFF_SIZE], int pid) {
@@ -112,9 +230,17 @@ SEGFAULT_HANDLER {
112230 backtrace_symbols_fd (array, size, STDERR_FD);
113231 #endif
114232
115- // Exit violently
116233 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
118244
119245 #ifdef _WIN32
120246 return EXCEPTION_EXECUTE_HANDLER;
@@ -162,19 +288,31 @@ NAN_METHOD(RegisterHandler) {
162288 // if passed a path, we'll set the log name to whatever is provided
163289 // this will allow users to use the logs in error reporting without redirecting
164290 // 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 ());
169296
170297 // need to do a copy to make sure the string doesn't become a dangling pointer
171298 int len = utf8Value.length ();
172299 len = len > BUFF_SIZE ? BUFF_SIZE : len;
173300
174301 strncpy (logPath, *utf8Value, len);
175302 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+ }
178316 }
179317 }
180318
@@ -185,7 +323,7 @@ NAN_METHOD(RegisterHandler) {
185323 memset (&sa, 0 , sizeof (struct sigaction ));
186324 sigemptyset (&sa.sa_mask );
187325 sa.sa_sigaction = segfault_handler;
188- sa.sa_flags = SA_SIGINFO;
326+ sa.sa_flags = SA_SIGINFO | SA_RESETHAND ;
189327 sigaction (SIGSEGV, &sa, NULL );
190328 #endif
191329}
0 commit comments