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;
@@ -3533,44 +3530,40 @@ static void EnableDebug(Environment* env) {
3533
3530
3534
3531
// Called from an arbitrary thread.
3535
3532
static void TryStartDebugger () {
3536
- // Call only async signal-safe functions here! Don't retry the exchange,
3537
- // it will deadlock when the thread is interrupted inside a critical section.
3538
- if (auto isolate = node_isolate.exchange (nullptr )) {
3533
+ uv_mutex_lock (&node_isolate_mutex);
3534
+ if (auto isolate = node_isolate) {
3539
3535
v8::Debug::DebugBreak (isolate);
3540
3536
uv_async_send (&dispatch_debug_messages_async);
3541
- CHECK_EQ (nullptr , node_isolate.exchange (isolate));
3542
3537
}
3538
+ uv_mutex_unlock (&node_isolate_mutex);
3543
3539
}
3544
3540
3545
3541
3546
3542
// Called from the main thread.
3547
3543
static void DispatchDebugMessagesAsyncCallback (uv_async_t * handle) {
3548
- // Synchronize with signal handler, see TryStartDebugger.
3549
- Isolate* isolate;
3550
- do {
3551
- isolate = node_isolate.exchange (nullptr );
3552
- } while (isolate == nullptr );
3544
+ uv_mutex_lock (&node_isolate_mutex);
3545
+ if (auto isolate = node_isolate) {
3546
+ if (debugger_running == false ) {
3547
+ fprintf (stderr, " Starting debugger agent.\n " );
3553
3548
3554
- if (debugger_running == false ) {
3555
- fprintf (stderr, " Starting debugger agent.\n " );
3549
+ HandleScope scope (isolate);
3550
+ Environment* env = Environment::GetCurrent (isolate);
3551
+ Context::Scope context_scope (env->context ());
3556
3552
3557
- HandleScope scope (isolate );
3558
- Environment* env = Environment::GetCurrent (isolate );
3559
- Context::Scope context_scope (env-> context ());
3553
+ StartDebug (env, false );
3554
+ EnableDebug (env );
3555
+ }
3560
3556
3561
- StartDebug (env, false );
3562
- EnableDebug (env );
3557
+ Isolate::Scope isolate_scope (isolate );
3558
+ v8::Debug::ProcessDebugMessages ( );
3563
3559
}
3564
-
3565
- Isolate::Scope isolate_scope (isolate);
3566
- v8::Debug::ProcessDebugMessages ();
3567
- CHECK_EQ (nullptr , node_isolate.exchange (isolate));
3560
+ uv_mutex_unlock (&node_isolate_mutex);
3568
3561
}
3569
3562
3570
3563
3571
3564
#ifdef __POSIX__
3572
3565
static void EnableDebugSignalHandler (int signo) {
3573
- TryStartDebugger ( );
3566
+ uv_sem_post (&debug_semaphore );
3574
3567
}
3575
3568
3576
3569
@@ -3609,11 +3602,46 @@ void DebugProcess(const FunctionCallbackInfo<Value>& args) {
3609
3602
}
3610
3603
3611
3604
3605
+ inline void * DebugSignalThreadMain (void * unused) {
3606
+ for (;;) {
3607
+ uv_sem_wait (&debug_semaphore);
3608
+ TryStartDebugger ();
3609
+ }
3610
+ return nullptr ;
3611
+ }
3612
+
3613
+
3612
3614
static int RegisterDebugSignalHandler () {
3613
- // FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
3615
+ // Start a watchdog thread for calling v8::Debug::DebugBreak() because
3616
+ // it's not safe to call directly from the signal handler, it can
3617
+ // deadlock with the thread it interrupts.
3618
+ CHECK_EQ (0 , uv_sem_init (&debug_semaphore, 0 ));
3619
+ pthread_attr_t attr;
3620
+ CHECK_EQ (0 , pthread_attr_init (&attr));
3621
+ // Don't shrink the thread's stack on FreeBSD. Said platform decided to
3622
+ // follow the pthreads specification to the letter rather than in spirit:
3623
+ // https://lists.freebsd.org/pipermail/freebsd-current/2014-March/048885.html
3624
+ #ifndef __FreeBSD__
3625
+ CHECK_EQ (0 , pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN));
3626
+ #endif // __FreeBSD__
3627
+ CHECK_EQ (0 , pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
3628
+ sigset_t sigmask;
3629
+ sigfillset (&sigmask);
3630
+ CHECK_EQ (0 , pthread_sigmask (SIG_SETMASK, &sigmask, &sigmask));
3631
+ pthread_t thread;
3632
+ const int err =
3633
+ pthread_create (&thread, &attr, DebugSignalThreadMain, nullptr );
3634
+ CHECK_EQ (0 , pthread_sigmask (SIG_SETMASK, &sigmask, nullptr ));
3635
+ CHECK_EQ (0 , pthread_attr_destroy (&attr));
3636
+ if (err != 0 ) {
3637
+ fprintf (stderr, " node[%d]: pthread_create: %s\n " , getpid (), strerror (err));
3638
+ fflush (stderr);
3639
+ // Leave SIGUSR1 blocked. We don't install a signal handler,
3640
+ // receiving the signal would terminate the process.
3641
+ return -err;
3642
+ }
3614
3643
RegisterSignalHandler (SIGUSR1, EnableDebugSignalHandler);
3615
3644
// Unblock SIGUSR1. A pending SIGUSR1 signal will now be delivered.
3616
- sigset_t sigmask;
3617
3645
sigemptyset (&sigmask);
3618
3646
sigaddset (&sigmask, SIGUSR1);
3619
3647
CHECK_EQ (0 , pthread_sigmask (SIG_UNBLOCK, &sigmask, nullptr ));
@@ -3855,6 +3883,8 @@ void Init(int* argc,
3855
3883
// Make inherited handles noninheritable.
3856
3884
uv_disable_stdio_inheritance ();
3857
3885
3886
+ CHECK_EQ (0 , uv_mutex_init (&node_isolate_mutex));
3887
+
3858
3888
// init async debug messages dispatching
3859
3889
// Main thread uses uv_default_loop
3860
3890
CHECK_EQ (0 , uv_async_init (uv_default_loop (),
@@ -4141,15 +4171,18 @@ static void StartNodeInstance(void* arg) {
4141
4171
params.code_event_handler = vTune::GetVtuneCodeEventHandler ();
4142
4172
#endif
4143
4173
Isolate* isolate = Isolate::New (params);
4174
+
4175
+ uv_mutex_lock (&node_isolate_mutex);
4176
+ if (instance_data->is_main ()) {
4177
+ CHECK_EQ (node_isolate, nullptr );
4178
+ node_isolate = isolate;
4179
+ }
4180
+ uv_mutex_unlock (&node_isolate_mutex);
4181
+
4144
4182
if (track_heap_objects) {
4145
4183
isolate->GetHeapProfiler ()->StartTrackingHeapObjects (true );
4146
4184
}
4147
4185
4148
- // Fetch a reference to the main isolate, so we have a reference to it
4149
- // even when we need it to access it from another (debugger) thread.
4150
- if (instance_data->is_main ())
4151
- CHECK_EQ (nullptr , node_isolate.exchange (isolate));
4152
-
4153
4186
{
4154
4187
Locker locker (isolate);
4155
4188
Isolate::Scope isolate_scope (isolate);
@@ -4213,10 +4246,10 @@ static void StartNodeInstance(void* arg) {
4213
4246
env = nullptr ;
4214
4247
}
4215
4248
4216
- if (instance_data-> is_main ()) {
4217
- // Synchronize with signal handler, see TryStartDebugger.
4218
- while (isolate != node_isolate. exchange ( nullptr )); // NOLINT
4219
- }
4249
+ uv_mutex_lock (&node_isolate_mutex);
4250
+ if (node_isolate == isolate)
4251
+ node_isolate = nullptr ;
4252
+ uv_mutex_unlock (&node_isolate_mutex);
4220
4253
4221
4254
CHECK_NE (isolate, nullptr );
4222
4255
isolate->Dispose ();
0 commit comments