I still have some process additions that I'd like to see in the standard 
Ruby process.c (if only because it feels that they should be standard).  
They include the wait-flags, Process.waitall, and now Process.gids/
Process.groups, useful because on many platforms there will be multiple 
groups that a user may belong to.

I believe the work I have done will enable these extensions to work on other 
systems (that is, e.g., ones without getgroups()).  Let me know what you all 
think.  I also made a change for consistency to file.c, to set the NGROUPS 
according to NGROUPS_MAX if possible.  Thanks for your time!

--- file.c.orig	Fri Oct 20 20:21:21 2000
+++ file.c	Fri Oct 20 20:22:11 2000
@@ -390,7 +390,9 @@
 	return Qtrue;
 
 # ifdef HAVE_GETGROUPS
-#  ifndef NGROUPS
+#  ifdef NGROUPS_MAX
+#    define NGROUPS NGROUPS_MAX
+#  else
 #    define NGROUPS 32
 #  endif
     {

--- process.c.orig	Tue Oct 17 14:13:58 2000
+++ process.c	Fri Oct 20 20:32:00 2000
@@ -158,6 +158,30 @@
     data->status = value;
     return ST_DELETE;
 }
+
+struct waitall_data {
+    int pid;
+    int status;
+    VALUE ary;
+}
+
+static int
+waitall_each(key, value, data)
+    int key, value;
+    struct wait_data *data;
+{
+    VALUE pid_status_member;
+
+    if (data->status != -1) return ST_STOP;
+
+    data->pid = key;
+    data->status = value;
+    pid_status_member = rb_ary_new2(2);
+    rb_ary_push(pid_status_member, INT2NUM(key));
+    rb_ary_push(pid_status_member, INT2NUM(value));
+    rb_ary_push(data->ary, pid_status_member);
+    return ST_DELETE;
+}
 #endif
 
 static VALUE
@@ -230,6 +254,135 @@
     return rb_assoc_new(pid, rb_last_status);
 }
 
+static VALUE
+rb_f_waitall()
+{
+    VALUE pid_status_ary, pid_status_member;
+    int pid, state;
+#ifdef NO_WAITPID
+    struct waitall_data data;
+
+    data.ary = pid_status_ary = rb_ary_new();
+    data.status = -1;
+    st_foreach(pid_tbl, waitall_each, &data);
+    if (data.status != -1) {
+	rb_last_status = data.status;
+	return pid_status_ary;
+    }
+
+    for (pid = -1;;) {
+	pid = wait(&state);
+	if (pid == -1) {
+	    if (errno == ECHILD)
+		break;
+            if (errno == EINTR) {
+		rb_thread_schedule();
+		continue;
+	    }
+	    rb_sys_fail(0);
+	}
+	pid_status_member = rb_ary_new2(2);
+	rb_ary_push(pid_status_member, INT2NUM(pid));
+	rb_ary_push(pid_status_member, INT2NUM(state));
+	rb_ary_push(pid_status_ary, pid_status_member);
+    }
+    if (RARRAY(pid_status_ary)->len != 0)
+	rb_last_status = INT2FIX(state);
+#else
+    pid_status_ary = rb_ary_new();
+    for (pid = -1;;) {
+	pid = rb_waitpid(-1, 0, &state);
+	if (pid == -1) {
+	    if (errno == ECHILD)
+		break;
+	    rb_sys_fail(0);
+	}
+	pid_status_member = rb_ary_new2(2);
+	rb_ary_push(pid_status_member, INT2NUM(pid));
+	rb_ary_push(pid_status_member, INT2NUM(state));
+	rb_ary_push(pid_status_ary, pid_status_member);
+    }
+#endif
+    return pid_status_ary;
+}
+
+static VALUE
+rb_f_wifstopped(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    if (WIFSTOPPED(status))
+	return Qtrue;
+    else
+	return Qfalse;
+}
+
+static VALUE
+rb_f_wstopsig(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    return INT2NUM(WSTOPSIG(status));
+}
+
+static VALUE
+rb_f_wifsignaled(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    if (WIFSIGNALED(status))
+	return Qtrue;
+    else
+	return Qfalse;
+}
+
+static VALUE
+rb_f_wtermsig(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    return INT2NUM(WTERMSIG(status));
+}
+
+static VALUE
+rb_f_wifexited(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    if (WIFEXITED(status))
+	return Qtrue;
+    else
+	return Qfalse;
+}
+
+static VALUE
+rb_f_wexitstatus(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    return INT2NUM(WEXITSTATUS(status));
+}
+
+#ifdef WCOREDUMP
+static VALUE
+rb_f_wcoredump(obj, statusnum)
+    VALUE obj, statusnum;
+{
+    int status = NUM2INT(statusnum);
+
+    if (WCOREDUMP(status))
+	return Qtrue;
+    else
+	return Qfalse;
+}
+#endif
+
 char *strtok();
 
 #ifdef HAVE_SETITIMER
@@ -993,6 +1146,33 @@
 }
 
 static VALUE
+proc_getgroups(obj)
+    VALUE obj;
+{
+# ifdef HAVE_GETGROUPS
+#  ifdef NGROUPS_MAX
+#    define NGROUPS NGROUPS_MAX
+#  else
+#    define NGROUPS 32
+#  endif
+    GETGROUPS_T gary[NGROUPS];
+    VALUE groups;
+    int anum, i;
+
+    anum = getgroups(NGROUPS, gary);
+    if (anum == -1)
+	rb_sys_fail(0);
+    groups = rb_ary_new2(anum);
+    for (i = 0; i < anum; i++)
+	rb_ary_push(groups, INT2NUM(gary[i]));
+
+    return groups;
+#  else
+    return rb_ary_new3(1, proc_getgid());
+#  endif
+}
+
+static VALUE
 proc_geteuid(obj)
     VALUE obj;
 {
@@ -1083,8 +1263,18 @@
 #ifndef NT
     rb_define_module_function(rb_mProcess, "wait", proc_wait, 0);
     rb_define_module_function(rb_mProcess, "wait2", proc_wait2, 0);
+    rb_define_module_function(rb_mProcess, "waitall", rb_f_waitall, 0);
     rb_define_module_function(rb_mProcess, "waitpid", proc_waitpid, -1);
     rb_define_module_function(rb_mProcess, "waitpid2", proc_waitpid2, -1);
+    rb_define_module_function(rb_mProcess, "wifstopped", rb_f_wifstopped, 1);
+    rb_define_module_function(rb_mProcess, "wstopsig", rb_f_wstopsig, 1);
+    rb_define_module_function(rb_mProcess, "wifsignaled", rb_f_wifsignaled, 1);
+    rb_define_module_function(rb_mProcess, "wtermsig", rb_f_wtermsig, 1);
+    rb_define_module_function(rb_mProcess, "wifexited", rb_f_wifexited, 1);
+    rb_define_module_function(rb_mProcess, "wexitstatus", rb_f_wexitstatus, 1);
+#ifdef WCOREDUMP
+    rb_define_module_function(rb_mProcess, "wcoredump", rb_f_wcoredump, 1);
+#endif
 
     rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
     rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
@@ -1114,4 +1304,6 @@
     rb_define_module_function(rb_mProcess, "euid=", proc_seteuid, 1);
     rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
     rb_define_module_function(rb_mProcess, "egid=", proc_setegid, 1);
+    rb_define_module_function(rb_mProcess, "gids", proc_getgroups, 0);
+    rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
 }


--
 Brian Fundakowski Feldman           \  FreeBSD: The Power to Serve!  /
 green / FreeBSD.org                    `------------------------------'