73
73
#define umask _umask
74
74
typedef int mode_t ;
75
75
#else
76
+ #include < pthread.h>
76
77
#include < sys/resource.h> // getrlimit, setrlimit
77
78
#include < unistd.h> // setuid, getuid
78
79
#endif
@@ -89,14 +90,6 @@ typedef int mode_t;
89
90
extern char **environ;
90
91
#endif
91
92
92
- #ifdef __APPLE__
93
- #include " atomic-polyfill.h" // NOLINT(build/include_order)
94
- namespace node { template <typename T> using atomic = nonstd::atomic<T>; }
95
- #else
96
- #include < atomic>
97
- namespace node { template <typename T> using atomic = std::atomic<T>; }
98
- #endif
99
-
100
93
namespace node {
101
94
102
95
using v8::Array;
@@ -166,9 +159,13 @@ static double prog_start_time;
166
159
static bool debugger_running;
167
160
static uv_async_t dispatch_debug_messages_async;
168
161
169
- static node::atomic<Isolate*> node_isolate;
162
+ static uv_mutex_t node_isolate_mutex;
163
+ static v8::Isolate* node_isolate;
170
164
static v8::Platform* default_platform;
171
165
166
+ #ifdef __POSIX__
167
+ static uv_sem_t debug_semaphore;
168
+ #endif
172
169
173
170
static void PrintErrorString (const char * format, ...) {
174
171
va_list ap;
@@ -3538,44 +3535,40 @@ static void EnableDebug(Environment* env) {
3538
3535
3539
3536
// Called from an arbitrary thread.
3540
3537
static void TryStartDebugger () {
3541
- // Call only async signal-safe functions here! Don't retry the exchange,
3542
- // it will deadlock when the thread is interrupted inside a critical section.
3543
- if (auto isolate = node_isolate.exchange (nullptr )) {
3538
+ uv_mutex_lock (&node_isolate_mutex);
3539
+ if (auto isolate = node_isolate) {
3544
3540
v8::Debug::DebugBreak (isolate);
3545
3541
uv_async_send (&dispatch_debug_messages_async);
3546
- CHECK_EQ (nullptr , node_isolate.exchange (isolate));
3547
3542
}
3543
+ uv_mutex_unlock (&node_isolate_mutex);
3548
3544
}
3549
3545
3550
3546
3551
3547
// Called from the main thread.
3552
3548
static void DispatchDebugMessagesAsyncCallback (uv_async_t * handle) {
3553
- // Synchronize with signal handler, see TryStartDebugger.
3554
- Isolate* isolate;
3555
- do {
3556
- isolate = node_isolate.exchange (nullptr );
3557
- } while (isolate == nullptr );
3549
+ uv_mutex_lock (&node_isolate_mutex);
3550
+ if (auto isolate = node_isolate) {
3551
+ if (debugger_running == false ) {
3552
+ fprintf (stderr, " Starting debugger agent.\n " );
3558
3553
3559
- if (debugger_running == false ) {
3560
- fprintf (stderr, " Starting debugger agent.\n " );
3554
+ HandleScope scope (isolate);
3555
+ Environment* env = Environment::GetCurrent (isolate);
3556
+ Context::Scope context_scope (env->context ());
3561
3557
3562
- HandleScope scope (isolate );
3563
- Environment* env = Environment::GetCurrent (isolate );
3564
- Context::Scope context_scope (env-> context ());
3558
+ StartDebug (env, false );
3559
+ EnableDebug (env );
3560
+ }
3565
3561
3566
- StartDebug (env, false );
3567
- EnableDebug (env );
3562
+ Isolate::Scope isolate_scope (isolate );
3563
+ v8::Debug::ProcessDebugMessages ( );
3568
3564
}
3569
-
3570
- Isolate::Scope isolate_scope (isolate);
3571
- v8::Debug::ProcessDebugMessages ();
3572
- CHECK_EQ (nullptr , node_isolate.exchange (isolate));
3565
+ uv_mutex_unlock (&node_isolate_mutex);
3573
3566
}
3574
3567
3575
3568
3576
3569
#ifdef __POSIX__
3577
3570
static void EnableDebugSignalHandler (int signo) {
3578
- TryStartDebugger ( );
3571
+ uv_sem_post (&debug_semaphore );
3579
3572
}
3580
3573
3581
3574
@@ -3614,11 +3607,46 @@ void DebugProcess(const FunctionCallbackInfo<Value>& args) {
3614
3607
}
3615
3608
3616
3609
3610
+ inline void * DebugSignalThreadMain (void * unused) {
3611
+ for (;;) {
3612
+ uv_sem_wait (&debug_semaphore);
3613
+ TryStartDebugger ();
3614
+ }
3615
+ return nullptr ;
3616
+ }
3617
+
3618
+
3617
3619
static int RegisterDebugSignalHandler () {
3618
- // FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
3620
+ // Start a watchdog thread for calling v8::Debug::DebugBreak() because
3621
+ // it's not safe to call directly from the signal handler, it can
3622
+ // deadlock with the thread it interrupts.
3623
+ CHECK_EQ (0 , uv_sem_init (&debug_semaphore, 0 ));
3624
+ pthread_attr_t attr;
3625
+ CHECK_EQ (0 , pthread_attr_init (&attr));
3626
+ // Don't shrink the thread's stack on FreeBSD. Said platform decided to
3627
+ // follow the pthreads specification to the letter rather than in spirit:
3628
+ // https://lists.freebsd.org/pipermail/freebsd-current/2014-March/048885.html
3629
+ #ifndef __FreeBSD__
3630
+ CHECK_EQ (0 , pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN));
3631
+ #endif // __FreeBSD__
3632
+ CHECK_EQ (0 , pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
3633
+ sigset_t sigmask;
3634
+ sigfillset (&sigmask);
3635
+ CHECK_EQ (0 , pthread_sigmask (SIG_SETMASK, &sigmask, &sigmask));
3636
+ pthread_t thread;
3637
+ const int err =
3638
+ pthread_create (&thread, &attr, DebugSignalThreadMain, nullptr );
3639
+ CHECK_EQ (0 , pthread_sigmask (SIG_SETMASK, &sigmask, nullptr ));
3640
+ CHECK_EQ (0 , pthread_attr_destroy (&attr));
3641
+ if (err != 0 ) {
3642
+ fprintf (stderr, " node[%d]: pthread_create: %s\n " , getpid (), strerror (err));
3643
+ fflush (stderr);
3644
+ // Leave SIGUSR1 blocked. We don't install a signal handler,
3645
+ // receiving the signal would terminate the process.
3646
+ return -err;
3647
+ }
3619
3648
RegisterSignalHandler (SIGUSR1, EnableDebugSignalHandler);
3620
3649
// Unblock SIGUSR1. A pending SIGUSR1 signal will now be delivered.
3621
- sigset_t sigmask;
3622
3650
sigemptyset (&sigmask);
3623
3651
sigaddset (&sigmask, SIGUSR1);
3624
3652
CHECK_EQ (0 , pthread_sigmask (SIG_UNBLOCK, &sigmask, nullptr ));
@@ -3860,6 +3888,8 @@ void Init(int* argc,
3860
3888
// Make inherited handles noninheritable.
3861
3889
uv_disable_stdio_inheritance ();
3862
3890
3891
+ CHECK_EQ (0 , uv_mutex_init (&node_isolate_mutex));
3892
+
3863
3893
// init async debug messages dispatching
3864
3894
// Main thread uses uv_default_loop
3865
3895
CHECK_EQ (0 , uv_async_init (uv_default_loop (),
@@ -4146,15 +4176,18 @@ static void StartNodeInstance(void* arg) {
4146
4176
params.code_event_handler = vTune::GetVtuneCodeEventHandler ();
4147
4177
#endif
4148
4178
Isolate* isolate = Isolate::New (params);
4179
+
4180
+ uv_mutex_lock (&node_isolate_mutex);
4181
+ if (instance_data->is_main ()) {
4182
+ CHECK_EQ (node_isolate, nullptr );
4183
+ node_isolate = isolate;
4184
+ }
4185
+ uv_mutex_unlock (&node_isolate_mutex);
4186
+
4149
4187
if (track_heap_objects) {
4150
4188
isolate->GetHeapProfiler ()->StartTrackingHeapObjects (true );
4151
4189
}
4152
4190
4153
- // Fetch a reference to the main isolate, so we have a reference to it
4154
- // even when we need it to access it from another (debugger) thread.
4155
- if (instance_data->is_main ())
4156
- CHECK_EQ (nullptr , node_isolate.exchange (isolate));
4157
-
4158
4191
{
4159
4192
Locker locker (isolate);
4160
4193
Isolate::Scope isolate_scope (isolate);
@@ -4218,10 +4251,10 @@ static void StartNodeInstance(void* arg) {
4218
4251
env = nullptr ;
4219
4252
}
4220
4253
4221
- if (instance_data-> is_main ()) {
4222
- // Synchronize with signal handler, see TryStartDebugger.
4223
- while (isolate != node_isolate. exchange ( nullptr )); // NOLINT
4224
- }
4254
+ uv_mutex_lock (&node_isolate_mutex);
4255
+ if (node_isolate == isolate)
4256
+ node_isolate = nullptr ;
4257
+ uv_mutex_unlock (&node_isolate_mutex);
4225
4258
4226
4259
CHECK_NE (isolate, nullptr );
4227
4260
isolate->Dispose ();
0 commit comments