From 054a412d540e7ed2de63d68da753f585ea6616c3 Mon Sep 17 00:00:00 2001 From: normal Date: Wed, 27 Jun 2018 03:14:30 +0000 Subject: hijack SIGCHLD handler for internal use Use a global SIGCHLD handler to guard all callers of rb_waitpid. To work safely with multi-threaded programs, we introduce a VM-wide waitpid_lock to be acquired BEFORE fork/vfork spawns the process. This is to be combined with the new ruby_waitpid_locked function used by mjit.c in a non-Ruby thread. Ruby-level SIGCHLD handlers registered with Signal.trap(:CHLD) continues to work as before and there should be no regressions in any existing use cases. Splitting the wait queues for PID > 0 and groups (PID <= 0) ensures we favor PID > 0 callers. The disabling of SIGCHLD in rb_f_system is longer necessary, as we use deferred signal handling and no longer make ANY blocking waitpid syscalls in other threads which could "beat" the waitpid call made by rb_f_system. We prevent SIGCHLD from firing in normal Ruby Threads and only enable it in the timer-thread, to prevent spurious wakeups from in test/-ext-/gvl/test_last_thread.rb with MJIT enabled. I've tried to guard as much of the code for RUBY_SIGCHLD==0 using C "if" statements rather than CPP "#if" so to reduce the likelyhood of portability problems as the compiler will see more code. We also work to suppress false-positives from Process.wait(-1, Process::WNOHANG) to quiets warnings from spec/ruby/core/process/wait2_spec.rb with MJIT enabled. Lastly, we must implement rb_grantpt for ext/pty. We need a MJIT-compatible way of supporting grantpt(3) which may spawn the `pt_chown' binary and call waitpid(2) on it. [ruby-core:87605] [Ruby trunk Bug#14867] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63758 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_core.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'vm_core.h') diff --git a/vm_core.h b/vm_core.h index ee151195d5..bdbe87287b 100644 --- a/vm_core.h +++ b/vm_core.h @@ -92,6 +92,14 @@ #define RUBY_NSIG NSIG +#if defined(SIGCLD) +# define RUBY_SIGCHLD (SIGCLD) +#elif defined(SIGCHLD) +# define RUBY_SIGCHLD (SIGCHLD) +#else +# define RUBY_SIGCHLD (0) +#endif + #ifdef HAVE_STDARG_PROTOTYPES #include #define va_init_list(a,b) va_start((a),(b)) @@ -553,6 +561,9 @@ typedef struct rb_vm_struct { #endif rb_serial_t fork_gen; + rb_nativethread_lock_t waitpid_lock; + struct list_head waiting_pids; /* PID > 0: <=> struct waitpid_state */ + struct list_head waiting_grps; /* PID <= 0: <=> struct waitpid_state */ struct list_head waiting_fds; /* <=> struct waiting_fd */ struct list_head living_threads; VALUE thgroup_default; @@ -1561,6 +1572,8 @@ static inline void rb_vm_living_threads_init(rb_vm_t *vm) { list_head_init(&vm->waiting_fds); + list_head_init(&vm->waiting_pids); + list_head_init(&vm->waiting_grps); list_head_init(&vm->living_threads); vm->living_thread_num = 0; } -- cgit v1.2.3