FEATURE: warn more loudly about forked environments

In single_threaded mode MiniRacer will behave far more reasonably if platform
is initialized in the master process.

Sadly this is only a partial solution since we will hang at:

```
#0  0x00007fe6f037e34d in pthread_cond_broadcast@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
#1  0x00007fe6ebc15c05 in v8::platform::DelayedTaskQueue::Terminate() ()
   from /home/sam/Source/mini_racer/lib/mini_racer_extension.so
#2  0x00007fe6ebc14dfd in v8::platform::DefaultWorkerThreadsTaskRunner::Terminate() ()
   from /home/sam/Source/mini_racer/lib/mini_racer_extension.so
#3  0x00007fe6ebc13bd6 in v8::platform::DefaultPlatform::~DefaultPlatform() ()
   from /home/sam/Source/mini_racer/lib/mini_racer_extension.so
#4  0x00007fe6ebc13cde in v8::platform::DefaultPlatform::~DefaultPlatform() ()
   from /home/sam/Source/mini_racer/lib/mini_racer_extension.so
#5  0x00007fe6effb0db7 in __run_exit_handlers () from /usr/lib/libc.so.6
```

Likely some more v8 changes are needed to mitigate the heavily forked use
case.
This commit is contained in:
Sam Saffron 2020-09-15 10:28:54 +10:00
parent 94cdb03211
commit 86bdc6d942
No known key found for this signature in database
GPG Key ID: B9606168D2FFD9F5
2 changed files with 38 additions and 3 deletions

View File

@ -156,7 +156,8 @@ static std::mutex platform_lock;
static pthread_attr_t *thread_attr_p;
static pthread_rwlock_t exit_lock = PTHREAD_RWLOCK_INITIALIZER;
static bool ruby_exiting; // guarded by exit_lock
static bool ruby_exiting = false; // guarded by exit_lock
static bool single_threaded = false;
static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
bool platform_already_initialized = false;
@ -169,6 +170,9 @@ static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
platform_lock.lock();
if (current_platform == NULL) {
if (!strcmp(RSTRING_PTR(flag_as_str), "--single_threaded")) {
single_threaded = true;
}
V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), (int)RSTRING_LEN(flag_as_str));
} else {
platform_already_initialized = true;
@ -1221,11 +1225,16 @@ IsolateInfo::~IsolateInfo() {
"it can not be disposed and memory will not be "
"reclaimed till the Ruby process exits.\n");
} else {
if (this->pid != getpid()) {
if (this->pid != getpid() && !single_threaded) {
fprintf(stderr, "WARNING: V8 isolate was forked, "
"it can not be disposed and "
"memory will not be reclaimed "
"till the Ruby process exits.\n");
"till the Ruby process exits.\n"
"It is VERY likely your process will hang.\n"
"If you wish to use v8 in forked environment "
"please ensure the platform is initialized with:\n"
"MiniRacer::Platform.set_flags! :single_threaded\n"
);
} else {
isolate->Dispose();
}
@ -1640,6 +1649,7 @@ static void set_ruby_exiting(VALUE value) {
(void)value;
int res = pthread_rwlock_wrlock(&exit_lock);
ruby_exiting = true;
if (res == 0) {
pthread_rwlock_unlock(&exit_lock);

25
test/test_forking.rb Normal file
View File

@ -0,0 +1,25 @@
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'mini_racer'
MiniRacer::Platform.set_flags! :single_threaded
@ctx = MiniRacer::Context.new
@ctx.eval("var a = 1+1")
def trigger_gc
puts "a"
ctx = MiniRacer::Context.new
puts "b"
ctx.eval("var a = #{('x' * 100000).inspect}")
puts "c"
ctx.eval("a = undefined")
puts "d"
ctx.isolate.low_memory_notification
puts "f"
puts "done triggering"
end
trigger_gc
Process.wait fork { puts @ctx.eval("a"); @ctx.dispose; puts Process.pid; trigger_gc; puts "done #{Process.pid}" }