nobu.nokada
6/26/2005 4:40:00 AM
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