### Eclipse Workspace Patch 1.0 #P frysk Index: frysk-core/frysk/proc/Proc.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/Proc.java,v retrieving revision 1.94 diff -u -r1.94 Proc.java --- frysk-core/frysk/proc/Proc.java 5 Dec 2006 17:39:14 -0000 1.94 +++ frysk-core/frysk/proc/Proc.java 15 Jan 2007 20:41:28 -0000 @@ -51,6 +51,7 @@ import java.util.logging.Logger; import frysk.event.Event; +import frysk.sys.proc.Stat; /** * A UNIX Process, containing tasks, memory, ... @@ -77,6 +78,13 @@ // XXX: This needs to be made on-demand. return this.parent; } + + public void requestGetParent(Host.FindProc finder) + { + Stat stat = new Stat(); + stat.refresh(id.id); + Manager.host.requestGetProc(new ProcId(stat.ppid), finder); + } final Host host; public Host getHost () Index: frysk-core/frysk/proc/HostState.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/HostState.java,v retrieving revision 1.21 diff -u -r1.21 HostState.java --- frysk-core/frysk/proc/HostState.java 5 Dec 2006 17:39:14 -0000 1.21 +++ frysk-core/frysk/proc/HostState.java 15 Jan 2007 20:41:28 -0000 @@ -58,6 +58,10 @@ { throw unhandled (host, "handleRefresh"); } + HostState handleGetProc (Host host, ProcId procId, Host.FindProc finder) + { + throw unhandled (host, "handleGetProc"); + } HostState handleCreateAttachedProc (Host host, String stdin, String stdout, String stderr, String[] args, Index: frysk-core/frysk/proc/LinuxPtraceProcState.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/LinuxPtraceProcState.java,v retrieving revision 1.1 diff -u -r1.1 LinuxPtraceProcState.java --- frysk-core/frysk/proc/LinuxPtraceProcState.java 5 Dec 2006 17:39:14 -0000 1.1 +++ frysk-core/frysk/proc/LinuxPtraceProcState.java 15 Jan 2007 20:41:28 -0000 @@ -219,7 +219,8 @@ logger.log (Level.FINE, "{0} handleDeleteObservation\n", proc); // If the observation was never added, this will // return false, but that is ok. - proc.removeObservation (observation); + if (!proc.removeObservation (observation)) + return this; observation.fail (new RuntimeException ("canceled")); if (proc.observationsSize() == 0) { // None of the other tasks are attached, just need @@ -367,7 +368,7 @@ proc); // Ouch; request to remove what must be an already // removed observation. - observation.fail (new RuntimeException ("canceled")); + observation.fail (new RuntimeException ("already deleted")); return this; } } Index: frysk-core/frysk/proc/TestLib.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/TestLib.java,v retrieving revision 1.135 diff -u -r1.135 TestLib.java --- frysk-core/frysk/proc/TestLib.java 12 Jan 2007 19:49:18 -0000 1.135 +++ frysk-core/frysk/proc/TestLib.java 15 Jan 2007 20:41:29 -0000 @@ -168,14 +168,30 @@ */ static public boolean isChildOf (int pid, Proc proc) { + logger.log(Level.FINE, "isChildOf pid: {0} proc: {1}\n", + new Object[] {new Integer(pid), proc}); // Process 1 has no parent so can't be a child of mine. if (proc.getPid () == 1) + { + logger.log(Level.FINE, "isChildOf proc is init\n"); return false; + } // If the parent's pid matches this processes pid, assume that // is sufficient. Would need a very very long running system - // for that to not be the case. - if (proc.parent.getPid () == pid) + // for that to not be the case. + + Stat stat = new Stat(); + stat.refresh(proc.id.id); + + if (stat.ppid == pid) + { + logger.log(Level.FINE, "isChildOf proc is child\n"); return true; + } + logger.log(Level.FINE, "isChildOf proc {3} not child pid: {0} ppid: {1} parent: {2}\n", + new Object[] {new Integer(pid), new Integer(stat.ppid), proc.getParent(), proc}); + + logger.log(Level.FINE, "isChildOf status{0}\n", new Character(stat.state)); return false; } /** @@ -187,7 +203,7 @@ */ static public boolean isChildOfMine (Proc proc) { - return isChildOf (Pid.get (), proc); + return isChildOf (Pid.get (), proc); } /** @@ -391,6 +407,7 @@ */ public Proc assertFindProcAndTasks () { + logger.log(Level.FINE, "assertFindProcAndTasks {0}\n", this); class FindProc implements Host.FindProc { @@ -1219,10 +1236,16 @@ { Manager.host.observableProcRemovedXXX.addObserver (this); } + int pid; + StopEventLoopWhenChildProcRemoved(int id) + { + pid = id; + Manager.host.observableProcRemovedXXX.addObserver (this); + } public void update (Observable o, Object obj) { Proc proc = (Proc) obj; - if (isChildOfMine (proc)) { + if (isChildOfMine (proc) || proc.id.id == pid ) { // Shut things down. logger.log(Level.FINE, "{0} update {1} has been removed stopping event loop\n", new Object[]{this, proc}); Manager.eventLoop.requestStop (); Index: frysk-core/frysk/proc/LinuxPtraceHostState.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/LinuxPtraceHostState.java,v retrieving revision 1.1 diff -u -r1.1 LinuxPtraceHostState.java --- frysk-core/frysk/proc/LinuxPtraceHostState.java 5 Dec 2006 17:39:14 -0000 1.1 +++ frysk-core/frysk/proc/LinuxPtraceHostState.java 15 Jan 2007 20:41:28 -0000 @@ -86,5 +86,11 @@ host.sendRefresh (procId, finder); return running; } + HostState handleGetProc (Host host, ProcId procId, Host.FindProc finder) + { + logger.log (Level.FINE, "{0} handleRefresh\n", host); + host.sendGetProc (procId, finder); + return running; + } }; } Index: frysk-core/frysk/proc/DummyHost.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/DummyHost.java,v retrieving revision 1.8 diff -u -r1.8 DummyHost.java --- frysk-core/frysk/proc/DummyHost.java 6 Dec 2006 19:36:34 -0000 1.8 +++ frysk-core/frysk/proc/DummyHost.java 15 Jan 2007 20:41:28 -0000 @@ -58,4 +58,8 @@ { } + void sendGetProc (ProcId procId, FindProc finder) + { + } + } Index: frysk-core/frysk/proc/Host.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/Host.java,v retrieving revision 1.53 diff -u -r1.53 Host.java --- frysk-core/frysk/proc/Host.java 7 Dec 2006 03:05:34 -0000 1.53 +++ frysk-core/frysk/proc/Host.java 15 Jan 2007 20:41:28 -0000 @@ -127,7 +127,8 @@ abstract void sendRefresh (boolean refreshAll); abstract void sendRefresh (ProcId procId, FindProc finder); - + abstract void sendGetProc (ProcId procId, FindProc finder); + /** * Tell the host to create a running child process. * @@ -193,7 +194,7 @@ } /** - * Find a specifc process from its Id. + * Find a specific process from its Id. */ public void requestFindProc(final ProcId procId, final FindProc finder) { @@ -205,6 +206,17 @@ }}); } + + public void requestGetProc(final ProcId procId, final FindProc finder) + { + Manager.eventLoop.add(new HostEvent("FindProc") { + + public void execute () + { + newState = oldState().handleGetProc (Host.this, procId, finder); + }}); + } + /** * Interface to be used with requestFindProc. */ Index: frysk-core/frysk/proc/LinuxPtraceHost.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/LinuxPtraceHost.java,v retrieving revision 1.1 diff -u -r1.1 LinuxPtraceHost.java --- frysk-core/frysk/proc/LinuxPtraceHost.java 5 Dec 2006 17:06:51 -0000 1.1 +++ frysk-core/frysk/proc/LinuxPtraceHost.java 15 Jan 2007 20:41:28 -0000 @@ -478,5 +478,68 @@ { ProcChanges procChanges = new ProcChanges(); return procChanges.update(Pid.get()); + } + + void sendGetProc (final ProcId procId, final FindProc finder) + { + ProcBuilder pidBuilder = new ProcBuilder() + { + public void buildId (int pid) + { + Proc proc = (Proc) procPool.get(procId); + if (proc == null) + { + // New, unknown process. Try to find both the process + // and its parent. In the case of a daemon process, a + // second attempt may be needed. + Stat stat = new Stat(); + int attempt = 0; + while (true) + { + // Should take no more than two attempts - one for + // a normal process, and one for a daemon. + if (attempt++ >= 2) + break; + // Scan in the process's stat file. Of course, if + // the stat file disappeared indicating that the + // process exited, return NULL. + if (! stat.refresh(procId.id)) + return; + } + // .. and then add this process. + new LinuxPtraceProc(LinuxPtraceHost.this, null, procId, stat); + } + } + }; + pidBuilder.construct(procId.id); + + if (!(procPool.containsKey(procId))) + { + + Manager.eventLoop.add(new Event() + { + + public void execute () + { + finder.procNotFound(procId, new RuntimeException( + "Couldn't find the" + + "proc with id: " + + procId.id)); + } + }); + return; + } + + LinuxPtraceProc proc = (LinuxPtraceProc) Manager.host.getProc(procId); + proc.sendRefresh(); + + Manager.eventLoop.add(new Event() + { + + public void execute () + { + finder.procFound(procId); + } + }); } } Index: frysk-core/frysk/proc/TestGetProc.java =================================================================== RCS file: frysk-core/frysk/proc/TestGetProc.java diff -N frysk-core/frysk/proc/TestGetProc.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ frysk-core/frysk/proc/TestGetProc.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,173 @@ +// 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.util.Observable; +import java.util.Observer; +import java.util.logging.Level; + +import frysk.event.RequestStopEvent; + +public class TestGetProc + extends TestLib +{ + class ProcCounter + implements Observer + { + + int count = 0; + + public void update (Observable o, Object arg) + { + count++; + } + + public int getCount () + { + return count; + } + } + + class MyFinder + implements Host.FindProc + { + ProcId expectedId; + + boolean shouldParent; + public MyFinder (ProcId pid, boolean shouldHaveParent) + { + expectedId = pid; + shouldParent = shouldHaveParent; + } + + public void procFound (ProcId procId) + { + Proc proc = Manager.host.getProc(procId); + logger.log(Level.FINE, "proc: {0} proc parent: {1} \n", + new Object[] { proc, proc.getParent() }); + assertEquals(expectedId, procId); + if (!shouldParent) + assertNull("Should not have parent", proc.getParent()); + else + assertNotNull("Should have parent", proc.getParent()); + + Manager.eventLoop.add(new RequestStopEvent(Manager.eventLoop)); + } + + public void procNotFound (ProcId procId, Exception e) + { + logger.log(Level.FINE, "{0} procId\n", procId); + fail("Could not find process with ID" + procId.id); + } + } + + private void doGetProc (AckProcess ackProc, int expectedCount, boolean shouldHaveParent) + { + logger.log(Level.FINE, "doGetProc ackProc {0}\n", ackProc); + ProcCounter o = new ProcCounter(); + Manager.host.observableProcAddedXXX.addObserver(o); + + /* + * This finds out how many processes are associated with the frysk process. + * For example: init->gnome terminal->bash->frysk. + */ + Manager.host.getSelf(); + int preFind = o.getCount(); + + /* + * Find out how many processes are associated with the test process. Should + * be just the one. + */ + Host.FindProc finder = new MyFinder(new ProcId(ackProc.getPid()), shouldHaveParent); + Manager.host.requestGetProc(new ProcId(ackProc.getPid()), finder); + assertRunUntilStop("testGetProc"); + + int postFind = o.getCount(); + + assertEquals(expectedCount, postFind - preFind); + logger.log(Level.FINE, "doGetProc exiting"); + } + + public void testGetAndRefreshFailed () + { + + Host.FindProc finder = new Host.FindProc() + { + public void procFound (ProcId procId) + { + logger.log(Level.FINE, "{0} procId\n", procId); + fail("Found proc 0, should have failed."); + } + + public void procNotFound (ProcId procId, Exception e) + { + logger.log(Level.FINE, "{0} procId\n", procId); + Manager.eventLoop.add(new RequestStopEvent(Manager.eventLoop)); + + } + }; + + Manager.host.requestGetProc(new ProcId(0), finder); + assertRunUntilStop("testFindFailed"); + + } + + public void testGetProcDetached () + { + AckProcess ackProc = new DetachedAckProcess(); + doGetProc(ackProc, 1, false); + } + + public void testGetProcAttached () + { + AckProcess ackProc = new AttachedAckProcess(); + + // expect no additional processes to be added to the procPool. + doGetProc(ackProc, 0, true); + } + + public void testGetProcAckDaemon () + { + AckProcess ackProc = new AckDaemonProcess(); + doGetProc(ackProc, 1, false); + } + +}