“And most of all, to write Java-GNOME code, wrestle with GLADE and wish GAZPACHO worked better with LibGlade. But I’ll write more of those tomorrow.â€
Well actually I won’t: I wanted to continue on the little article from yesterday. Bloggers are fickle things indeed!
Anyway, I wanted to look just a little bit further and explore some basic core functionality. I wanted to look at a Task observer, and also provide a simple example. Along the way, we’ll touch on what a Task/Proc/Host is, so a twenty second tour is needed first..
So what is a Host, Proc and Task, and what do they mean?
A Proc is Frysk’s model of a Process. In Java, the Proc object is abstract, and currently there is only one concrete implementation called LinuxProc. But it can relate to any concept of a process; just as long as there is a concrete class that implements it.
Much the same, a Task is model of a Thread. And Host is a model of the system (or the host)
. In the current incarnation of Frysk, there are three concrete implementations known as: LinuxHost, LinuxProc and LinuxTask. But the design and the architecture is there to grow.
In simplest terms (for the purpose of this post):
- Host is a physical computer somewhere.
- Proc represents a process on that Host.
- Task represents a thread in that Process.
So for example:
- Proc.getPid() will get the pid of that Proc (or Process).
- Task.getTid() will get the tid of that Task (or Thread).
And to highlight the relationship between the two: Proc.getTasks() will return all Tasks that belong to that Proc.
So, theory done.
If you recall from yesterday’s whirlwind tour, we started the event-loop, set-up a refresh timer, and registered a process created observer with the core.
With those three things completed, very soon we will be getting notifications about what Procs (Processes) exist in the system, and any new Procs that are created later in the future. Also as a side-note, we did not register a Process Destroyed Observer in that example, but it is essentially the same mechanism.
As time goes on and Frysk sends updates of the processes on a system, our Java program might store them in a Hashmap or a LinkedList or similar structure. So now that our Java program has lots of Proc objects, what can we do with them? Well lots of things!
Lets look at a simple example. Let’s add a Fork observer to the main Task object of a Proc object. A Task observer is the same as a Proc observer, except (of course) they apply to Tasks.
So lets setup a fork observer so that Frysk informs us when the given Task for a given Proc calls fork().
class ForkObserver implements TaskObserver.Forked
{
public void addFailed (Object o, Throwable w) {
// Adding the observer failed. Handle here.
}
public Action updateForkedParent (Task parent, Task offspring) {
// You have been told that the parent has made
// a fork systemcall, and the child has been delivered to it.
// We can manipulate parent here.
System.out.println(“Hello Forked world, parent! “ + parent.getTid());
return Action.CONTINUE;
}
public Action updateForkedOffspring(Task parent, final Task offspring) {
// Called when the Task (the offspring) that was created by a fork has
// stopped at its first instruction.
System.out.println(“Hello Forked world, child! “ + offspring.getTid());
// Add a fork() observer to the child, thus propagating the fork() observer
// parent -> child.
offspring.requestAddForkedObserver(ForkObserver.this);
return Action.CONTINUE;
}
}
ForkObserver forkObserver = new ForkObserver ();
...
... // Get a Proc object called linuxProc, probably from the Proc Created Observer.
... // Look at yesterdays article to find out how to recieve procs that reside in the
... // system from Frysk.
...
linuxProc.getMainTask().requestAddForkedObserver(forkObserver);
And that is it! We add the fork observer using the requestAddForkedObserver() call. It’s a Task based api, and we want to add it to the main Task. So we call the Proc.getMainTask() api to find out the main Task in that Proc object.
The observer is split up into two sections: the first when the fork syscall is first seen (updateForkedParent), and the other when the forked offspring Task is sitting at the first instruction fully formed and ready (updateForkedOffspring). As you can see in updateForkedOffspring, we re-apply the fork Task observer to the offspring of the parent. We don’t have to do this, but I thought it would be a neat example on how to propagate observers. You could create an Exec observer in the offspring, and trap exec events in that forked offspring, as another example.
Both updateForkedParent and updateForkedOffspring return the Action.CONTINUE. This tells the Frysk Core to let the Task continue. We could optionally return Action.BLOCK and have the parent and/or the offspring blocked. We would later have to call parent.requestUnblock() and offspring.requestUnblock() to let them continue.
On another note, a word of caution. You should not be tempted to do any heavy lifting in the updateForkedParent or updateForkedOffspring functions in the current thread of execution. Instead you should spin-off another thread and do the heavy lifting there. A simple Thread/Runnable will do. The core event loop is waiting on a response whether to block the parent/offspring and should be answered as soon as possible.
There are many more implementation details to think about, and this is a very simple example.
For Example: If we don’t return Action.BLOCK and (like in the code snippet) perform the call:
offspring.requestAddForkedObserver(ForkObserver.this);
how do we handle events where the offspring had died before the observer could be added? (Remember it is a request that gets queued in an asynchronous loop; no guarantees on time of execution.) How do we request an unBlock outside of the context of the actual observer? We’ve tackled these and other questions in the UI, and I’ll touch on them as I write more on the challenges of writing Frysk: both as a consumer of, and a contributor to it.
And so, to close this post, if you wanted to explore all the Task observers Frysk has today, you can look at all the sub-interfaces to TaskObserver here:
TaskObserver JavaDoc
Each Task observers has its own interface that you must implement; much like how we implemented the fork observer here today.
Many thanks to Sami Wagiaalla, another member of the Frysk team, for help with this post.
Happy hacking!