[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

speeding up Process.detach frequency

Joe Van Dyk

6/25/2005 2:42:00 AM

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.


7 Answers

Joe Van Dyk

6/25/2005 3:12:00 AM

0

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?

On 6/24/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> 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.
>


Ara.T.Howard

6/25/2005 4:02:00 AM

0

nobu.nokada

6/25/2005 4:15:00 AM

0

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



--
Nobu Nakada


Joe Van Dyk

6/25/2005 4:33:00 AM

0

On 6/24/05, nobu.nokada@softhome.net <nobu.nokada@softhome.net> wrote:
> 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;
> }

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

Thanks,
Joe


nobu.nokada

6/26/2005 4:40:00 AM

0

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


nobu.nokada

6/26/2005 5:38:00 AM

0

Hi,

At Sun, 26 Jun 2005 13:39:35 +0900,
nobu.nokada@softhome.net wrote in [ruby-talk:146500]:
> 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


--
Nobu Nakada


nobu.nokada

6/26/2005 1:23:00 PM

0

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.

--
Nobu Nakada