fredag 30 oktober 2015

Mind sweeped

Today I'm playing a game of Minesweep. I never really got the hang of that game, but I'm hoping that one day we might be able play some more intriguing games. On the Amiga, using JAmiga!

So, yes, I've finally managed to get the existing AWT functionality working! Much of this is not my code, but created like ten years ago (!) by the original JAmiga developer, Peter Werno. There were a few issues that kept it from running using the new JamVM, and otherwise updated code, but I've finally got the original demos to work.

Volatile

There were a few synchronization issues, which didn't happen before. One minor, easy quick fix, was to add the word "transient", I mean "volatile" to the running flag of the window listener thread. This is how it works: the main Java thread wants to open a window. Then a new "window listener" thread is started, which actually opens the window. In order for the main thread to know when the window has been opened, it polls and loops for a flag to be set to true by the window listener thread.

// main thread waits for(ever) for running to be true 
MainThread::startGUI() {
   new WindowListenerThread().openWindow();
   while(running == false) {
     // do nothing
   }
}

...
// window listener notifies "object" when opened
WindowListenerThread::openWindow() {
   window.open();
   running = true;
}

In the old code, this was a normal boolean flag, not marked with special word "volatile". "Volatile" means that the variable can be changed by more than one thread, and, if you don't mark it that way, the JVM can make clever assumptions if it thinks that this variable isn't going to change. This means that if the main thread keeps looping and looking at it, the flag will, most of the times, be false. Even though it will take like no time to open that window, the loop will probably have made quite a few loops, and thus, in order to optimize and get a snappier Java experience, instead of actually fetching the value of the flag each time, the JVM assumes it is always false. And this is all according to the specifications and the way Java works. Previously the JVM didn't make this clever assumption (or if it was the old Java compiler that didn't make them).

I also added some synchronization around these parts, so instead of a constant loop, the loop is synchronized, meaning it checks the flag, and then waits to be notified from the window listener thread, and only then checks the flag.

// main thread waits for "object" to be notified
MainThread::startGUI() {
   new WindowListenerThread().openWindow();
   while(running == false) {
      object.wait();
   }
}

...

// window listener notifies "object" when opened
WindowListenerThread::openWindow() {
   window.open();
   running = true;
   object.notify();
}

This synchronization (the notify() and wait() methods) are part of the Java standard, and used all over the place. And when looking at it for the AWT stuff, I found some things in my implementation that were not quite working. I've known that the synchronization and signalling parts have had some glitches, so that signals sometimes aren't received as they should, leading the JVM to a halt. I knew I was taking a few shortcuts before, but now I'm pretty confident it works according to specification, since I this time actually carefully read the specifications... And, I've also been able to verify that it seems to work better, since I actually now use JAmiga to compile Java code when I'm developing JAmiga on my X1000. We kind of almost have a Java implementation so we can build Java ourselves on the Amiga!
Edited: of course I meant volatile, not transient

So, all the graphics is done now?

Now, this doens't mean that the graphics are all done, and that we can download NetBeans and run it. There's still quite a few unimplemented methods in the JAmiga specific AWT-packages. But it's getting there!

4 kommentarer:

  1. Hi Joakim,

    Nice work! :)

    Just one minor point, in the article, you indicate use of transient. Just wondering if you mean volatile, since transient just stops serialization of data, so shouldn't have any meaning when dealing with multiple threads?

    SvaraRadera
    Svar
    1. Hardly a minor point! You gave me quite the scare, I had to look at my code! And thankfully, I did use volatile in the code. Don't know why I wrote transient here...
      Thanks for pointing it out!

      Radera
  2. Sorry I scared you Joakim - but very glad it was a false alarm! :))

    All the best,

    Sean.

    SvaraRadera