Category Frysk

Syscalls and Unwinding

It’s been a bit. Been very busy with assorted Frysk related deadlines. Things have let up, and I’ve a little more time to write.

There’s some excellent work that has been done – and is continuing – on stack-trace unwinding. It’s an integral piece of any debugger/execution analysis suite. I posted on the Frysk external list recently in reply to this work some speculation on the ability to capture a stack-trace on a system-call (or filtered system-calls).

If we do this, when we log that the system-call has been entered in a monitored thread, we can render a click-able link in the log that will take you to the point in the code the system-call happened. This has all sorts of costs associated with it, so the idea very much blue-sky. But it would be nice to click on a list of sys-calls and find out where in the symbol-enabled code each one originated from.

I’ve also been sucked into some Java-GNOME bindings issues. In FC6 some glibc pointer warnings crop up with the bindings. Tracking these down are very difficult, not only because debugging native code in Java can be very tricky in the most vanilla of situations, but the native blobs are processed for free’ing during a g_idle loop. So not only is there the Java GC() scheduling to deal with, but also the idle-loop reaps the native objects at n time in the future. It’s a very challenging debugging scenario, and I cannot but smile at the apparent schadenfreude that fate takes, considering the project I work on.

Work in the horizon includes disassembly, fixing the marshalling widget to record per thread events for the event-viewer (ie fork, syscall, clone and so on), and a mixed bag of other tasks. There’s been a good amount of work on system-calls, and Tom Tromey seems to be having a tremendous amount of fun hacking on ftrace. So happy hacking!

Books

I just finished reading Neil Gaiman’s American Gods. I really enjoyed it during my first reading several years ago, and more so this time around. I rarely read books over again anymore – I used to do it all the time. But I found I would bring a more critical eye on the second reading, and it would ruin the suspension of belief. There are very few books then, that can pull off a second reading that beats the first. So highly recommended.

So what’s going on with Frysk?

I thought I would write about what I am currently working on and been involved with in the last week. There are lots of other things that other team members are up to, but I thought I would let them blog about them (hint) ;)

Right now, I’m puzzling out concurrent sessions. The architecture is there to allow for multiple sessions in the UI, but it needs some work. A concurrent session is just a way to allow multiple disparate sessions to run at once. Though these sessions are separate, they all still have to cooperate and communicate; they will still all be channeled through the one frysk-core, but using multiple core event loops. A likely first candidate is to refactor out the singleton Window Manager to a Factory. I’m not even sure if that is the right approach. So judicious diving into the Gang of Four Design Patterns book, is in order. I can only read the book a chapter or so at a time, as it is so deeply technical. Add to that the Smalltalk -> Java conversions, and the neurons whimper for relief after an hour. It’s a very good book. Anyway, the problem is not converting a singleton to a factory, but rather all the accesses throughout the code to Window Manager expect it to be a singleton, and expect the static instantiations of the windows it manages.

Another thing that has been on my mind for a long time, is a richer set of Actions to Custom Observers. A Custom observer is a UI concept where you can extend the core observers to do X action on Y observer fire, as long as it matches Z filter. It really allows some fine-grain control when an observer fires, and what to do when it fires. Mike took this one last week, and one of the first things we came up with was an additional action that would run a binary file. Once we thought about it for a bit longer, we realized we’d have to throttle this somehow. If the executable was a pager executable that would send a page to someone, and the observer action was “Fork” (or Clone) on httpd, we would not want to page the poor harried system admin a 1000 times in an hour, if httpd went crazy. Lots to think about. It’s going to be exciting see what Mike comes up with in the next few weeks.

Sessions

Sessions. They’ve consumed me this week. And Dogtail. Have not written; blame them.

Sessions, Sessions, Session …

Sessions are tricky. And still not feeling right in the Frysk UI. Some work-flows seem to slot right in, and some require a lot of work. So you keep working at them, tracing down the disconnects with the other flows. And then sometimes after that, they still don’t feel right. It’s a good bet that if it does not feel right to the hackers, it will not feel right to the users, either.

I often think it is the case of the UI failing to bridge what the user wants, and what the system can/cannot provide. That can be in badly written error messages, clunky work-flows, bad prompting or a whole mixed-bag of reasons.

If the UI cannot provide what the user wants, as the system-functionality cannot provide it, how do we communicate that in non-obvious cases? On a functional level, the user might not realize that something is not possible. It might be that they did something that was exactly the same 2 minutes ago, and that worked. The reason might not be obvious. A media player is a good example. It plays music. Media players are good at that, and arguably, the user can expect it to do it well. It can play FOO files, but not BAR files. It can play FOO files as the system has an auxiliary plug-in that can do this. It might have shipped with this plug-in. It cannot play BAR files because the plug-in for that does not exist due to (insert reason here). The functional requirement is still the same: play music. And the work-flow is the same, but the outcome is different. And all the user really wants it to listen to some music.

Someday I might rewrite the above paragraph, as it seems muddled. But keep with me, I’ll slug right along. So what the devil does this have to do with Frysk? A little look at what a Frysk UI session is, might illuminate that a little.

As Frysk is part a forensic tool, it is often that you need to go through a very detailed set of tasks in the UI to get that environment just so. Setting up an environment manually over and over is frustrating. Also, you are very rarely interested in the the whole system, but just a subset. Frysk sessions allow you to narrow the focus of your forensic time to processes you are interested in, and also adds the observers you define to those processes.

So a Frysk UI session is just two steps:

  • Pick the process groups that interest you, currently running on the host (IE Bash)
  • Choose the observers that you wish to add to those processes when the sessions executes.

After that, the UI session setup is complete. You can run the session now, you can run the session next week – whenever. Sessions stick around; they allow you to do a setup chore once, and done. You can edit them of course, delete them, copy them and so on. But ultimately, once you create a session, it is there to stay until you decide to delete it.

The problem here is PIDs. Because a session can last forever, a session cannot allow you to choose Bash with a PID of 1234. It can only allow you to select all Bash, or no Bash. When you select Bash in a session, you are selecting all Bash processes. When you select Fork Observer to apply to that Bash, you are applying it to all Bash processes present. Why? Because if the UI were to allow PIDs to be seen, the PID you select now, and that stored PID in the session you run next week, is meaningless. So to make sure the Bash session you create now, will also run next week, it has to be generic in the selection of what is interesting to you, and what is not.

The interesting thing here is that user feedback seems to be polarized into two camps: people who hate it, and people who don’t. Some people don’t care what Frysk attaches too as long as it attaches to what they are interested in. The rest – to that group – is just implementation. However, some people really want to see PIDs up front, and don’t like the all or nothing approach.

The solution we thought about, and Mike coded up, was to have a session launcher. A session launcher receives a session you decide to run, and inspects it. Say session Foo had Bash in it, and to attach a Fork observer to Bash. The session launcher would look up all Bash instances running when the session launches, bring up a dialog showing all instances, and allow the user to pick what PIDs at session launch time to really attach too. This solved the all or nothing approach, but it still does not answer the question up front. Are we hiding data from users? They may want to see PIDs (even though a PID is not useful to a session). How do we answer the question?

That’s what I’m currently thinking on.

Happy Hacking!

UI testing, Dogtail, and JUnit

I have been starting to use Dogtail recently. I’ve been following it for awhile, as a really excellent open source UI testing tool. It’s something we’ve been looking at for Frysk UI testing, for quite awhile. Beyond the selfish desire to code some Python now and then (I get an odd urge to program it occasionally, and who can blame me: it’s an excellent language). But also it’s a great way to test Java-GNOME (and any GTK+) application out there. We’ve been using this as a part of the tier one Frysk UI testing.

I’m still very much in the learning phase, but I think Dogtail answers a great many questions on how we can answer UI test design challenges. Len DiMaggio at Red Hat just recently wrote two great articles in Red Hat Magazine:

Automated GUI testing with Dogtail

and

Dogtail’s Python Modules (and how to use them)

And also wrote the existing Dogtail scripts for Frysk. Those articles can explain in far more eloquence than I can aspire, what Dogtail is, and why it is important.

The other tier of testing is Junit testing. Every UI of size eventually accumulates various managers that start running behind the scenes. In Frysk we have various Singletons, Factories and Builder patterns that can all be exercised with Junit tests. Sometimes it is a challenge to write them, as it requires a major shift in code philosophy. I touched on the UI not coding to the API based pattern last night, and Junit patterns are testing – it seems – just that. Thankfully, I’ve lots to learn from the Frysk group in this regard, and Andrew is a great advocate of Test Driven Development. It gets easier. I think to greatly-paraphrase Keringhan (and thanking Rik van Riel for the full quote, from his sig): It’s twice as hard to debug code than to write it. I would make an equal assertion about writing complete and sound test cases.

Have a great weekend, and happy hacking!

A look at ftrace, or how to write your own Frysk utility

It’s true that Frysk will have a UI that will wrap and encompass its functionality. But there is no reason that a set of other Frysk based utilities cannot exist either. A set of tightly focused utilities would complement the UI, and expand the functionality of Frysk. Personally, I’ve always envisioned Frysk to be a suite of tools, rather than one monolithic tool.

This suite concept is important, because all Frysk tools will have a common architecture. Utility Foo will have the same common architecture as Utility Bar, which uses the same architecture that Frysk UI is built on. Because of this core-based approach,
resulting tools will be lightweight, and have a much smaller code-base than “from-scratch” utilities. This was a very conscious design decision by the architects of Frysk; primarily, so we don’t reinvent the world each time we we write a tool. So on that subject, I’d like to explore a Frysk based utility that was recently written.

Recently, there has been a lot of work done on the System Call Observer in Frysk. A System Call Observer is – as its name implies – a tool for watching entering and exiting system calls in a task. So the system call observer code was written. During that time, another standalone tool was also written called ftrace. This tool was written to use the functionality of the system call observer in a standalone environment, which has clear and existing need in the system-tool world.

ftrace allows you to pass a binary file as an argument. When run, ftrace loads and executes that binary, and watches system calls that the binary calls. When it sees the call, it prints them to the console. Sound familiar? In many ways it is the same as strace. It’s a new tool and sure to grow, but the entire codebase for the ftrace utility itself 107 lines. Why so small? Because most of the heavy lifting is done in the Frysk Core.

Before we dive in and have a look, a lot of this post covers material explored during the last week. So have a quick read back, if you missed the other posts. Finally, you can find the full ftrace code in the namespace:

/frysk-core/frysk/bindir/ftrace.java
and
/frysk-core/frysk/util/Ftrace.java

or here are links to the project webcvs view: ftrace.java and FTrace.java

How does ftrace start? It’s a pretty standard Java program, with a main function, just like you have seen many times before. It also setups a PrintWriter, and does a brief argument sanity check


public static void main (String[] args)
{
    final PrintWriter out = new PrintWriter(System.out, true);
    if (args.length == 0)
      {
        out.println("Usage: ftrace pid...>");
        return;
      }

Pretty vanilla so far. The two really interesting things here, are the two Frysk calls that comprise the rest of the main function:


   Manager.host.requestCreateAttachedProc(args, new AttachedObserver());
   Manager.eventLoop.start();
}

And that is the main function. Looking back at those Frysk calls, the first call takes the arguments from main (in this case, the name of the program that was passed to ftrace, stored in args). It then calls the requestCreateAttachedProc function which asks Frysk to: create the process specified, execute the process, and then attach to that process. The second argument to the requestCreateAttachedProc function attaches the given observer (in this case, AttachedObserver which is defined later on in ftrace) to that process.

The second function call: Manager.eventLoop.start() simply starts the eventLoop (as discussed in previous posts).

Lets take a look at AttachedObserver that was passed as an argument to the requestCreateAttachedProc function call. It is defined later on in ftrace.java:


private static class AttachedObserver implements TaskObserver.Attached{
    public Action updateAttached (Task task)
    {
      task.requestAddSyscallObserver(new SyscallObserver());
      setProc(task.getProc());
      task.requestUnblock(this);
      return Action.BLOCK;
    }

    public void addFailed (Object observable, Throwable w){
      throw new RuntimeException("Failed to attach to created process", w);
    }

  }

I’ve deleted addedTo, deletedFrom for sake of brevity (as they were not implemented). We can see that AttachedObserver implements the TaskObserver.Attached interface. The important function here is updateAttached. This function is called when the Task (in our case the mainTask) has been attached by Frysk. As requestCreateAttachedProc() actually attaches to the mainTask of the given process, this observer is called when requestCreateAttachedProc() has completed its work.

If we look in updateAttached(), the first thing it does is add a System Call observer called SyscallObserver. This is defined later on in ftrace.java. For now, we’ll stay and continue with AttachedObserver. It then calls the setProc function that adds a rudimentary ProcDestroyed observer. This observer – when notified of a destruction event – will stop the event loop and exit. Why do this? Because if the process we have attached too has been destroyed, then it is completed; and our syscall tracing is done.

Time to take stock, and recap so far:

  • args is passed to Manager.host.requestCreateAttachedProc() which denotes the process to be run. So for example: ftrace /bin/uname, would create, attach and run /bin/uname.
  • We add the AttachedObserver as a parameter to requestCreateAttachedProc(), so that when the process is loaded, prepared, and attached too by requestCreateAttachedProc(), this observer will be notified.
  • In AttachedObserver, we add a new System Call observer to the main task of the given process. We also set up a Proc Destroyed Observer that kills the event loop and exits when the given process exits.

In essence, all of the code this far into the article was just setup, set observers, and tear down code. Now that the process is running, and we know when to exit, lets take a look at the actual System Call Observer. This forms the core of ftrace, and is notified whenever the task it is attached to enters or exits a system call.


   private static class SyscallObserver implements TaskObserver.Syscall{

    public Action updateSyscallEnter (Task task)
    {
      SyscallEventInfo syscallEventInfo;
      try {
          syscallEventInfo = task.getSyscallEventInfo ();
      }  catch (Task.TaskException e) {
          throw new RuntimeException("Failed with task exception: ", e);
          return Action.CONTINUE;
        }
      frysk.proc.Syscall syscall = frysk.proc.Syscall.syscallByNum(syscallEventInfo.number(task));
      PrintWriter printWriter = new PrintWriter(System.out);
      printWriter.print(task.getProc().getPid() + "." + task.getTid() + " ");
      syscall.printCall(printWriter, task, syscallEventInfo);
      printWriter.flush();
      return Action.CONTINUE;
    }

    public Action updateSyscallExit (Task task)
    {
      SyscallEventInfo syscallEventInfo;
      try {
          syscallEventInfo = task.getSyscallEventInfo ();
      } catch (Task.TaskException e) {
          throw new RuntimeException("Failed with task exception: ", e);
          return Action.CONTINUE;
      }
      frysk.proc.Syscall syscall = frysk.proc.Syscall.syscallByNum(syscallEventInfo.number(task));
      PrintWriter printWriter = new PrintWriter(System.out);
      syscall.printReturn(printWriter, task, syscallEventInfo);
      printWriter.flush();
      return Action.CONTINUE;
    }
  }

I deleted addedTo, addFailed, and deletedFrom for the purposes of brevity. When we add this observer to a given process, all system calls that happen inside that process (or the main task of that process) are captured here. The system call observer implements the TaskObserver.Syscall interface. The really Read more

A little bit more on UIs

Let it be said, that writing a UI is a difficult task. I think if I’ve learned anything in the last year, this is my biggest lesson. It really requires a shift in thinking: it’s different from writing a library api, for example. You design the api to be called in one way, to pass these arguments, and expect these results. If something goes wrong, you throw an exception, and hey buddy, you handle it.

UI’s are different. A user can use it in many different ways. The problem is even worse if the UI is not directed (like an assistant), but expects input from the user in a variety of different ways (like a word processor). There are many workflows, and the more there are, the more complex testing becomes. But that is just the mechanics of the UI. You can write a perfectly stable UI that is a perfect pain to use.

The best UIs I find are the least obtrusive. And so in terms of complexity, it also seems to be on an inverse scale; the less you actually noticed a UI, the more difficult that UI was to write. At least for me. That sort of makes no sense, unless you think of the UI as a facilitator to that tool’s functionality. Is that a metric that is useful? For me it is, but it might not be for you. I judge the usefulness of a tool on two levels:

  • Does it give me the functionality that I want?
  • How much of a toll on me is it to get that functionality?

For the purposes of this post, I’ll extrapolate toll to be frustration.

It’s easy to write a UI you notice. Write one that crashes, or abstracts choices away in forever-nested-menus, or just plain gets in the way; it will get noticed real fast. Write an assistant (or wizard) that goes on and on, and leaves you thinking: “when is it going to stop asking me inane questions?!” That too, will get noticed.

But why does a UI frustrate you, me … Uncle Bob? I’m sure that was not the intent of the author. What patterns of usage did the author see when he wrote the UI? Why do those usage patterns frustrate you? And perhaps more importantly, why did the author not perceive your usage pattern? Why is tool X better than tool Y, when they both do they same thing?

So it’s interesting to me, when I come across an interface that (quietly) does it’s job so well; that works so well you barely even notice it (the UI) and sing its praises. How is that done? What formula did that UI use, that was so unobtrusive, it went virtually unnoticed? Can we bottle it? ;)

That for me is the grail. When one writes a UI that is transparent to the user, that exposes the functionality of a product without so much whisper of notice. That is genius. How can some teams achieve that, and not others? How can we achieve that?

I’ve been musing on these ideas a great deal lately. We’re at point X and I want to be at point Y. I want the user to use Frysk UI to use Frysk Core and do the great things it can do; but not notice they are using Frysk to do it. Facilitate. We’ve got a very complicated tool to write, and a lot of deeply complex, yet compelling information about a host to present. Frysk can be a forensic tool and map out when your process: forks, execs, clones, or does lot of other things. It will let you look at the source code when this event occurs (if my process forks, stop the process, and I want to see the source window at the point that it forks). Or log it, or send a dialog to the user. And lots of other things. There are many, many work-flows and they all have to work together. Big challenge.

If I were to take a stab at an answer, I think we often forget the actual user we are writing the tool towards, and end-up programming functionality for ourselves. It’s an insidious problem: we write the tool to solve a problem; and it might be a problem we are trying to solve ourselves, as well as for others. It might be a very compelling problem for us – it is difficult not to imprint your own personality on that solution, to the exclusion of it being the best solution. I think we’ve all put something together – just as a quick interface – to get along just for now – for a tool. And this UI is still there 10 years later. It is something that happens everyday in software engineering, and I think a lot of UIs get in this category because of time, lack of knowledge, and to quote that funny old bugzilla entry: “WORKSFORME”.

So there are many challenges and questions. Are there answers?

Thankfully there are a lot of people who do a lot of deep-thinking on these issues. I’ve had the pleasure of meeting a few of them when I traveled and visited the Boston office this year. Their jobs are almost philosophical (and seemingly somewhat painful at times). But they do them very well. Why does the user want to do this? What is the user going to do next? How can we be kind to the user? Those are the things I thought about after talking to them, and I think they and their counterparts all over the world really do work very hard for the user, and usability.

So as a programmer, engineer and user, I find myself evolving towards these ideas. Something I never used to practice, but practice now:

  • I use UI builders. I think the importance of these tools cannot be overstated. They allow for prototyping and rapid (or more rapid) changes to UIs than conventional “all in code” methodologies. There are two tools for GTK+ that I use:

    I’ve recently discovered Gazpacho, and like it almost as much as its namesake. It’s a newer product than Glade, and has some excellent features that Glade does not. Because it is new, it has some issues in interoperability with Glade. When you import a Glade project, I’d keep a backup of the .glade files as Java-GNOME’s LibGlade can have difficulty reading the Gazpacho altered files. And no, I’ve not filed a bz, and I’m not allowed to whine and make please fix! noises yet.

  • I’ve read the Gnome HIG. Re-read it. It’s a an excellent guide, and it also tells you in many situations the “why” as well as the “how”. I don’t know about you, but that really puts the information in context.
  • Use workflows. I (and lots other on the Frysk team) have started doing quite a bit of this, as it keeps the user in context. It helps maintain a focus, and also brings the notion of a feature into context with the product.
  • Build usecases for users. Again another thing I (and others) have started doing in Frysk. It brings back to you the concept of the problem, what the problem is, and do we really need that cool widget you invented yesterday?

If there are any other tips, methodologies, or practices out there I should be using, let me know! Or you can write to the Frysk mailing list and find me, and many others of the Frysk group .

You can find the team, mailing list, and many ways to get involved on the Frysk Get Involved! page.

A Simple Fork Task Observer

“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!

Frysk Development

I thought I would write a little about Frysk development.

Frysk is a pretty standard layered architecture:

  • frysk-gui sits on the top.
  • frysk-core sits in the middle.
  • frysk-sys sits closest to the metal.

we also have an orthogonal layer that we need to tug around with us, called frysk-imports. I won’t embellish on these layers right now, but just wanted to point our their relationship to each other.

The Frysk UI uses the Frysk Core just like any other Java library. It imports the jar file and starts calling the APIs. There is very little overhead in Frysk Core’s use. However there is one prerequisite to using it, and that is to start the event loop.

The Frysk core runs an asynchronous event-based loop (which means you request that it do something, and it will get back to you later when it has done it, or failed). Example code to start the event loop might look like:


Thread eventLoopThread = new Thread(new Runnable() {
   public void run() {
      try {
         Manager.eventLoop.run();
      } catch ({Exception e) {
         //Eventloop threw an exception, handle it
      }
   }
});
eventLoopThread.start();

And that very simple piece of code would get the frysk-core event loop running.

Another thing you may wish to do is to request that Frysk Core send periodic updates of its process/tasks table. For that purpose, we use TimerEvent, which is a Frysk Core api that allow us to periodically place requests in the Frysk Core Eventloop.

So something very simple like:


TimerEvent refreshTimer = new TimerEvent(0,3000) {
   public void execute() {
      CustomEvents.addEvent(new Runnable() {
         public void run() {
            Manager.host.requestRefreshXXX(true);
         }
      });
   }
};
Manager.eventLoop.add (refreshTimer);

Would send us updates every 3000ms, or 3 seconds.

So the Frysk Core is ticking along, recording what processes are being added or deleted (and their children). But how do we get these creation/deletion events, and how do we handle them?

Well, the answer is pretty simple. The Frysk Core follows the observer/observable design pattern for notifications and addition of (most) observers. To get a process added/removed event, you would have to register your own observer/handler with the core. This is so you may handle those events as you wish, in whatever programming design pattern you choose (or don’t choose ;) . Here is a brief example of a Process Creation observer.


private HelloWorldProcCreatedObserver myProcCreatedObserver = new HelloWorldProcCreatedObserver();

class HelloWorldProcCreatedObserver implements Observer {
   public void update (Observable o, Object obj) {
      final Proc proc = (Proc) obj; // the proc object that was just created, and sent up from the core.
      System.out.println("Hello World " + proc.getCommand() + " " + proc.getPid());
   }
}

Manager.host.observableProcAddedXXX.addObserver(myProcCreatedObserver);

For those of you familiar with the observer design pattern, the above code should look very familiar. All we are doing there is registering our observer with the Manager so that when a ProcAdded event occurs, it gets notified along with the object (in this case a core object knowm as a proc). All of the UI datamodels that the user sees represented in the various treeviews and listviews follow this simple example.

Clearly there is far, far more to Frysk than these simple examples. And we have barely dipped the proverbial toe into the water (one might argue, we’ve not got our socks off yet). But at the outset of this blog I just wanted to illustrate how easy it is to get interesting things out of the core, so quickly. And being a UI contributor, how important that is.

The asynchronous event loop that uses observer design patterns allows us to detach ourselves from the implementation details of the core. (As well as write complicated-sounding sentences like that).

We’ve been granted that freedom, which allows us (well me) to focus our efforts towards other challenges, such as managing data input in sync with core output. Managing the vast amounts of data propagating between the UI and the Core. Managing the concept of a custom observer, which has an action and a filter to allow users to make decisions about their data. And so on.

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.

Frysk

I’ll have to admit that before I joined the Frysk team, I did not think much about Execution Analysis – or Debugging – or really any of the thorny, tricksy issues that now dominate my thoughts. Back then – before I looked behind the curtain – a breakpoint was something to be set; a register peek was just that, and stack traces were supposed to just happen. Debuggers, and I use that term carefully, were tools – just like compilers, editors and profilers. Something you used, but rarely thought about. Carpenter and chisel. Bricklayer and trowel. And they (these tools) were supposed to just work. I was wrong.

I dropped into the Frysk team in June 2005. How I got there, is neither important or relevant, but it means I’ve been at Frysk for about a year: thinking very complicated thoughts about above and more importantly, how to communicate these to the user.

It’s slowly taking shape. I’m not going to write about why Frysk needed to happen, or why it is sorely needed – that’s for later posts. But during that process Frysk has become increasingly more complex, and with that, the danger of it becoming complicated. Complex and complicated are two very different things. Apple are very good at making simple interfaces to complex devices. They are not complicated. They are good at it. They are a pleasure to use (mostly).

There are a lot of other tools out there, in GNOME, in KDE, and other areas that perform the same role of turning the complex into the delightfully simple to use. You do not grumble, gnash teeth, wail in frustration when using these tools. In fact you barely notice the UI at all; you are connected with the tool, and the UI facilitates that connection. It’s transparent.

This might all have been said and written down before, but for me it was an epiphany of recent times.

I’m reminded of a quote by a favorite jazz musician:

“Making the simple complicated is commonplace; making the complicated simple, awesomely simple, that’s creativity.”

Charles Mingus

And so, with that in mind, the reason for this post. I’m not an experienced UI builder, and with only the trusty GNOME HIG to guide me, this is most clearly a new garden.

I was expressing my frustration to a friend of mine, about the very indistinct art of building a UI for a very complex interface, and it was he came up with the suggestion that I write. To organize your thoughts he said. It stuck with me over the weeks, and decided to at least give a whirl. So I did, and here I am.

You can find more info at the Frysk website

Copyright © Phil Muldoon

Built on Notes Blog Core
Powered by WordPress