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: Test and fix for syscall observer adding (bug #3147)


Hi,

On Fri, 2006-09-01 at 23:01 +0200, Mark Wielaard wrote:
> For the testcase I can of course do some tricks and see if accept() is a
> syscall or, if not, whether socketcall() is available and then select
> based on the first argument of the syscall to see if it really is accept
> (#5). But this seems 1) fragile and 2) looks like a general problem
> people will have when using Syscall Observers.

I worked around it for the test case by just using the SYSread call for
now:

2006-09-04  Mark Wielaard  <mark@klomp.org>

        * funit-syscall-running.c: Accept socket and read() for it.

2006-09-04  Mark Wielaard  <mark@klomp.org>

        * TestSyscallRunning.java: Added back, use SYSread and write to
        Socket.

For the testcase this is OK since it just tests something low-level. But
I think in general we have to look how people will want to use the
syscalls and whether or not to provide something more portable and
higher level.

Cheers,

Mark
Index: frysk-core/frysk/pkglibexecdir/funit-syscall-running.c
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/pkglibexecdir/funit-syscall-running.c,v
retrieving revision 1.1
diff -u -u -r1.1 funit-syscall-running.c
--- frysk-core/frysk/pkglibexecdir/funit-syscall-running.c	1 Sep 2006 12:34:10 -0000	1.1
+++ frysk-core/frysk/pkglibexecdir/funit-syscall-running.c	4 Sep 2006 12:16:40 -0000
@@ -40,6 +40,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -74,32 +75,27 @@
   printf("%d\n", ntohs (addr.sin_port));
   fflush(stdout);
 
-  int runs;
-  // Go round and round.
-  while (1)
+  struct sockaddr_in sai;
+  len = sizeof (sai);
+  fflush(stderr);
+  int f = accept (fd, (struct sockaddr *) &sai, &len);
+  if (f == -1)
     {
-      // Wait till we are OK to go!
-      runs = getchar();
-      if (runs == 0)
-	break;
-      if (runs < 0) 
-        {
-	  fprintf(stderr, "Couldn't read runs\n");
-	  break;
-        }
-
-      while(runs--)
-	{
-	  struct sockaddr_in c;
-	  len = sizeof (c);
-	  fflush(stderr);
-	  if (accept (fd, (struct sockaddr *) &c, &len) == -1)
-	    {
-	      perror ("accept");
-	      exit (-1);
-	    }
-	}
+      perror ("accept");
+      exit (-1);
     }
 
-  return runs;
+  // Wait for the start sign
+  getchar();
+  
+  char cs[1];
+  // Keep reading from the socket till it is closed.
+  ssize_t c = 1;
+  while (c > 0)
+    c = read(f, &cs, 1);
+  
+  if (c < 0) 
+    perror ("read");
+
+  return c;
 }
Index: frysk-core/frysk/proc/TestSyscallRunning.java
===================================================================
RCS file: frysk-core/frysk/proc/TestSyscallRunning.java
diff -N frysk-core/frysk/proc/TestSyscallRunning.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ frysk-core/frysk/proc/TestSyscallRunning.java	4 Sep 2006 12:16:40 -0000
@@ -0,0 +1,371 @@
+// 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 java.io.*;
+import java.net.*;
+
+import frysk.sys.SyscallNum;
+
+public class TestSyscallRunning
+  extends TestLib
+{
+  // Process id and Proc representation of our test program.
+  int pid;
+  Proc proc;
+
+  // How we communicate with the test program.
+  BufferedReader in;
+  DataOutputStream out;
+
+  // The thread that handles the event loop.
+  EventLoopRunner eventloop;
+
+  // Monitor to notify and wait on for state of event changes..
+  static Object monitor = new Object();
+
+  /**
+   * Launch our test program and setup clean environment with a runner
+   * eventloop.
+   */
+  public void setUp()
+  {
+    // Make sure everything is setup so spawned processes are recognized
+    // and destroyed in tearDown().
+    super.setUp();
+
+    // Create a process that we will communicate with through stdin/out.
+    String command = TestLib.getExecPrefix() + "funit-syscall-running";
+    ForkTestLib.ForkedProcess process;
+    process = ForkTestLib.fork(new String[] { command });
+    pid = process.pid;
+
+    in = new BufferedReader(new InputStreamReader(process.in));
+    out = new DataOutputStream(process.out);
+
+    // Make sure the core knows about it.
+    Manager.host.requestRefreshXXX(true);
+    Manager.eventLoop.runPending();
+    proc = Manager.host.getProc(new ProcId(pid));
+
+    // Start an EventLoop so we don't have to poll for events all the time.
+    eventloop = new EventLoopRunner();
+    eventloop.start();
+  }
+
+  /**
+   * Make sure the test program is really gone and the event loop is
+   * stopped.  Individual tests are responsible for nice termination
+   * if the want to.
+   */
+  public void tearDown()
+  {
+    // Make sure event loop is gone.
+    eventloop.requestStop();
+    synchronized (monitor)
+      {
+	while (!eventloop.isStopped())
+	  {
+	    try
+	      {
+		monitor.wait();
+	      }
+	    catch (InterruptedException ie)
+	      {
+		// Ignored
+	      }
+	  }
+      }
+
+    // And kill off any remaining processes we spawned
+    super.tearDown();
+  }
+
+  public void testSyscallRunning() throws IOException
+  {
+    // Get the port that will be listened on and connect to it.
+    String line = in.readLine();
+    int port = Integer.decode(line).intValue();
+    Socket s = new Socket("localhost", port);
+
+    final Task task = proc.getMainTask();
+
+    final SyscallObserver syso = new SyscallObserver();
+    task.requestAddSyscallObserver(syso);
+
+    // Make sure the observer is properly installed.
+    synchronized (monitor)
+      {
+	while (! syso.isAdded())
+	  {
+	    try
+	      {
+		monitor.wait();
+	      }
+	    catch (InterruptedException ie)
+	      {
+		// ignored
+	      }
+	  }
+      }
+
+    // Tell the process to go some rounds!
+    out.writeByte(1);
+    out.flush();
+
+    // Wait till our syscall observer triggers and blocks
+    synchronized (monitor)
+      {
+        while (! syso.getEntered())
+          {
+            try
+              {
+                monitor.wait();
+              }
+            catch (InterruptedException ie)
+              {
+                // ignored
+              }
+          }
+      }
+
+    // Now unblock and then attach another observer.
+    // Do all this on the eventloop so properly serialize calls.
+    final SyscallObserver syso2 = new SyscallObserver();
+    Manager.eventLoop.add(new TaskEvent()
+      {
+	public void execute ()
+	{
+	  // Continue running (inside syscall),
+	  // while attaching another syscall observer
+	  task.requestUnblock(syso);
+	  task.requestAddSyscallObserver(syso2);
+	}
+      });
+
+    // Wait till we are properly added...
+    synchronized (monitor)
+      {
+	while (! syso2.isAdded())
+	  {
+	    try
+	      {
+		monitor.wait();
+	      }
+	    catch (InterruptedException ie)
+	      {
+		// ignored
+	      }
+	  }
+      }
+
+    // Sanity check
+    assertTrue(syso.getEntered());
+    assertFalse(syso.getExited());
+    assertFalse(syso2.getEntered());
+    assertFalse(syso2.getExited());
+
+    // Write something to the socket and close it so the syscall exits.
+    OutputStream out = s.getOutputStream();
+    out.write(1);
+    out.flush();
+    s.close();
+
+    // And check that the observers trigger
+    synchronized (monitor)
+      {
+	while (! syso.getExited() || ! syso2.getExited())
+	  {
+	    try
+	      {
+		monitor.wait();
+	      }
+	    catch (InterruptedException ie)
+	      {
+		// ignored
+	      }
+	  }
+      }
+  }
+
+  /**
+   * Observer that looks for open and close syscalls.
+   * After a given number of calls it will BLOCK from the syscall enter.
+   */
+  class SyscallObserver implements TaskObserver.Syscall
+  {
+    private boolean entered;
+    private boolean exited;
+    private boolean added;
+    private boolean removed;
+
+    SyscallObserver()
+    {
+    }
+
+    public Action updateSyscallEnter(Task task)
+    {
+      SyscallEventInfo syscallEventInfo = getSyscallEventInfo(task);
+      int syscallNum = syscallEventInfo.number (task);
+      if (syscallNum == SyscallNum.SYSread)
+	{
+	  entered = true;
+	  synchronized(monitor)
+	    {
+	      monitor.notifyAll();
+	      return Action.BLOCK;
+	    }
+	}
+      return Action.CONTINUE;
+    }
+
+    public Action updateSyscallExit(Task task)
+    {
+      SyscallEventInfo syscallEventInfo = getSyscallEventInfo(task);
+      int syscallNum = syscallEventInfo.number (task);
+      if (syscallNum == SyscallNum.SYSread)
+	{
+	  exited = true;
+	  synchronized(monitor)
+            {
+              monitor.notifyAll();
+            }
+	}
+      return Action.CONTINUE;
+    }
+
+    boolean getEntered()
+    {
+      return entered;
+    }
+
+    boolean getExited()
+    {
+      return exited;
+    }
+
+    public void addFailed(Object observable, Throwable w)
+    {
+      w.printStackTrace();
+      fail(w.getMessage());
+    }
+    
+    public void addedTo(Object observable)
+    {
+      // Hurray! Lets notify everybody.
+      synchronized (monitor)
+	{
+	  added = true;
+	  removed = false;
+	  monitor.notifyAll();
+	}
+    }
+
+    public boolean isAdded()
+    {
+      return added;
+    }
+    
+    public void deletedFrom(Object observable)
+    {
+      synchronized (monitor)
+	{
+	  removed = true;
+	  added = true;
+	  monitor.notifyAll();
+	}
+    }
+
+    public boolean isRemoved()
+    {
+      return removed;
+    }
+
+    private SyscallEventInfo getSyscallEventInfo(Task task)
+    {
+      try
+	{
+	  return task.getSyscallEventInfo();
+	}
+      catch (TaskException e)
+	{
+	  fail("task exception " + e);
+	  return null; // not reached
+	}
+    }
+  }
+
+  static class EventLoopRunner extends Thread
+  {
+    private boolean stopped;
+
+    public void run()
+    {
+      stopped = false;
+      try
+	{
+	  Manager.eventLoop.run();
+	}
+      finally
+	{
+	  synchronized (monitor)
+	    {
+	      stopped = true;
+	      monitor.notifyAll();
+	    }
+	}
+    }
+
+    public void requestStop()
+    {
+      Manager.eventLoop.requestStop();
+    }
+
+    public boolean isStopped()
+    {
+      return stopped;
+    }
+
+    public String toString()
+    {
+      return "EventLoop-" + super.toString();
+    }
+  }
+}

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