This is the mail archive of the
frysk@sources.redhat.com
mailing list for the frysk project.
Re: ForkedProcess (Was: Kill and refresh)
Hi,
On Fri, 2006-08-04 at 14:11 +0200, Mark Wielaard wrote:
> > - since it is only intended for testing and testing fork, can this live
> > in TestLib - keeps frysk.sys's interfaces as close as possible to the
> > underlying mechanism?
>
> Can do. Will move it to TestLib. It was just so similar to the rest of
> the Fork class that it seemed natural to put it there.
This proved more difficult than I thought. TestLib uses junit and we
would need cni headers for that. I couldn't figure out an easy way to
generate those in the fryks-imports and then use those inside
frysk-proc. So I created a separate package private test utility class
in frysk.proc for those tests that need it. If you rather have it in
TestLib itself please do file a bug report and assign it to me and I
will have another look at the build-magic needed.
The usage of Errno outside the frysk.sys package is also a bit
confusing. I ended up creating a subclass to be able to throw. If there
is a better mechanism for this please do let me know.
2006-08-15 Mark Wielaard <mark@klomp.org>
* ForkTestLib.java: New file.
* cni/ForkTestLib.cxx: Likewise.
Committed as attached.
Cheers,
Mark
Index: frysk/proc/ForkTestLib.java
===================================================================
RCS file: frysk/proc/ForkTestLib.java
diff -N frysk/proc/ForkTestLib.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ frysk/proc/ForkTestLib.java 15 Aug 2006 13:06:24 -0000
@@ -0,0 +1,144 @@
+// This file is part of the program FRYSK.
+//
+// Copyright 2006, Red Hat Inc.
+//
+// FRYSK is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// FRYSK is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with FRYSK; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// In addition, as a special exception, Red Hat, Inc. gives You the
+// additional right to link the code of FRYSK with code not covered
+// under the GNU General Public License ("Non-GPL Code") and to
+// distribute linked combinations including the two, subject to the
+// limitations in this paragraph. Non-GPL Code permitted under this
+// exception must only link to the code of FRYSK through those well
+// defined interfaces identified in the file named EXCEPTION found in
+// the source code files (the "Approved Interfaces"). The files of
+// Non-GPL Code may instantiate templates or use macros or inline
+// functions from the Approved Interfaces without causing the
+// resulting work to be covered by the GNU General Public
+// License. Only Red Hat, Inc. may make changes or additions to the
+// list of Approved Interfaces. You must obey the GNU General Public
+// License in all respects for all of the FRYSK code and other code
+// used in conjunction with FRYSK except the Non-GPL Code covered by
+// this exception. If you modify this file, you may extend this
+// exception to your version of the file, but you are not obligated to
+// do so. If you do not wish to provide this exception without
+// modification, you must delete this exception statement from your
+// version and license this file solely under the GPL without
+// exception.
+
+package frysk.proc;
+
+import frysk.sys.Errno;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Utility class for creating a forked process.
+ */
+class ForkTestLib
+{
+ /**
+ * Returned by the fork() method to supply the process id an
+ * InputStream and an OutputStream for communicating with the newly
+ * created process.
+ */
+ public static final class ForkedProcess
+ {
+ public final int pid;
+ public final InputStream in;
+ public final OutputStream out;
+
+ /* Package private contructor used by fork(). */
+ ForkedProcess(int pid, InputStream in, OutputStream out)
+ {
+ this.pid = pid;
+ this.in = in;
+ this.out = out;
+ }
+ }
+
+ /**
+ * Package private InputStream subclass created by fork(). Reads
+ * bytes from the stdout of the newly created process.
+ */
+ static final class ForkedInputStream extends InputStream
+ {
+ final int fd;
+
+ ForkedInputStream(int fd)
+ {
+ this.fd = fd;
+ }
+
+ public native int read() throws IOException;
+ public native int read(byte[] buf, int off, int len) throws IOException;
+ }
+
+ /**
+ * Package private OutputStream subclass created by fork(). Writes
+ * bytes to the stdin of the newly created process.
+ */
+ static final class ForkedOutputStream extends OutputStream
+ {
+ final int fd;
+
+ ForkedOutputStream(int fd)
+ {
+ this.fd = fd;
+ }
+
+ public native void write(int i) throws IOException;
+ }
+
+ /**
+ * Creates a child process running ARGV[0] with arguments. Returns
+ * the pid, InputStream and OutputStream that can be used to
+ * communicate with the process. Unlike Runtime.exec() this will not
+ * setup any new Threads or try to reap the process by waiting on
+ * signals.
+ */
+ public static native ForkedProcess fork(String[] argv);
+
+ /**
+ * For use in the cni code when an unexpected errno is encountered.
+ */
+ static void throwErrno(int errno, String msg) throws Errno
+ {
+ // We cannot actually insert the original errno, nor can
+ // we use Errno.throwErrno() to get an appropriate subclass :{
+ // We actually need to subclass Errno for our own use.
+ throw new ForkedErrno(errno, msg);
+ }
+
+ static class ForkedErrno extends Errno
+ {
+ // Fake one to keep the ecj warning check pass happy.
+ private static final long serialVersionUID = 1;
+
+ private final int errno;
+
+ ForkedErrno(int errno, String msg)
+ {
+ super(msg);
+ this.errno = errno;
+ }
+
+ public String toString()
+ {
+ return super.toString() + " (" + errno + ")";
+ }
+ }
+}
Index: frysk/proc/cni/ForkTestLib.cxx
===================================================================
RCS file: frysk/proc/cni/ForkTestLib.cxx
diff -N frysk/proc/cni/ForkTestLib.cxx
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ frysk/proc/cni/ForkTestLib.cxx 15 Aug 2006 13:06:24 -0000
@@ -0,0 +1,151 @@
+// This file is part of the program FRYSK.
+//
+// Copyright 2006 Red Hat Inc.
+//
+// FRYSK is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// FRYSK is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with FRYSK; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// In addition, as a special exception, Red Hat, Inc. gives You the
+// additional right to link the code of FRYSK with code not covered
+// under the GNU General Public License ("Non-GPL Code") and to
+// distribute linked combinations including the two, subject to the
+// limitations in this paragraph. Non-GPL Code permitted under this
+// exception must only link to the code of FRYSK through those well
+// defined interfaces identified in the file named EXCEPTION found in
+// the source code files (the "Approved Interfaces"). The files of
+// Non-GPL Code may instantiate templates or use macros or inline
+// functions from the Approved Interfaces without causing the
+// resulting work to be covered by the GNU General Public
+// License. Only Red Hat, Inc. may make changes or additions to the
+// list of Approved Interfaces. You must obey the GNU General Public
+// License in all respects for all of the FRYSK code and other code
+// used in conjunction with FRYSK except the Non-GPL Code covered by
+// this exception. If you modify this file, you may extend this
+// exception to your version of the file, but you are not obligated to
+// do so. If you do not wish to provide this exception without
+// modification, you must delete this exception statement from your
+// version and license this file solely under the GPL without
+// exception.
+
+#include <stdio.h>
+#include <alloca.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <gcj/cni.h>
+
+#include "frysk/proc/ForkTestLib.h"
+#include "frysk/proc/ForkTestLib$ForkedInputStream.h"
+#include "frysk/proc/ForkTestLib$ForkedOutputStream.h"
+#include "frysk/proc/ForkTestLib$ForkedProcess.h"
+
+#include <java/io/IOException.h>
+
+frysk::proc::ForkTestLib$ForkedProcess*
+frysk::proc::ForkTestLib::fork (jstringArray args)
+{
+ // Convert args into argv, argc.
+ int argc = JvGetArrayLength (args);
+ char **argv = (char **) alloca ((argc + 1) * sizeof (void*));
+ for (int i = 0; i < argc; i++) {
+ jstring arg = elements (args)[i];
+ int len = JvGetStringUTFLength (arg);
+ argv[i] = (char *) alloca (len + 1);
+ JvGetStringUTFRegion (arg, 0, arg->length (), argv[i]);
+ argv[i][len] = '\0';
+ }
+ argv[argc] = 0;
+
+ // Create input/output pipes.
+ int pfds[2][2];
+ errno = 0;
+ if (pipe (pfds[0]) == -1)
+ throwErrno (errno, JvNewStringLatin1("pipe"));
+ errno = 0;
+ if (pipe (pfds[1]) == -1)
+ throwErrno (errno, JvNewStringLatin1("pipe"));
+
+ // Fork/exec
+ errno = 0;
+ pid_t pid = ::fork ();
+ switch (pid) {
+ case -1:
+ // Fork failed.
+ throwErrno (errno, JvNewStringLatin1("fork"));
+ case 0:
+ // Child
+ dup2 (pfds[0][0], 0);
+ close (pfds[0][1]);
+ dup2 (pfds[1][1], 1);
+ close (pfds[1][0]);
+ ::execvp (argv[0], argv);
+ // This should not happen.
+ ::perror ("execvp");
+ ::_exit (errno);
+ default:
+ frysk::proc::ForkTestLib$ForkedInputStream *in;
+ in = new frysk::proc::ForkTestLib$ForkedInputStream (pfds[1][0]);
+ close (pfds[1][1]);
+ frysk::proc::ForkTestLib$ForkedOutputStream *out;
+ out = new frysk::proc::ForkTestLib$ForkedOutputStream (pfds[0][1]);
+ close (pfds[0][0]);
+ return new frysk::proc::ForkTestLib$ForkedProcess (pid, in, out);
+ }
+}
+
+void
+frysk::proc::ForkTestLib$ForkedOutputStream::write (jint i)
+{
+ jbyte b;
+ int w;
+
+ b = (jbyte) i;
+ errno = 0;
+ w = ::write (fd, &b, 1);
+ if (w == -1)
+ throw new java::io::IOException (JvNewStringLatin1 (strerror (errno)));
+}
+
+jint
+frysk::proc::ForkTestLib$ForkedInputStream::read (void)
+{
+ jbyte b;
+ int r;
+ errno = 0;
+ r = ::read (fd, &b, 1);
+ if (r == 0)
+ return -1;
+ if (r == -1)
+ throw new java::io::IOException (JvNewStringLatin1 (strerror (errno)));
+
+ return b & 0xff;
+}
+
+jint
+frysk::proc::ForkTestLib$ForkedInputStream::read (jbyteArray buf, jint off,
+ jint len)
+{
+ jbyte *bs = elements (buf) + off;
+ int r;
+ errno = 0;
+ r = ::read (fd, bs, len);
+ if (r == 0)
+ return -1;
+ if (r == -1)
+ throw new java::io::IOException (JvNewStringLatin1 (strerror (errno)));
+
+ return r;
+}