speeding up Process.detach frequency

J

Joe Van Dyk

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.
 
J

Joe Van Dyk

Answering my own question... Apparently not without modifying Ruby
source.. it seems to be hard coded as once a second.

Would it make sense for it to be user configurable?=20
 
A

Ara.T.Howard

Answering my own question... Apparently not without modifying Ruby
source.. it seems to be hard coded as once a second.

Would it make sense for it to be user configurable?

you might be able to use this:

http://codeforpeople.com/lib/ruby/slave/slave-0.0.0/

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================
 
N

nobu.nokada

Hi,

At Sat, 25 Jun 2005 11:42:03 +0900,
Joe Van Dyk wrote in [ruby-talk:146425]:
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.


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 25 Jun 2005 04:04:39 -0000
@@ -850,9 +850,7 @@ detach_process_watcher(pid_p)
int cpid, status;

- for (;;) {
- cpid = rb_waitpid(*pid_p, &status, WNOHANG);
- if (cpid == -1) return rb_last_status;
- rb_thread_sleep(1);
- }
+ cpid = rb_waitpid(*pid_p, &status, 0);
+ if (cpid == -1) return Qnil;
+ return rb_last_status;
}
 
J

Joe Van Dyk

Hi,
=20
At Sat, 25 Jun 2005 11:42:03 +0900,
Joe Van Dyk wrote in [ruby-talk:146425]:
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.
=20
It seems like a bug of Process.detach. After it received the
termination, it unnecessarily waits for one second again.
=20
=20
Index: process.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
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 25 Jun 2005 04:04:39 -0000
@@ -850,9 +850,7 @@ detach_process_watcher(pid_p)
int cpid, status;
=20
- for (;;) {
- cpid =3D rb_waitpid(*pid_p, &status, WNOHANG);
- if (cpid =3D=3D -1) return rb_last_status;
- rb_thread_sleep(1);
- }
+ cpid =3D rb_waitpid(*pid_p, &status, 0);
+ if (cpid =3D=3D -1) return Qnil;
+ return rb_last_status;
}

Hm, that might work. I'll have to try it on Monday.

Thanks,
Joe
 
N

nobu.nokada

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
}
 
N

nobu.nokada

Hi,

At Sun, 26 Jun 2005 13:39:35 +0900,
Or if it's not enough, a patch to use SIGCHLD.

Sorry, it was incomplete. Following is an additional patch.


diff -U2 eval.c eval.c
--- eval.c 26 Jun 2005 04:27:51 -0000
+++ eval.c 26 Jun 2005 05:01:37 -0000
@@ -10692,4 +10692,5 @@
int need_select = 0;
int select_timeout = 0;
+ int do_pause = 0;

#ifdef HAVE_NATIVETHREAD
@@ -10766,4 +10767,7 @@
}
}
+ if (th->wait_for & WAIT_PID) {
+ do_pause = 1;
+ }
}
END_FOREACH_FROM(curr, th);
@@ -10890,8 +10894,9 @@
/* raise fatal error to main thread */
curr_thread->node = ruby_current_node;
- if (curr->next == curr) {
+ if (do_pause || curr->next == curr) {
TRAP_BEG;
pause();
TRAP_END;
+ if (do_pause) return;
}
FOREACH_THREAD_FROM(curr, th) {
diff -U2 signal.c signal.c
--- signal.c 26 Jun 2005 04:33:30 -0000
+++ signal.c 26 Jun 2005 05:30:16 -0000
@@ -360,4 +360,5 @@
if (handler == SIG_IGN) sigact.sa_flags |= SA_NOCLDWAIT;
#endif
+ sigact.sa_flags |= SA_RESTART;
}
#endif
 
N

nobu.nokada

Hi,

At Sun, 26 Jun 2005 19:28:09 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:146512]:
|> |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().

Isn't it too often for most of the cases?

I don't think it is a too heavy process, though it would not be
a problem if it were less frequent.
|Or if it's not enough, a patch to use SIGCHLD.

I'm not sure if SIGCHLD is available on non-UNIX platforms.

Of course not, but nothing will change on such platforms. And
it would be possible to emulate it, e.g., a watcher native
thread could wake up a ruby thread waiting for a child.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top