Possible bug in rb_detach_process()

e$B5WJ]$G$9!#e(B

waitpid
e$B4X78$G$A$i$[$i%=!<%9$r8+$F$$$?$N$G$9$,!"0J2<$NItJ,$OLdBj$G$O$Je(B
e$B$$$G$7$g$&$+!)e(B

static VALUE
detach_process_watcher(int *pid_p)
{
rb_pid_t cpid;
int status;

for (;;) {
    cpid = rb_waitpid(*pid_p, &status, WNOHANG);
    if (cpid != 0) return rb_last_status_get();
    rb_thread_sleep(1);
}

}

VALUE
rb_detach_process(rb_pid_t pid)
{
return rb_thread_create(detach_process_watcher, (void*)&pid);
}

detach_process_watcher() e$B$KEO$5$l$k0z?t$O!"e(Brb_detach_process
e$B$N%9%l%Ce(B
e$B%I$N%9%?%C%/>e$NCM$K$J$C$F$$$^$9!#e(Brb_waitpid()
e$B$,<B9T$5$l$kA0$Ke(B
rb_detach_process
e$B$N%9%l%C%I$,F0$$$F%9%?%C%/>e$NCM$,=q$-JQ$o$C$?$i!"e(B
rb_waitpid() e$B$KEO$5$l$ke(B pid e$B$O$o$1$N$o$+$i$J$$CM$K$J$j$^$9!#e(B

e$B@5$7$/$O$3$&!)e(B

static VALUE
detach_process_watcher(void *arg) <- int *pid_p e$B$re(B void arg
e$B$Ke(B
{
rb_pid_t pid = (int)arg; <- void
e$B$re(B rb_pid_t
e$B$KLa$9!#e(B
rb_pid_t cpid;
int status;

for (;;) {
    cpid = rb_waitpid(pid, &status, WNOHANG);  <- *pid_p e$B$re(B 

pid e$B$Ke(B
if (cpid != 0) return rb_last_status_get();
rb_thread_sleep(1);
}
}

VALUE
rb_detach_process(rb_pid_t pid)
{
return rb_thread_create(detach_process_watcher, (void*)pid); <- &pid
e$B$re(B pid e$B$Ke(B
}

e$B$J$+$@$G$9!#e(B

At Sat, 17 Mar 2007 18:36:07 +0900,
KUBO Takehiro wrote in [ruby-dev:30618]:

detach_process_watcher() e$B$KEO$5$l$k0z?t$O!"e(Brb_detach_process e$B$N%9%l%Ce(B
e$B%I$N%9%?%C%/>e$NCM$K$J$C$F$$$^$9!#e(Brb_waitpid() e$B$,<B9T$5$l$kA0$Ke(B
rb_detach_process e$B$N%9%l%C%I$,F0$$$F%9%?%C%/>e$NCM$,=q$-JQ$o$C$?$i!"e(B
rb_waitpid() e$B$KEO$5$l$ke(B pid e$B$O$o$1$N$o$+$i$J$$CM$K$J$j$^$9!#e(B

e$B$?$7$+$K!#e(B

    cpid = rb_waitpid(pid, &status, WNOHANG);  <- *pid_p e$B$re(B pid e$B$Ke(B
    if (cpid != 0) return rb_last_status_get();
    rb_thread_sleep(1);

1.9e$B$G$Oe(Bpollinge$B$OITMW$K$J$C$?$O$:$G$9!#e(B

e$B$3$N:]$J$N$G!"e(B1.8e$B$G$be(Bwatche$B%9%l%C%I$+$ie(Bexit
statuse$B$r$+$($9$h$&$Ke(B
e$B$7$^$;$s$+!#e(B

  • process.c (detach_process_watcher): should not pass the pointer
    to an auto variable to the thread to be created. pointed and
    fix by KUBO Takehiro [ruby-dev:30618]

  • process.c (detach_process_watcher): now returns the exit status
    of the detached process.

Index: trunk/process.c

— trunk/process.c (revision 12102)
+++ trunk/process.c (working copy)
@@ -861,14 +861,13 @@ proc_waitall(void)

static VALUE
-detach_process_watcher(int *pid_p)
+detach_process_watcher(void *arg)
{

  • rb_pid_t cpid;
  • rb_pid_t cpid, pid = (rb_pid_t)arg;
    int status;
  • for (;:wink: {
  • cpid = rb_waitpid(*pid_p, &status, WNOHANG);
  • if (cpid != 0) return rb_last_status_get();
  • rb_thread_sleep(1);
  • while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
  • /* wait while alive */
    }
  • return rb_last_status_get();
    }

@@ -876,5 +875,5 @@ VALUE
rb_detach_process(rb_pid_t pid)
{

  • return rb_thread_create(detach_process_watcher, (void*)&pid);
  • return rb_thread_create(detach_process_watcher, (void*)pid);
    }

@@ -892,6 +891,5 @@ rb_detach_process(rb_pid_t pid)

  • process pid when it terminates. Use detach
  • only when you do not intent to explicitly wait for the child to
    • terminate. detach only checks the status
    • periodically (currently once each second).
    • terminate.
    • The waiting thread returns the exit status of the detached process
      Index: stable/process.c
      ===================================================================
      — stable/process.c (revision 12102)
      +++ stable/process.c (working copy)
      @@ -839,14 +839,13 @@ proc_waitall()

static VALUE
-detach_process_watcher(pid_p)

  • int *pid_p;
    +detach_process_watcher(arg)
  • void *arg;
    {
  • int cpid, status;
  • int pid = (int)arg, status;
  • for (;:wink: {
  • cpid = rb_waitpid(*pid_p, &status, WNOHANG);
  • if (cpid != 0) return Qnil;
  • while (rb_waitpid(pid, &status, WNOHANG) == 0) {
    rb_thread_sleep(1);
    }
  • return rb_last_status;
    }

@@ -855,5 +854,5 @@ rb_detach_process(pid)
int pid;
{

  • return rb_thread_create(detach_process_watcher, (void*)&pid);
  • return rb_thread_create(detach_process_watcher, (void*)pid);
    }

@@ -874,4 +873,9 @@ rb_detach_process(pid)

  • periodically (currently once each second).
    • The waiting thread returns the exit status of the detached process
    • when it terminates, so you can use Thread#join to
    • know the result. If specified pid is not a valid child process
    • ID, the thread returns +nil+ immediately.
    • In this first example, we don’t reap the first child process, so
    • it appears as a zombie in the process status display.