I've been battling with pthreads and signals. I couldn't seem to get Amiga processes and signaling system to function correctly using a simple pthread mapping. I should've figured this, since there is no simple pluginable replacement. There is the AmigaOS 4 pthread implementation, but it doesn't seem to take signals into consideration.
But, now, I've finally managed to get JamVM running and ending in non-crashable manner. I've basically implemented a lot of the pthread and signal functionality, with much regard taken toward adapting it to Amiga-JamVM interaction, rather than a all-purpose pthread re-implementation. I will commit these changes, and also post a blog with more details on my particular solutions sometime (I dare not add "in the near future", since that would probably be lying).
Threading dark alleys
What i now have running is JamVM, with its finalizer, signal handling and garbage collector processes. These JamVM's "utility threads" are Amiga processes, but I'm thinking of changing them to tasks instead, since they really don't do any DOS stuff, and can't be easily interrupted. Tasks can be removed with a simple RemoveTask(), whereas DOS processes has other stuff attached to it that needs closing. I am actually cheating on this point already, since I call abort() in the child processes, which newlib complains about (and actually decides to do a RemoveTask() on the processes -- I'm assuming this is a big memory leak). None the less, the overall functionality is there, practically without alterations to the original JamVM code base! I've tried to only add sources to the architecture and OS specific drawers. Only a few modifications has been made to JamVM, and I believe I'll be able to catch most of the special cases in the Amiga code.
Work continues with the classpath libraries
With JamVM finally running and producing stack traces, I can continue my work in adapting JAmiga's GNU classpath library implementation. I've found that some native reflection methods and fields aren't loaded correctly. I think/hope this is only a matter of better naming in the JAmiga libraries.
How does the native libraries work, anyway?
The native classpath libraries are implemented as ordinary Amiga libraries. This differs from how JamVM handle's dynamic libraries on other platforms. As I've previously mentioned, JamVM uses either *nix shared objects (.so) or Windows DLL. Both these can export actual function names, which Amiga libraries can't, at least not in the same way. Shortly put, when writing libraries, the actual function name can be exported, and looked up by whatever code wants to use them. A Java method that is executed in native code (i.e. written in C or similar), is looked up by a mangled name.
For instance, the isDirectory(String) method in class java.io.VMFile is in the DLL called Java_java_io_VMFile_isDirectory__Ljava_lang_String_2. This is handled dynamically by the VM, and it can try with various mangled name variants for the same method before deciding it doesn't exist. In a Windows DLL or .so object, it is enough to have a function called "Java_java_io_VMFile_isDirectory__Ljava_lang_String_2" and prefixed with an JNI_EXPORT define. For the JAmiga libraries, we must however create a mapping that defines the class and method as simple strings, and then make a manual lookup. This was the way the JAmiga libraries was implemented already. However, the JAmiga mangling scheme doesn't always adhere to the actual Java mangling standard. Sometimes the functions are mangled with the prefix "Jamiga_" instead of "Java_", and the signatures isn't always entirely correct. So, that is the next step: make sure all native methods are correclty mangled.