From: nobu.nokada@... Date: 2005-06-26T13:39:35+09:00 Subject: Re: speeding up Process.detach frequency Hi, At Sat, 25 Jun 2005 23:05:49 +0900, Yukihiro Matsumoto wrote in [ruby-talk:146448]: > |> Is there any way to speed up Process.detach? The ri documentation for > |> it says that it checks once a second, and I'd like to up that to maybe > |> once every quarter second. > | > |It seems like a bug of Process.detach. After it received the > |termination, it unnecessarily waits for one second again. > > Right. But using rb_waitpid() withouth WNOHANG does busy-wait. It should check periodically once per 0.06sec in rb_thread_polling(). Or if it's not enough, a patch to use SIGCHLD. * eval.c (rb_thread_wait_child, rb_thread_wake_child): wait child process. * process.c (rb_waitpid): ditto. * signal.c (sigchld): use siginfo to wake corresponding threads up. Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.791 diff -U2 -p -r1.791 eval.c --- eval.c 20 Jun 2005 09:59:58 -0000 1.791 +++ eval.c 26 Jun 2005 04:27:51 -0000 @@ -11496,4 +11496,46 @@ rb_thread_stop() } +void +rb_thread_wait_child(pid) + int pid; +{ +#if defined SIGCHLD || defined SIGCLD + curr_thread->status = THREAD_STOPPED; + curr_thread->wait_for = WAIT_PID; + curr_thread->fd = pid; + rb_thread_schedule(); +#else + rb_thread_polling(); +#endif +} + +int +rb_thread_wake_child(pid) + int pid; +{ +#if defined SIGCHLD || defined SIGCLD + int w = Qfalse; + rb_thread_t curr, th; + + curr = curr_thread; + while (curr->status == THREAD_KILLED) { + curr = curr->prev; + } + + FOREACH_THREAD_FROM(curr, th) { + if (th->status != THREAD_STOPPED) continue; + if (th->wait_for != WAIT_PID) continue; + if (pid != -1 && th->fd != pid) continue; + w = Qtrue; + rb_thread_ready(th); + } + END_FOREACH_FROM(curr, th); + if (w && !rb_thread_critical) rb_thread_schedule(); + return w; +#else + return 0; +#endif +} + struct timeval rb_time_timeval(); Index: process.c =================================================================== RCS file: /cvs/ruby/src/ruby/process.c,v retrieving revision 1.131 diff -U2 -p -r1.131 process.c --- process.c 16 May 2005 13:42:59 -0000 1.131 +++ process.c 26 Jun 2005 04:31:08 -0000 @@ -578,26 +578,4 @@ rb_waitpid(pid, st, flags) flags |= WNOHANG; } - - retry: - TRAP_BEG; -#ifdef HAVE_WAITPID - result = waitpid(pid, st, flags); -#else /* HAVE_WAIT4 */ - result = wait4(pid, st, flags, NULL); -#endif - TRAP_END; - if (result < 0) { - if (errno == EINTR) { - rb_thread_polling(); - goto retry; - } - return -1; - } - if (result == 0) { - if (oflags & WNOHANG) return 0; - rb_thread_polling(); - if (rb_thread_alone()) flags = oflags; - goto retry; - } #else /* NO_WAITPID */ if (pid_tbl && st_lookup(pid_tbl, pid, (st_data_t *)st)) { @@ -610,12 +588,19 @@ rb_waitpid(pid, st, flags) rb_raise(rb_eArgError, "can't do waitpid with flags"); } +#endif for (;;) { TRAP_BEG; +#if defined NO_WAITPID result = wait(st); +#elif defined HAVE_WAITPID + result = waitpid(pid, st, flags); +#else /* HAVE_WAIT4 */ + result = wait4(pid, st, flags, NULL); +#endif TRAP_END; if (result < 0) { if (errno == EINTR) { - rb_thread_schedule(); + rb_thread_wait_child(pid); continue; } @@ -625,10 +610,15 @@ rb_waitpid(pid, st, flags) break; } +#ifndef NO_WAITPID + if (oflags & WNOHANG) return 0; + rb_thread_wait_child(pid); + if (rb_thread_alone()) flags = oflags; +#else /* NO_WAITPID */ if (!pid_tbl) pid_tbl = st_init_numtable(); st_insert(pid_tbl, pid, (st_data_t)st); if (!rb_thread_alone()) rb_thread_schedule(); - } #endif + } if (result > 0) { last_status_set(*st, result); Index: signal.c =================================================================== RCS file: /cvs/ruby/src/ruby/signal.c,v retrieving revision 1.61 diff -U2 -p -r1.61 signal.c --- signal.c 12 Jun 2005 16:56:05 -0000 1.61 +++ signal.c 26 Jun 2005 04:33:30 -0000 @@ -30,4 +30,14 @@ #endif +#ifdef SIGCLD +# ifndef SIGCHLD +# define SIGCHLD SIGCLD +# endif +#else +# ifdef SIGCHLD +# define SIGCLD SIGCHLD +# endif +#endif + static struct signals { char *signm; @@ -98,8 +108,4 @@ static struct signals { #ifdef SIGCLD {"CLD", SIGCLD}, -#else -# ifdef SIGCHLD - {"CLD", SIGCHLD}, -# endif #endif #ifdef SIGTTIN @@ -331,7 +337,8 @@ typedef RETSIGTYPE (*sighandler_t)_((int #ifdef POSIX_SIGNAL static sighandler_t -ruby_signal(signum, handler) +ruby_sigaction(signum, handler, flags) int signum; sighandler_t handler; + int flags; { struct sigaction sigact, old; @@ -339,15 +346,28 @@ ruby_signal(signum, handler) rb_trap_accept_nativethreads[signum] = 0; + if (flags & SA_SIGINFO) { + sigact.sa_sigaction = (void (*)_((int, siginfo_t *, void *)))handler; + } + else { + sigact.sa_handler = handler; + } sigact.sa_handler = handler; sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; + sigact.sa_flags = flags; +#ifdef SIGCHLD + if (signum == SIGCHLD || signum == SIGCLD) { #ifdef SA_NOCLDWAIT - if (signum == SIGCHLD && handler == SIG_IGN) - sigact.sa_flags |= SA_NOCLDWAIT; + if (handler == SIG_IGN) sigact.sa_flags |= SA_NOCLDWAIT; +#endif + } #endif sigaction(signum, &sigact, &old); + if (old.sa_flags & SA_SIGINFO) + return (sighandler_t)old.sa_sigaction; return old.sa_handler; } +#define ruby_signal(sig,handler) ruby_sigaction((sig),(handler), 0) + void posix_signal(signum, handler) @@ -536,4 +556,42 @@ sigpipe(sig) #endif +#ifdef SIGCHLD +#ifdef POSIX_SIGNAL +static RETSIGTYPE sigchld _((int, siginfo_t *, void *)); +#else +static RETSIGTYPE sigchld _((int)); +#endif +static RETSIGTYPE +#ifdef POSIX_SIGNAL +sigchld(sig, info, ptr) +#else +sigchld(sig) +#endif + int sig; +#ifdef POSIX_SIGNAL + siginfo_t *info; + void *ptr; +#endif +{ + int pid = -1; + +#ifdef POSIX_SIGNAL + pid = info->si_pid; +#endif +#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL) + ruby_signal(sig, sigchld); +#endif + if (rb_thread_wake_child(pid)) return; + if (ATOMIC_TEST(rb_trap_immediate)) { + IN_MAIN_CONTEXT(signal_exec, sig); + ATOMIC_SET(rb_trap_immediate, 1); + } + else { + ATOMIC_INC(rb_trap_pending); + ATOMIC_INC(trap_pending_list[sig]); + } +} +#endif + void rb_trap_exit() @@ -708,5 +766,10 @@ trap(arg) } } - oldfunc = ruby_signal(sig, func); +#ifdef SIGCHLD + if (sig == SIGCHLD || sig == SIGCLD) + oldfunc = sighandler; + else +#endif + oldfunc = ruby_signal(sig, func); oldcmd = trap_list[sig].cmd; if (!oldcmd) { @@ -882,4 +945,7 @@ init_sigchld(sig) int sig; { +#ifdef POSIX_SIGNAL + ruby_sigaction(sig, (sighandler_t)sigchld, SA_SIGINFO); +#else sighandler_t oldfunc; #ifndef _WIN32 @@ -918,4 +984,5 @@ init_sigchld(sig) trap_last_mask = mask; #endif +#endif } -- Nobu Nakada