söndag 29 december 2013

Java Developer's Kit

Tiny update for Java developer's

On the JAmiga support forum on amigans.net I've added a little note on a developer's package available on AmiUpdate:

On AmiUpdate you can find an update consisting of a few developer's files. There's a new Java compiler, a simple example, as well as documentation.

Just update your system, go to JAmiga:Documents/Developer.guide, and you're just minutes away from compiling your own applications.

I'll try to add more info on how you can use it with various third-party jar files.

New year's resolution?

I managed to get this tiny update out before the year has ended. Next year, I'll try to be better in getting stuff out there. Even it's only small things. I've been a bit too silent the last two months, but other things in life has taken up my time.

Over and out. And a happy new year!

måndag 4 november 2013

JAmiga 1.2

JAmiga 1.2 is currently in os4depot's upload queue. After its been approved and uploaded, I will add the update to AmiUpdate -- so you who already have v 1.1 installed can wait for the AmiUpdate update.

This is a full release: all required components are in the archive. Future updates of the individual components will be available with AmiUpdate as usual.

Change log

  • Added support for java.io.Console in javanio.library
  • Changed drawer hierarchy of JAmiga files in order to ease update and maintainability
  • Minor fixes in jamvm
  • New default and regular icons from Mason
  • The environmental variables (BOOTCLASSPATH and LD_LIBRARY_PATH) are no longer needed

Thanks to all of you

I'd like to, in no particular order, thank you all who have contributed in any way to JAmiga. To mention a few:

  • Joel Edberg for testing (and constant nagging me for updates)
  • Thomas Blatt for the first set of icons
  • Martin Mason Merz for the 2nd set of icons, including DefIcons
  • All you kind lovely amigans for support, cheering and donations! Without you, my work would be profoundly pointless!

And, of course, credit where credit is due. This is a continuation of the original JAmiga effort, by Peter Werno and André Dörffler. Even though there has been lots of changes, and it now also sports the JamVm JVM by Robert Lougher.

Nope, now I have to press "Publish" -- the os4depot upload has been approved!

torsdag 17 oktober 2013

Continuing mauve testing

Slowly but surely I'm working through the mauve suite. Currently, focus is on java.io.
Yesterday I got these fails:
FAIL: java.io.File.ReadMethods
FAIL: java.io.File.ExecuteMethods
FAIL: java.io.File.newFileURI
FAIL: java.io.File.WriteMethods
FAIL: java.io.File.URI
FAIL: java.io.File.security
FAIL: java.io.File.UnicodeURI
FAIL: java.io.File.createFile
FAIL: java.io.File.newFile
FAIL: java.io.File.emptyFile
FAIL: java.io.RandomAccessFile.security
After running these tests:
And, tonight I fixed these issues:

So, slowly, but surely. Even though most of these errors aren't show stoppers, they still need to be fixed.

söndag 29 september 2013

File me a river

I finally found what was wrong, and why ECJ couldn't compile like it should. I missed my modifications made to jva.io.VMFile, the native layer between Java files and Amiga files. With this in place, ECJ can now compile correctly. So, no more need to use jikes.

Connecting the dots

However, the file handling is not entirely solved just yet. I'm still pondering on how to solve the dot file, ".", denoting the current directory. I think it's a rather silly little marker; to me as an amigan it serves no real purpose. It just sits there. On unix, a path like "/dev/./././" is really just "/dev/". So, I don't really see the point (pun intended).

Picture stolen from bigactivities.com

Anyhow, I think I have to handle it somehow, since there'll probably be a few applications assuming that it works (amongst them jamvm). The "/dev/" example also leads me to one such unix-amiga inconsistency. In the mauve test suite, a test exists involving files and URI's. The test wants the URI of file "/dev/tmp" to be just "/dev/tmp" (or rather the URI "file://dev/tmp"), whereas the current JAmiga implementation happily tries to make that into "file://SYS:System//dev/tmp/", when I guess it really should be just "file://dev/tmp/" (internally represented as "dev:tmp/"). And where AmigaDOS thinks the path "SYS:System//Utilities", really is "SYS:Utilities", JAmiga thinks its just "SYS:System/Utilities".


måndag 26 augusti 2013

Whose line is it anyway?

Its been a while since an update. I've however not been entirely idle. I've updated to the latest GNU Classpath CVS version, which only added the java.io.Console class. But I found the Console class to be needed by the egit Git Hub client. Sadly, egit also requires some annotation stuff found in the not yet implemented "javalangreflect" library. Its a library with only one method in it, so it shouldn't be a biggie. Its just a matter of, well, doing it.

Commas and colons

Furthermore, I've been looking at running the Eclipse Java Compiler, ECJ. Now, don't get your hopes up on the Eclipse mentioning -- its only the compiler, no GUI stuff. But it can compile new Java source, i.e. generics and stuff, and is not limited to Java 1.4, like the old Jikes. However, with my move to the latest GNU Classpath (and some other organizational changes), ECJ won't compile things correctly.

This either due to something not being correctly configured in the new Classpath, or due to the classpath misbehaving. In order to work, Java needs to know where to find all the Java classes. Usually you can set this using the ENV variable CLASSPATH. In order to set a list of directories to search for classes, you use some sort of delimiter between the directories. In JAmiga this is comma.

A classpath with two (actually three) directories to search for classes.

The GNU Classpath and jamvm are (or were), like everything else, mostly Unix/Linux and Windows oriented. They use either colon, or semicolon to separate classpath directories, for Unix/Linux and Windows respectively. Now, Amiga's device separator is colon, so colon can't be used. Semicolon could be used... but the way GNU Classpath and jamvm detects that a system is f.i. Windows, is based on the simple occurrence of a colon, sometimes a backslash, and sometimes the fact that it doesn't seem to be a Unix path at all. So using semicolon would sometimes suggest a Windows system (and, inherently, only allowing device names consisting of one character like in C:). Therefor I thought it better to simply "invent" a new standard, using comma. To make matters worse, sometimes files are referenced using an URI, meaning we have even more colons, like "file:Work:classpath/", or "file://Work:classpath/". More often than seldom, I see lines like "file:JAmiga:jvm/classes/Work:classpath/" being interpreted as one directory. Its a mess, really.

The dotted line

I don't know if the whole classpath-colon-slash-backslash mess, is the real culprit to ECJ not running. There are also known issues with the "dot" device, i.e. the current directory marker. The CLASSPATH ENV variable usually ends with a dot, so that the current directory is included in the search. Using f.i. "JAmiga:classpath,Work:other/classes,." should include three directories in Java's class search. However, in the Amiga world, this doesn't work, since the dot does nothing special in the Amiga OS (its just a non-existing file). A possible workaround for AmigaOS 4 would be "JAmiga:classpath,Work:other/classes,CURRDIR:". However, that will actually search for stuff in "CURRDIR:/", which is nothing else than the parent directory of CURRDIR -- if you know your Amiga DOS, you'll know that the last slash is what Windows and Unix calls "..", i.e. the parent directory. And this last slash is added on a line nestled in various for loops looking for slashes and colons, trying to both determine Windows- or unixness, as well as formatting the path correctly. And after a hard day's work... for loops and slashes really becomes a jungle.

Trying to find whose line it is... usually only makes me waste hours on youtube looking at stuff like this:

Whose line can really consume hours.

torsdag 1 augusti 2013


I've managed to draw a nice new icon for JAmiga! This is what I've been doing the last few days since my silly release:

Finally, I deliver some quality work. If you'd like to have this really nice eye-candy, just download the latest release.

No, seriously, that icon looks like something my lolcat managed to draw in PPaint trying to pet the Logitech (which is not far from the truth). With the help from Joel Edberg, Thomas Blatt was persuaded to draw me some really nice icons, and JAmiga can now boast with fancy icons. How they look? Well, download the update below to see.

Not only pretty pictures

This release also includes support for AmiUpdate, so you'll get freshly squeezed JAmiga automatically!

Besides AmiUpdate, these are the other changes in this new first real release.

  • New script, JAmiga:JAmiga, which holds the release version. Executing this script will show you the currrent status of your JAmiga installation -- invaluable information for me when looking for errors. Besides the script spitting out various settings and assigns, it'll also try and start a tiny Java application, only to show you that it works (or not).
  • Fixed the "Filer:" assign in jamvm
  • Changed versioning of jamvm. The previous pre-release of jamvm had version 1.5.4, just like jamvm really has. I've now changed this, so the 1.5.4 version is reported in the full version string, and the Amiga jamvm version is reported as 1.1. I hope this doesn't pose problems in future AmiUpdates (since 1.5.4 is higher than 1.1)
  • Removed debugging from javanio.library making it less slow.
  • And, of course, the new shiny icons!

Java application seen working

Now, my ill-fated Twitter client isn't really the killer application we all wanted, I guess. But other stuff has been reported working:

  • The reason for fixing javanio.library, was primalrily that it caused problems running Smushit, as reported by asymetrix over at amigaworld.net. With my tiny fix it now actually works. It turned out that writing the smushed files took too long time, timeing out the Yahoo server.
  • Chris_Y reported that jasypt (some sort of encryption thingie) worked, after giving it some proper command-line love.

It's really nice to see the amigans eagerness in trying out JAmiga. I will myself try a few things I've been looking at running, and hope that you all keep up the good work! I will keep on reporting what has been seens working.

Enough rambling, show me the download!

You can install this 1.1 version over your current installation, or to a clean system.
If you have the 0.1.0 version installed, you can uncheck the GNU Classpath choice -- nothing has changed there.
Follow the link below to download. Unpack the archive with UnArc (lha sometimes misses the the flags for the scripts)

And keep an eye on AmiUpdate!

torsdag 25 juli 2013

A silly release

Downloads available

So, I haven't done much lately on JAmiga, but I'd thought I at least give you something to play with. I've prepared an archive with everything you need to install a Java environment on AmigaOS 4.

And first of all: its still considered beta!

Here are the downloads:


  • If you have installed JAmiga on a drive with international characters in it, like "Hårddisk", AmigaOS will ask you to insert the disk "H?rddisk". You can either assign "H?rddisk" to the real "Hårddisk", or alter your user-starup, and assign JAmiga to the partition name, like DH1:. I guess this also applies for drawers with international names.


The installation of the main JAmiga archive is pretty straight forward. Just unpack and stat the installer. The "installation" of the silly Twitter client is also easy - just unpack to wherever you want it.

Actually a silly release

I say silly Twitter client, because it is. To be totally honest, this entire release is a bit silly, at least from a user perspective. Not that JAmiga doesn't work - it does indeed work. Only that we don't have so much content to play with. My hope is however that someone with some Java skills will start developing, or find some novel stuff we can run. The source code for my silly Twitter client is included. And you get a Java compiler in the installation! So its only a matter of starting to develop and do stuff better!

Running the silly client

After you've installed JAmiga, you can download and unpack the Twitter client.

Start the Twitter client by double click the JAmigaTwitter.jar file.

You'll be asked for input. This first time you can simply run it, and you'll eventually be presented with some info on how to make it do stuff. Notice the "eventually" - depending on your machine it might take a while to start it, and there's no splash screen. (On my A1XE it starts in 5 seconds, and on my X1000 in like 3 seconds.)

The first you have to do is to allow the Java Twitter client to access your data.
Double click JAmigaTwitter.jar again. But this time, enter "auth" at the end of the input.

After running it this time, JAmiga Twitter will... well... its actually up to you to see what it'll do. But you will need to log into your Twitter account and give access to the "JAmigaTwotter" (sic!) client.

You can of course start the JAmiga from the Shell. You simply point to your JAR file from the java.script:

1.System:> JAmiga:java.script DH1:SillyApps/JAmigaTwitter.jar

With the client you can post status updates on your wall (or whatever it's called on Twitter), fetch your status (Ousp. Just noticed that you can't fetch your own status, some sort of bug), and do query searchs. The query search returns some sort of HTML, and searching for Amiga will only get you spanish people looking for girls.

Searching for geeky amiga stuff is hard...

What's next?

I will continue to update and improve JAmiga, as well as create some Java content. Even if I named this a silly release, I wanted to get it out there for you to test and play with. Hopefully all you Amiga Java coders will find it nice to play with. I will try to produce some tutorials on how to get started coding little Java applications. If you have questions, don't hesitate to ask me.

tisdag 25 juni 2013

Mauve tests, partial result

I thought I'd share the current status of my Mauve tests. I haven't had much time these last few days, but I have atleast a partial Mauve run:

TEST FAILED: 1 of 1 checks failed java.net.InetAddress.getCanonicalHostName
TEST PASSED (2 checks) java.net.InetAddress.getByName
TEST PASSED (14 checks) java.net.InetAddress.getByAddress
TEST PASSED (6 checks) java.net.InetAddress.getAllByName

TEST FAILED: 16 of 51 checks failed java.io.File.jdk11
TEST FAILED: 8 of 15 checks failed java.io.File.emptyFile
TEST PASSED (0 checks) java.io.File.createFile
TEST FAILED: uncaught exception java.io.File.canWrite
TEST PASSED (1 checks) java.io.DataOutputStream.writeUTF
TEST FAILED: 6 of 9 checks failed java.io.DataOutputStream.WriteRead2
TEST FAILED: 4 of 6 checks failed java.io.DataOutputStream.WriteRead
TEST FAILED: 6 of 6 checks failed java.io.DataInputStream.ReadReference2
TEST FAILED: 1 of 5 checks failed java.io.DataInputStream.ReadReference
TEST PASSED (37 checks) java.io.DataInputStream.readLine
TEST PASSED (2 checks) java.io.CharArrayWriter.ProtectedVars
TEST PASSED (4 checks) java.io.CharArrayWriter.BasicTests
TEST PASSED (1 checks) java.io.CharArrayReader.SimpleRead
TEST PASSED (4 checks) java.io.CharArrayReader.ProtectedVars
TEST PASSED (2 checks) java.io.CharArrayReader.OutOfBounds
TEST PASSED (4 checks) java.io.CharArrayReader.MarkReset
TEST PASSED (9 checks) java.io.ByteArrayOutputStream.write
TEST PASSED (12 checks) java.io.ByteArrayOutputStream.subclass
TEST PASSED (1 checks) java.io.ByteArrayInputStream.SimpleRead
TEST PASSED (5 checks) java.io.ByteArrayInputStream.MarkReset
TEST PASSED (4 checks) java.io.ByteArrayInputStream.ProtectedVars
TEST PASSED (2 checks) java.io.BufferedWriter.Test
TEST PASSED (1 checks) java.io.BufferedReader.SimpleRead
TEST PASSED (2 checks) java.io.BufferedReader.MarkReset
TEST PASSED (19 checks) java.io.BufferedReader.mark
TEST PASSED (5 checks) java.io.BufferedReader.boundary
TEST PASSED (6 checks) java.io.BufferedOutputStream.interrupt
TEST PASSED (2 checks) java.io.BufferedOutputStream.Test
TEST PASSED (5 checks) java.io.BufferedInputStream.ProtectedVars
TEST PASSED (5 checks) java.io.BufferedInputStream.SimpleRead
TEST PASSED (2 checks) java.io.BufferedInputStream.Skip
TEST PASSED (1 checks) java.io.BufferedInputStream.ZeroRead
TEST PASSED (2 checks) java.io.FileDescriptor.jdk11
TEST PASSED (24 checks) java.io.BufferedInputStream.BigMark
TEST PASSED (2 checks) java.io.BufferedInputStream.Skip
TEST PASSED (9 checks) java.io.Reader.Test

TEST PASSED (5 checks) java.lang.Thread.getThreadGroup
TEST PASSED (57 checks) java.lang.Thread.priority
TEST PASSED (11 checks) java.lang.Thread.join
TEST PASSED (20 checks) java.lang.Thread.security10
TEST PASSED (8 checks) java.lang.Thread.name
TEST PASSED (4 checks) java.lang.Thread.isAlive
TEST FAILED: 24 of 27 checks failed java.lang.Thread.security
TEST PASSED (9 checks) java.lang.Thread.daemon
TEST PASSED (79 checks) java.lang.Thread.sleep
TEST FAILED: 3 of 21 checks failed java.lang.Thread.insecurity
TEST PASSED (7 checks) java.lang.Thread.contextClassLoader
TEST PASSED (11 checks) java.lang.Thread.interrupt
TEST FAILED: 3 of 6 checks failed java.lang.Thread.stop
TEST PASSED (2 checks) java.lang.ClassLoader.redefine
TEST PASSED (3 checks) java.lang.ClassLoader.Resources
TEST PASSED (13 checks) java.lang.ClassLoader.findLoadedClass
TEST PASSED (27 checks) java.lang.ClassLoader.BootDefinedPackages
TEST FAILED: 4 of 5 checks failed java.lang.ClassLoader.security
TEST PASSED (16 checks) java.lang.ClassLoader.loadClass
TEST PASSED (13 checks) java.lang.ClassLoader.initialize
TEST FAILED: 2 of 3 checks failed java.lang.SecurityManager.thread
TEST: java.lang.ProcessBuilder.simple

You can see there are some issues with the security manager stuff. The security is in this case security as in which classes in what contexts can execute certain sensitive or possibly dangerous methods. This involves stuff like not allowing everyone to call exitVM, or write to files, et cetera. There is also methods that are deprecated, and in JamVM does nothing, like java.lang.Thread.stop.

One more thing to note is that this is not a complete list, there are a few more I need to run, but the last failed test (not shown in list) actually locked the VM, so I had to break it (it was a well-behaved lock up, I could Ctrl-C it).

Other than Mauve testing I've begun to package a milestone 1 archive, which I hope to get done soon.

tisdag 18 juni 2013

I tawt I taw a putty tat

I just have to show you this tweet.

Isn't it like the best thing ever written in less than 140 characters?

Like you might have guessed, the tweet is tweeted from the oh-so elegant JAmigaTwitter console. Which evidently works.

Dare I say, just two more wee...?

I'm currently in the process of packaging things together in order to release a beta of JamVM, together with GNU Classpath 0.99 and a at least two demonstration programs. This will, as mentioned on the JAmiga bounty page allow AmigaOS 4 users to run Java 1.5, with the exception of GUI and other more advanced stuff. So, watch this space!

söndag 16 juni 2013

Some sort of success

This is getting annoying, but I do have had some success, just this very minute. Even though it doesn't work.

Now, what you see is my minimal Twitter console client. It works relatively straight forward, you get a link to open in your browser in order to authenticate the Twitter console. When you have logged in to Twitter, and authorized the application (currently named "Jamiga Twotter"), you get a PIN which you should enter into the console application.

An error indicating some sort of success

The result you can the see further down in the picture: Twitter responds with an error, saying that the REST API v1 is no longer active. So, it turns out, that the Twitter4J client I tried out is no longer supported. And this happened recently, in March 2013. I had my Twitter console application running nicely on another platform just the other day, so even though I probably should be a bit mad, I'm actually happy getting this error. Because this is a valid really great error! It means that what I've done, actually works. The JVM can communicate with outside servers, and he whole Twitter API parsing works. So this test actually proves that a lot of stuff is working.

Now, to the avail, the Twitter4J people (who's java implementation I'm using) are saying they've fixed it. So it look like I'm just an update and configuration away from having a working Twitter implementation on JAmiga.

Oh, and by the way, I also fixed the "double trouble" with converting doubles to strings.

lördag 15 juni 2013

Amiga paths

I eventually got some work done this week, but still not quite there. The problems regarding the reported file size was easily fixed, once I saw the error. It was a rather embarassing error. Apparantely the Java type "long" was defined as a 32 bit value, where Java wants a 64 bit type. Easily fixed, and kind of in the areas of what I thought was wrong. Following that fix, my current problem arise around opening file through the Java URL class, i.e. on the "file://SYS:s/startup-sequence"-form. I had the feeling this would come and bite me, sooner or later. GNU Classpath supports Unix and Windows paths, and it decides which system is in use by checking the file separator; if its backslash, its Windows, if it isn't we have Unix. A very pragmatic look, but not terribly allowing for other systems. I'm currently going through the Java class hierarchy to try and find where exactly it doesn't work, because in some cases it works, and in other cases JamVM is trying to reach volumes named "/SYS:".

So, I'm think I'll be able to solve this in the next week, and I can only hope I don't stumble upon some other big issues. I'm counting on minor issues, though. 

måndag 10 juni 2013

Slight delay

The deadline for the bounty is closing in on me. Sadly I won't have much time to work on it this week... so my fear is that the deadline will be delayed. Hopefully only a few days though.

My recent progress has surfaced a few specific issues I have to deal with prior releasing a beta version.

A piece of pie

One of the bounty goals is an SSH-client. The more simple telnet variant works, as can be seen in previous post. However, trying with SSH bubbles up an issue I'm well aware of, that I thought I could wait with. Converting the string "3.1415" to the actual value 3.1415, is actually performed in native code, meaning I need to implement the support for it. Its a rather complex amount of code, but luckily I don't have to do it myself since it has been taken care of in the GNU Classpath implementation. The existing code however doesn't compile out-of-the-box, so I have ignored it for now. I'm hoping this will only be a matter of hours fiddling with the existing source to make it compile in the Amiga environment. And then I'm hoping that the SSH client won't have anymore issues.

The file was how big?

One other issue, that I perhaps could get away without resolving immediately, is a strange issue with how classes are loaded by the JVM. Up until this point, all my classes have been residing in the bootclasspath, as opposed to the ordinary classpath. The bootclasspath should contain all classes needed for the JVM to start, and "user" classes, or rather, external thirdparty jars (for instance the SSH library, or the Twitter4J API) should reside in the ordinary classpath. The ordinary class loader uses Java code to load the classes while the bootclasspath loader uses native code. And there seems to be some issues with how my Amiga implementation reports the size of class files, because every time the JVM want's to allocate memory for the class to load, I get an OutOfMemory exception. Looking at my code and debugging, I really can't see where the size get messed up. The Amiga part correctly reports ordinary sizes, but on the Java side its almost as if using uninitialized variables, or some sort of unsigned/signed error.

Given enough time this week, I believe I could have solved these issues in time. However, my current workload and various after work meetings, minimize my JAmiga time to a value near zero.

måndag 20 maj 2013

A telnet-client in Java on AmigaOS 4.1

I'm happy to announce the first working usable application for Java on Amiga: a telnet-client.

What can be seen is the class "org.jamiga2.jta.JTAConsole" telnetting into my Mac. It's really slow at the moment, but that's due to the extensive logging, and currently my Mac's login credentials are hardcoded in the Java file. And when quitting, one of the Java processes crashes due to some memory I might be freeing too many times. But besides that: it's alive!

Now what?

What's left to do, is everything else. Fix the crash, try out real SSH, fix the client from proof-of-concept status into a real SSH client, and lots of other stuff. But it's really nice to see something usable actually running.

måndag 25 mars 2013

Islands in the streams

This just in!

Update: So, I thought my problems where with the error 209, ACTION_UNKNOWN seen below in a few logs. Not so. Tonight I just realized that I'm playing around with streams that don't support stuff like available() (natively using IDOS->GetFilePosition() and such), i.e. any streaming data with no real end, like STDIN. Like, duh... Anyhow. I've solved this by calling IDOS->IsInteractive() on the file handle prior calling any un-supported functions on it.

Now, this minor "progress" hasn't solved everything, it just renders much of yesterdays ramblings regarding processes interchanging streams invalid. Much is however still valid. I'll try to remove the false parts hastily.

Continuing my Mauve testing, I'm currently occupied in trying to get one process to read data from another process' streams. In the Java world it's really easy to just send an object to any other thread and do stuff with it. Not so much in the AmigaOS 4 world. It's much the same problem I had with the sockets, where each process executes in its own context, i.e. data stream pointers are actually just pointers to internal structures valid only in the current process context.

Problems described in the context of trying to tell something about how Java works

Now, I try to write these blogs with the mixed intent of giving a powerpointy overview in combination with gory tech-details that might spark the attention of Amiga and Java coders, and at the same time getting order to my own thoughts. I sometimes get stuck in complex explanations and an overall eager to combine words in long sentences without seemingly coming to any conclusion. Sometimes I just keep it short. The text today probably requires some degree of technical knowledge. Hopefully, I will have some more real-world usage stuff to talk about in later blogs.

Starting with how Mauve executes tests

The Mauve test suite works by spawning new processes for each test to perform. When you start a Mauve test run, Mauve starts another instance of JamVM, using a simple Runtime.getRuntime().exec("jamvm RunnerProcess test") call, which in Amiga native code is realized using IExec->SystemTags(). While the test JamVM instance is running, there are a few Mauve controller threads keeping track of the test suite processes, aborting any failed or long-running tests. These controller threads talks to the tests using simple "console redirection", i.e. one programs console output decides what will happen next; the controller threads are only loops checking for data on System.in (i.e. STDIN or IDOS->Input()) and performs various tasks depending on input.

A simplified Java code example can be seen below:

02    public static void main(String[] args) {
03        // Exec the other jamvm process and 
04        // set up in/out communications with it.
05        Process process = Runtime.getRuntime().
06                         exec("jamvm RunnerProcess test");
07        // Our controller thread keeping track of
08        // System.in actions
09        InputPiperThread pipe = 
10                 new InputPiperThread(
11                       System.in,
12                       process.getOutputStream());
13        // Start our InputPiperThread
14        pipe.start();
16        // Do other stuff here...
17        ...
18    }
19    private static class InputPiperThread extends Thread {
20        // The controller starts by executing run 
21        public void run() {            
22            do {
23                // Check what's available on 
24                // parent's System.in
25                if (in.available() < 0) {
26                    ch = in.read();
27                    ...
28                } else {
29                    Thread.sleep(200);
30                }
31            } while (ch != -1);
32        }
33        InputStream in;
34        OutputStream out;
35        InputPiperThread(InputStream i, OutputStream o) {
36            in = i;out = o;int ch = 0;
37        }
39    }

The problem -- so far

The problem I had was that call to in.available() on line 25 wasn't interrupted correctly -- it just kept on going on forever. I've simplified the code above, so you can't see that the main Mauve process will eventually try to kill the InputPipeThread, and this should lead to an exception halting the thread, ending the entire process. What I noticed, was that I could not read the data at all -- there was no data to be found, my input stream (in) is actually not even a valid input stream.

Investigation begins

Before I understood what was wrong I had to see how System.in eventually is mapped to IDOS->Input(). This info gives you a good look at what actually goes around in a Java Virtual Machine and its different parts. I have a nice screenshot of it:

  1. In the center of the picture you see the first step in java.lang.System where the actual reference to STDIN is (Java coders will certainly recognize System.in)
  2. You can see it is being statically initialized to VMSystem.makeStandardInputStream(), with VMSystem being the GNU Classpath specific VM native layer.
  3. There we wrap a FileDescriptor.in in a few buffered streams.
  4. FileDescription.in is a statically initialized and wrapped version of FileChannelImpl.in, which in turn is a statically initialized to the value of VMFileChannel.getStdIn().
  5. VMFileChannel.getStdIn() is finally where we get to the actual core of the poodle: stdin_fd().
  6. The stdin_fd() function is native, so in the last step we can see the utterly simple C counterpart (Amiga C coders will recognize this part): the actual call to IDOS->Input().
So, in summary, System.in is the file handle returned by IDOS->Input() wrapped in various Java fluff.

My first thought was that something was awry with the file handle. Looking through logs however showed it wasn't so. Then, remembering my socket problems I realized that I probably can't send one Amiga process's STDIN file handle to any other Amiga process with the same ease I can send data from one Java thread to the other.

Going back to the Mauve threads and processes:

In the picture above we see the first process (marked 1) spawning a new jamvm process (number 2 in the picture). We can also see the Mauve controller threads, 3 and 4, as started by process 1. What to notice here is that to the Amiga, all four boxes represent a unique Amiga DOS Process. However, in the Java virtual machine, process 1, 3 and 4 are regarded as equals all executing in one virtual machine able to share data without much fuss. Process 2 could from the Java viewpoint of process 1 actually be any Amiga native process, like SketchBlock, OWB or whatnot, but in this particular context happens to be another jamvm instance.

Where's the Grim Reaper?

Now, anyone who's been coding on AmigaOS 4 knows that the Grim Reaper will manifest itself if any process tries to mess with privately allocated data by another process. This is also true for sockets and data stream pointers (i.e. our file handle to STDIN as returned by IDOS->Input()), but without the Grim Reaper showing up, since the pointers are only identifiers easily detected by the API as non-valid data. Looking at the logs for one of my experiments clearly show this:

Level PID Message TRACE 260 Returning stdin: 19248530 DEBUG 260 Available for file 19248530 Input: 19248530 Output:19248630 DEBUG 271 Available for file 19248530 Input: 18271650 Output:18271550 ERROR 271 IoErro reading examine data: 209 (ACTION_UNKNOWN)

What you can see is the main jamvm process with ProcessID (PID) 260, returning a file handle to System.in, STDIN (19248530), to be handed over to the controller thread (PID 271). The next line is again process 260 successfully checking for available data on STDIN. And, on the third line you see the controller thread 271 trying the exact same thing, but on the fourth line evidently failing. (The numbers after Input and Output on the second and third line are what IDOS->Input/Output, returns in each process, just to be sure we have the pointer we want.)

And, the solution?

This perhaps doesn't come as a surprise to knowledgeable Amiga programmers (I'm also not surprised), but it does take a while to come to this conclusion given the number of things that can be wrong.

I haven't yet come to a solution, but i think it can involve using a PIPE:. Looking again at the Java example above, around line 12 we actually have a PIPE: in use under the bonnet:

05        Process process = Runtime.getRuntime().
06                         exec("jamvm RunnerProcess test");
07        // Our controller thread keeping track of
08        // System.in actions
09        InputPiperThread pipe = 
10                 new InputPiperThread(
11                       System.in,
12                       process.getOutputStream());
When getting the output and input stream from a Java spawned Amiga process I am already using Amiga pipes, and this works without problems. Now I only need to open a new PIPE: and then pipe the real IDOS->Input() to it. But I don't yet know how to do it.

tisdag 29 januari 2013

The colour Mauve

As briefly mentioned in my previous entry, trying anything more fancy than sending a little data over the network, causes JamVM to wildly crash. I've yet not found the reason for this, it only happens for one particular example (that I've come across) and I can't find any obvious cause for it. It happens right after JamVM has actually ended, and the crash is according to Grim Reaper caused by the process of name "", which milliseconds before was named "jamvm.exe". I'm guessing it has something to do with the C-library trying to close/free something that I've already freed, or something like that. One upside of this problem is that I finally got around to sorting out my issues regarding which C-library I'm using.

JamVM currently uses clib2

So, there, I've said it. Its in black and white. I'm using clib2, and I'm sticking to it. I find that I constantly ask myself about design decisions I've made, and wondering both when, and why I came up with a certain solution. I will not use newlib, for the simple reason that I just wrote that "JamVM currently uses clib2". The JNI libraries (java-net, java-io, etc) should preferably use no C-library, or clib2 when needed. Being libraries, we're not using the C-library startup code. Some libraries however dependes on the reference GNU Classpath implementation, which uses c-library functions. So, in some cases it is more convenient to use a C-library.

I'm not entirely one-hundred percent sure that you can mix different c-libraries in your shared libraries, but I really do not see why not. As long as you don't try to make them talk to each other by interchanging implementation specific handles like sockets or such. But I see no reason why one library calling clib2's printf should interfere with another library calling newlib's printf. Steven Solie has a few good pointers on AmigaOS 4 programming in general, and specifically for networking. He also mentions that clib2 is open-source, and therefore a good choice in terms of debugging options. Which I believe it will prove to be, if I don't stumble upon my problem by accident.

What about that colour?

My previously mentioned doodling with mauve (the test suite for JVM's) continues. Instead of hopelessly banging my head against the keyboard, I thought it wise to continue my mauve runnings. With that I might be able to pinpoint the cause of crash more accurately, instead of wading through hierarchies of Java classes. And that is also one step closer to finishing the bounty.

Note to self

Like I said, my memory fails me. So I thought I'd write down how I run mauve. And it isn't that complicated. I have a mauve installation on my DH1, and it's only a matter of putting it in the classpath to be able to run the "Harness" class. However, putting stuff in the classpath should be as easy as setting an environment variable. But clib2's getenv implementation only has a buffer size of 256 bytes, which means that my scattered long windling classpath doesn't fit. Instead of solving the problem, I hardcoded the classpath. Fugly. But it works. Anyhow, with that in place, starting mauve is as easy as:

jamvm.exe -vm=jamvm.exe Harness java.lang.String

The "java.lang.String" reference is the test to actually run. Not entering this will run all tests. Entering something like java.* will run anything in the "java" package.
Edit: Just remembered that you need to say which VM you want to test. If none is specified, it uses "java", which in my particular case will execute the original JAmiga VM, and not JamVM.

Finding bugs as we speak!

Trying to run mauve, and simultaneously writing this blog entry, I'm actually bumping over a bug of "getenv" in java.lang.VMSystem not being linked correctly. How coincidental. Which concludes my rambling for the night. Off to get that bug!

onsdag 16 januari 2013

Jamiga net fishing

I've had some more progress with the networking. Instead of boring you with text about it, I thought I'd show you a clip of the progress and give an insight in how a day coding JAmiga might look.


Well, its almost like that.

Anyhow, what the clip tries to illustrate is the Amiga running a Java program opening a server socket on port 7777, with my Mac telnetting to that port, and then exchanging a few strings. You can see a more academic documentary version below:

The current running network solution will most likely only work in single threaded environments, since using bsdsockets.library in multiple processes requires some extra care. My previous described "one-amiga-process-for-each-socket approach is currently disabled. There were other issues with that solution. I haven't yet decided how to do it, but starting an extra process for each socket is really not a satisfying solution -- it can be sufficient to get past the obstacle, but in the long run its really not a good way to do it.

What's next?

Next, I'll focus on getting one of the Milestone 1 possible applications to work, namely the Telnet/SSH client. At the moment, the whole thing crashes wildly, but I'm assuming its a simple mistake I've made.