This is the mail archive of the frysk@sources.redhat.com mailing list for the frysk project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]