[前][次][番号順一覧][スレッド一覧]

ruby-changes:51545

From: normal <ko1@a...>
Date: Wed, 27 Jun 2018 20:14:47 +0900 (JST)
Subject: [ruby-changes:51545] normal:r63758 (trunk): hijack SIGCHLD handler for internal use

normal	2018-06-27 12:14:30 +0900 (Wed, 27 Jun 2018)

  New Revision: 63758

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63758

  Log:
    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]

  Modified files:
    trunk/configure.ac
    trunk/ext/pty/pty.c
    trunk/internal.h
    trunk/mjit.c
    trunk/process.c
    trunk/signal.c
    trunk/thread.c
    trunk/thread_pthread.c
    trunk/vm_core.h
Index: configure.ac
===================================================================
--- configure.ac	(revision 63757)
+++ configure.ac	(revision 63758)
@@ -1782,6 +1782,7 @@ AC_CHECK_FUNCS(getsid) https://github.com/ruby/ruby/blob/trunk/configure.ac#L1782
 AC_CHECK_FUNCS(gettimeofday)		# for making ac_cv_func_gettimeofday
 AC_CHECK_FUNCS(getuidx)
 AC_CHECK_FUNCS(gmtime_r)
+AC_CHECK_FUNCS(grantpt)
 AC_CHECK_FUNCS(initgroups)
 AC_CHECK_FUNCS(ioctl)
 AC_CHECK_FUNCS(isfinite)
Index: thread_pthread.c
===================================================================
--- thread_pthread.c	(revision 63757)
+++ thread_pthread.c	(revision 63758)
@@ -1479,6 +1479,13 @@ static void * https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L1479
 thread_timer(void *p)
 {
     rb_global_vm_lock_t *gvl = (rb_global_vm_lock_t *)p;
+#ifdef HAVE_PTHREAD_SIGMASK /* mainly to enable SIGCHLD */
+    {
+        sigset_t mask;
+        sigemptyset(&mask);
+        pthread_sigmask(SIG_SETMASK, &mask, NULL);
+    }
+#endif
 
     if (TT_DEBUG) WRITE_CONST(2, "start timer thread\n");
 
@@ -1764,4 +1771,22 @@ rb_thread_create_mjit_thread(void (*chil https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L1771
     return ret;
 }
 
+#define USE_NATIVE_SLEEP_COND (1)
+
+#if USE_NATIVE_SLEEP_COND
+rb_nativethread_cond_t *
+rb_sleep_cond_get(const rb_execution_context_t *ec)
+{
+    rb_thread_t *th = rb_ec_thread_ptr(ec);
+
+    return &th->native_thread_data.sleep_cond;
+}
+
+void
+rb_sleep_cond_put(rb_nativethread_cond_t *cond)
+{
+    /* no-op */
+}
+#endif /* USE_NATIVE_SLEEP_COND */
+
 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 63757)
+++ vm_core.h	(revision 63758)
@@ -92,6 +92,14 @@ https://github.com/ruby/ruby/blob/trunk/vm_core.h#L92
 
 #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 <stdarg.h>
 #define va_init_list(a,b) va_start((a),(b))
@@ -553,6 +561,9 @@ typedef struct rb_vm_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L561
 #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 https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1572
 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;
 }
Index: thread.c
===================================================================
--- thread.c	(revision 63757)
+++ thread.c	(revision 63758)
@@ -413,6 +413,10 @@ rb_vm_gvl_destroy(rb_vm_t *vm) https://github.com/ruby/ruby/blob/trunk/thread.c#L413
     gvl_release(vm);
     gvl_destroy(vm);
     rb_native_mutex_destroy(&vm->thread_destruct_lock);
+    if (0) {
+        /* may be held by running threads */
+        rb_native_mutex_destroy(&vm->waitpid_lock);
+    }
 }
 
 void
@@ -4131,6 +4135,9 @@ rb_gc_set_stack_end(VALUE **stack_end_p) https://github.com/ruby/ruby/blob/trunk/thread.c#L4135
 #endif
 
 
+/* signal.c */
+void ruby_sigchld_handler(rb_vm_t *);
+
 /*
  *
  */
@@ -4163,6 +4170,7 @@ timer_thread_function(void *arg) https://github.com/ruby/ruby/blob/trunk/thread.c#L4170
     rb_native_mutex_unlock(&vm->thread_destruct_lock);
 
     /* check signal */
+    ruby_sigchld_handler(vm);
     rb_threadptr_check_signal(vm->main_thread);
 
 #if 0
@@ -4247,6 +4255,9 @@ rb_thread_atfork_internal(rb_thread_t *t https://github.com/ruby/ruby/blob/trunk/thread.c#L4255
     }
     rb_vm_living_threads_init(vm);
     rb_vm_living_threads_insert(vm, th);
+
+    /* may be held by MJIT threads in parent */
+    rb_native_mutex_initialize(&vm->waitpid_lock);
     vm->fork_gen++;
 
     vm->sleeper = 0;
@@ -4999,6 +5010,7 @@ Init_Thread(void) https://github.com/ruby/ruby/blob/trunk/thread.c#L5010
 	    gvl_init(th->vm);
 	    gvl_acquire(th->vm, th);
             rb_native_mutex_initialize(&th->vm->thread_destruct_lock);
+            rb_native_mutex_initialize(&th->vm->waitpid_lock);
             rb_native_mutex_initialize(&th->interrupt_lock);
 
 	    th->pending_interrupt_queue = rb_ary_tmp_new(0);
@@ -5302,3 +5314,25 @@ rb_uninterruptible(VALUE (*b_proc)(ANYAR https://github.com/ruby/ruby/blob/trunk/thread.c#L5314
 
     return rb_ensure(b_proc, data, rb_ary_pop, cur_th->pending_interrupt_mask_stack);
 }
+
+#ifndef USE_NATIVE_SLEEP_COND
+#  define USE_NATIVE_SLEEP_COND (0)
+#endif
+
+#if !USE_NATIVE_SLEEP_COND
+rb_nativethread_cond_t *
+rb_sleep_cond_get(const rb_execution_context_t *ec)
+{
+    rb_nativethread_cond_t *cond = ALLOC(rb_nativethread_cond_t);
+    rb_native_cond_initialize(cond);
+
+    return cond;
+}
+
+void
+rb_sleep_cond_put(rb_nativethread_cond_t *cond)
+{
+    rb_native_cond_destroy(cond);
+    xfree(cond);
+}
+#endif /* !USE_NATIVE_SLEEP_COND */
Index: mjit.c
===================================================================
--- mjit.c	(revision 63757)
+++ mjit.c	(revision 63758)
@@ -80,6 +80,7 @@ https://github.com/ruby/ruby/blob/trunk/mjit.c#L80
 #include "constant.h"
 #include "id_table.h"
 #include "ruby_assert.h"
+#include "ruby/thread.h"
 #include "ruby/util.h"
 #include "ruby/version.h"
 
@@ -118,6 +119,10 @@ extern void rb_native_cond_wait(rb_nativ https://github.com/ruby/ruby/blob/trunk/mjit.c#L119
 
 extern int rb_thread_create_mjit_thread(void (*child_hook)(void), void (*worker_func)(void));
 
+/* process.c */
+pid_t ruby_waitpid_locked(rb_vm_t *, rb_pid_t, int *status, int options,
+                          rb_nativethread_cond_t *cond);
+
 #define RB_CONDATTR_CLOCK_MONOTONIC 1
 
 #ifdef _WIN32
@@ -401,22 +406,40 @@ start_process(const char *path, char *co https://github.com/ruby/ruby/blob/trunk/mjit.c#L406
 static int
 exec_process(const char *path, char *const argv[])
 {
-    int stat, exit_code;
+    int stat, exit_code = -2;
     pid_t pid;
+    rb_vm_t *vm = RUBY_SIGCHLD ? GET_VM() : 0;
+    rb_nativethread_cond_t cond;
 
-    pid = start_process(path, argv);
-    if (pid <= 0)
-        return -2;
+    if (vm) {
+        rb_native_cond_initialize(&cond);
+        rb_native_mutex_lock(&vm->waitpid_lock);
+    }
 
-    for (;;) {
-        waitpid(pid, &stat, 0);
-        if (WIFEXITED(stat)) {
-            exit_code = WEXITSTATUS(stat);
-            break;
-        } else if (WIFSIGNALED(stat)) {
-            exit_code = -1;
+    pid = start_process(path, argv);
+    for (;pid > 0;) {
+        pid_t r = vm ? ruby_waitpid_locked(vm, pid, &stat, 0, &cond)
+                     : waitpid(pid, &stat, 0);
+        if (r == -1) {
+            if (errno == EINTR) continue;
+            fprintf(stderr, "[%d] waitpid(%d): %s\n",
+                    getpid(), pid, strerror(errno));
             break;
         }
+        else if (r == pid) {
+            if (WIFEXITED(stat)) {
+                exit_code = WEXITSTATUS(stat);
+                break;
+            } else if (WIFSIGNALED(stat)) {
+                exit_code = -1;
+                break;
+            }
+        }
+    }
+
+    if (vm) {
+        rb_native_mutex_unlock(&vm->waitpid_lock);
+        rb_native_cond_destroy(&cond);
     }
     return exit_code;
 }
@@ -1491,12 +1514,15 @@ mjit_init(struct mjit_options *opts) https://github.com/ruby/ruby/blob/trunk/mjit.c#L1514
 static void
 stop_worker(void)
 {
+    rb_execution_context_t *ec = GET_EC();
+
     stop_worker_p = TRUE;
     while (!worker_stopped) {
         verbose(3, "Sending cancel signal to worker");
         CRITICAL_SECTION_START(3, "in stop_worker");
         rb_native_cond_broadcast(&mjit_worker_wakeup);
         CRITICAL_SECTION_FINISH(3, "in stop_worker");
+        RUBY_VM_CHECK_INTS(ec);
     }
 }
 
Index: process.c
===================================================================
--- process.c	(revision 63757)
+++ process.c	(revision 63758)
@@ -885,12 +885,6 @@ pst_wcoredump(VALUE st) https://github.com/ruby/ruby/blob/trunk/process.c#L885
 #endif
 }
 
-struct waitpid_arg {
-    rb_pid_t pid;
-    int flags;
-    int *st;
-};
-
 static rb_pid_t
 do_waitpid(rb_pid_t pid, int *st, int flags)
 {
@@ -903,45 +897,248 @@ do_waitpid(rb_pid_t pid, int *st, int fl https://github.com/ruby/ruby/blob/trunk/process.c#L897
 #endif
 }
 
+struct waitpid_state {
+    struct list_node wnode;
+    rb_execution_context_t *ec;
+    rb_nativethread_cond_t *cond;
+    rb_pid_t ret;
+    rb_pid_t pid;
+    int status;
+    int options;
+    int errnum;
+};
+
+void rb_native_mutex_lock(rb_nativethread_lock_t *);
+void rb_native_mutex_unlock(rb_nativethread_lock_t *);
+void rb_native_cond_signal(rb_nativethread_cond_t *);
+void rb_native_cond_wait(rb_nativethread_cond_t *, rb_nativethread_lock_t *);
+rb_nativethread_cond_t *rb_sleep_cond_get(const rb_execution_context_t *);
+void rb_sleep_cond_put(rb_nativethread_cond_t *);
+
+static void
+waitpid_notify(struct waitpid_state *w, pid_t ret)
+{
+    w->ret = ret;
+    list_del_init(&w->wnode);
+    rb_native_cond_signal(w->cond);
+}
+
+/* called by both timer thread and main thread */
+
+static void
+waitpid_each(struct list_head *head)
+{
+    struct waitpid_state *w = 0, *next;
+
+    list_for_each_safe(head, w, next, wnode) {
+        pid_t ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+
+        if (!ret) continue;
+        if (ret == -1) w->errnum = errno;
+
+        if (w->ec) { /* rb_waitpid */
+            rb_thread_t *th = rb_ec_thread_ptr(w->ec);
+
+            rb_native_mutex_lock(&th->interrupt_lock);
+            waitpid_notify(w, ret);
+            rb_native_mutex_unlock(&th->interrupt_lock);
+        }
+        else { /* ruby_waitpid_locked */
+            waitpid_notify(w, ret);
+        }
+    }
+}
+
+void
+ruby_waitpid_all(rb_vm_t *vm)
+{
+    rb_native_mutex_lock(&vm->waitpid_lock);
+    waitpid_each(&vm->waiting_pids);
+    if (list_empty(&vm->waiting_pids)) {
+        waitpid_each(&vm->waiting_grps);
+    }
+    rb_native_mutex_unlock(&vm->waitpid_lock);
+}
+
+static void
+waitpid_state_init(struct waitpid_state *w, pid_t pid, int options)
+{
+    w->ret = 0;
+    w->pid = pid;
+    w->options = options;
+}
+
+/*
+ * must be called with vm->waitpid_lock held, this is not interruptible
+ */
+pid_t
+ruby_waitpid_locked(rb_vm_t *vm, rb_pid_t pid, int *status, int options,
+                    rb_nativethread_cond_t *cond)
+{
+    struct waitpid_state w;
+
+    assert(!ruby_thread_has_gvl_p() && "must not have GVL");
+
+    waitpid_state_init(&w, pid, options);
+    if (w.pid > 0 || list_empty(&vm->waiting_pids))
+        w.ret = do_waitpid(w.pid, &w.status, w.options | WNOHANG);
+    if (w.ret) {
+        if (w.ret == -1) w.errnum = errno;
+    }
+    else {
+        w.cond = cond;
+        w.ec = 0;
+        list_add(w.pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w.wnode);
+        do {
+            rb_native_cond_wait(w.cond, &vm->waitpid_lock);
+        } while (!w.ret);
+        list_del(&w.wnode);
+    }
+    if (status) {
+        *status = w.status;
+    }
+    if (w.ret == -1) errno = w.errnum;
+    return w.ret;
+}
+
+static void
+waitpid_wake(void *x)
+{
+    struct waitpid_state *w = x;
+
+    /* th->interrupt_lock is already held by rb_threadptr_interrupt_common */
+    rb_native_cond_signal(w->cond);
+}
+
 static void *
-rb_waitpid_blocking(void *data)
+waitpid_nogvl(void *x)
 {
-    struct waitpid_arg *arg = data;
-    rb_pid_t result = do_waitpid(arg->pid, arg->st, arg->flags);
-    return (void *)(VALUE)result;
+    struct waitpid_state *w = x;
+    rb_thread_t *th = rb_ec_thread_ptr(w->ec);
+
+    rb_native_mutex_lock(&th->interrupt_lock);
+    if (!w->ret) { /* we must check this before waiting */
+        rb_native_cond_wait(w->cond, &th->interrupt_lock);
+    }
+    rb_native_mutex_unlock(&th->interrupt_lock);
+
+    return 0;
 }
 
-static rb_pid_t
-do_waitpid_nonblocking(rb_pid_t pid, int *st, int flags)
+static VALUE
+waitpid_sleep(VALUE x)
 {
-    void *result;
-    struct waitpid_arg arg;
-    arg.pid = pid;
-    arg.st = st;
-    arg.flags = flags;
-    result = rb_thread_call_without_gvl(rb_waitpid_blocking, &arg,
-					RUBY_UBF_PROCESS, 0);
-    return (rb_pid_t)(VALUE)result;
+    struct waitpid_state *w = (struct waitpid_state *)x;
+
+    while (!w->ret) {
+        rb_thread_call_without_gvl(waitpid_nogvl, w, waitpid_wake, w);
+    }
+
+    return Qfalse;
+}
+
+static VALUE
+waitpid_cleanup(VALUE x)
+{
+    struct waitpid_state *w = (struct waitpid_state *)x;
+
+    if (w->ret == 0) {
+        rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
+
+        rb_native_mutex_lock(&vm->waitpid_lock);
+        list_del(&w->wnode);
+        rb_native_mutex_unlock(&vm->waitpid_lock);
+    }
+    rb_sleep_cond_put(w->cond);
+
+    return Qfalse;
+}
+
+static void
+waitpid_wait(struct waitpid_state *w)
+{
+    rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
+
+    /*
+     * Lock here to prevent do_waitpid from stealing work from the
+     * ruby_waitpid_locked done by mjit workers since mjit works
+     * outside of GVL
+     */
+    rb_native_mutex_lock(&vm->waitpid_lock);
+
+    if (w->pid > 0 || list_empty(&vm->waiting_pids))
+        w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+    if (w->ret) {
+        w->cond = 0;
+        if (w->ret == -1) w->errnum = errno;
+    }
+    else if (w->options & WNOHANG) {
+        w->cond = 0;
+
+        /* MJIT must be waiting, but don't tell Ruby callers about it */
+        if (w->pid < 0 && !list_empty(&vm->waiting_pids)) {
+            w->ret = -1;
+            w->errnum = ECHILD;
+        }
+    }
+    else {
+        w->cond = rb_sleep_cond_get(w->ec);
+        /* order matters, favor specified PIDs rather than -1 or 0 */
+        list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode);
+    }
+
+    rb_native_mutex_unlock(&vm->waitpid_lock);
+
+    if (w->cond) {
+        rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
+    }
+}
+
+static void *
+waitpid_blocking_no_SIGCHLD(void *x)
+{
+    struct waitpid_state *w = x;
+
+    w->ret = do_waitpid(w->pid, &w->status, w->options);
+
+    return 0;
+}
+
+static void
+waitpid_no_SIGCHLD(struct waitpid_state *w)
+{
+    if (w->options & WNOHANG) {
+        w->ret = do_waitpid(w->pid, &w->status, w->options);
+    }
+    else {
+        do {
+            rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, &w,
+                                       RUBY_UBF_PROCESS, 0);
+        } while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
+    }
 }
 
 rb_pid_t
 rb_waitpid(rb_pid_t pid, int *st, int flags)
 {
-    rb_pid_t result;
+    struct waitpid_state w;
+
+    waitpid_state_init(&w, pid, flags);
+    w.ec = GET_EC();
 
-    if (flags & WNOHANG) {
-	result = do_waitpid(pid, st, flags);
+    if (RUBY_SIGCHLD) {
+        waitpid_wait(&w);
     }
     else {
-	while ((result = do_waitpid_nonblocking(pid, st, flags)) < 0 &&
-	       (errno == EINTR)) {
-	    RUBY_VM_CHECK_INTS(GET_EC());
-	}
+        waitpid_no_SIGCHLD(&w);
     }
-    if (result > 0) {
-	rb_last_status_set(*st, result);
+
+    if (st) *st = w.status;
+    if (w.ret > 0) {
+	rb_last_status_set(w.status, w.ret);
     }
-    return result;
+    if (w.ret == -1) errno = w.errnum;
+    return w.ret;
 }
 
 
@@ -3595,6 +3792,8 @@ disable_child_handler_fork_child(struct https://github.com/ruby/ruby/blob/trunk/process.c#L3792
 	}
     }
 
+    /* non-Ruby child process, ensure cmake can see SIGCHLD */
+    sigemptyset(&old->sigmask);
     ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL); /* async-signal-safe */
     if (ret != 0) {
         ERRMSG("sigprocmask");
@@ -4086,16 +4285,6 @@ rb_f_system(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L4285
     VALUE execarg_obj;
     struct rb_execarg *eargp;
 
-#if defined(SIGCLD) && !defined(SIGCHLD)
-# define SIGCHLD SIGCLD
-#endif
-
-#ifdef SIGCHLD
-    RETSIGTYPE (*chfunc)(int);
-
-    rb_last_status_clear();
-    chfunc = signal(SIGCHLD, SIG_DFL);
-#endif
     execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
     pid = rb_execarg_spawn(execarg_obj, NULL, 0);
 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
@@ -4106,9 +4295,6 @@ rb_f_system(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L4295
             rb_sys_fail("Another thread waited the process started by system().");
     }
 #endif
-#ifdef SIGCHLD
-    signal(SIGCHLD, chfunc);
-#endif
     TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp);
     if (pid < 0) {
         if (eargp->exception) {
Index: ext/pty/pty.c
===================================================================
--- ext/pty/pty.c	(revision 63757)
+++ ext/pty/pty.c	(revision 63758)
@@ -246,19 +246,13 @@ get_device_once(int *master, int *slave, https://github.com/ruby/ruby/blob/trunk/ext/pty/pty.c#L246
     /* Unix98 PTY */
     int masterfd = -1, slavefd = -1;
     char *slavedevice;
-    struct sigaction dfl, old;
-
-    dfl.sa_handler = SIG_DFL;
-    dfl.sa_flags = 0;
-    sigemptyset(&dfl.sa_mask);
 
 #if defined(__sun) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
     /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set.  [ruby-dev:44688] */
     /* FreeBSD 9.2 or later supports O_CLOEXEC
      * http://www.freebsd.org/cgi/query-pr.cgi?pr=162374 */
     if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
-    if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
-    if (grantpt(masterfd) == -1) goto grantpt_error;
+    if (rb_grantpt(masterfd) == -1) goto error;
     rb_fd_fix_cloexec(masterfd);
 #else
     {
@@ -272,10 +266,8 @@ get_device_once(int *master, int *slave, https://github.com/ruby/ruby/blob/trunk/ext/pty/pty.c#L266
 	if ((masterfd = posix_openpt(flags)) == -1) goto error;
     }
     rb_fd_fix_cloexec(masterfd);
-    if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
-    if (grantpt(masterfd) == -1) goto grantpt_error;
+    if (rb_grantpt(masterfd) == -1) goto error;
 #endif
-    if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
     if (unlockpt(masterfd) == -1) goto error;
     if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
     if (no_mesg(slavedevice, nomesg) == -1) goto error;
@@ -293,8 +285,6 @@ get_device_once(int *master, int *slave, https://github.com/ruby/ruby/blob/trunk/ext/pty/pty.c#L285
     strlcpy(SlaveName, slavedevice, DEVICELEN);
     return 0;
 
-  grantpt_error:
-    sigaction(SIGCHLD, &old, NULL);
   error:
     if (slavefd != -1) close(slavefd);
     if (masterfd != -1) close(masterfd);
@@ -346,21 +336,17 @@ get_device_once(int *master, int *slave, https://github.com/ruby/ruby/blob/trunk/ext/pty/pty.c#L336
 
     extern char *ptsname(int);
     extern int unlockpt(int);
-    extern int grantpt(int);
 
 #if defined(__sun)
     /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set.  [ruby-dev:44688] */
     if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
-    s = signal(SIGCHLD, SIG_DFL);
-    if(grantpt(masterfd) == -1) goto error;
+    if(rb_grantpt(masterfd) == -1) goto error;
     rb_fd_fix_cloexec(masterfd);
 #else
     if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
     rb_update_max_fd(masterfd);
-    s = signal(SIGCHLD, SIG_DFL);
-    if(grantpt(masterfd) == -1) goto error;
+    if(rb_grantpt(masterfd) == -1) goto error;
 #endif
-    signal(SIGCHLD, s);
     if(unlockpt(masterfd) == -1) goto error;
     if((slavedevice = ptsname(masterfd)) == NULL) goto err (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]