C# Actors with Akka 2.0 via IKVM .NET

Typesafe have released their second iteration of the amazing Akka actor framework. This was very exciting news to me, but unfortunately I can't really make any use of it professionally at the moment, as I have switched to C#/.NET for the current project I'm working on. So I have investigated the possibility of using the library in .NET, via IKVM. Guess what: I succeeded in executing various Akka samples in C#, opening up very interesting opportunities...


Here's how I did it. At first I tried to simply compile the akka-actors-2.0.jar into a DLL (using IKVM), using the following command, from within the Akka lib folder:


ikvmc -target:library -recurse:..\scala-library.jar akka-actors-2.0.jar


This basically instructs the IKVM compiler to convert the JAR into a .NET DLL assembly and to use the Scala library JAR to lookup missing dependencies / classes. A number of IKVMC0100 warnings are shown, about multiple missing anonymous class files. This seems quite worrying (there were about 50+ warnings) but didn't seem to affect the end library! In actual fact the classes reported as missing are not part of the JAR, so this may be an IKVM bug...


The next step was to convert this "getting started with Akka" Java code into C#. This step was fairly trivial. I'm planning to attach the C# file here. (!TODO!)


The final step (I thought) was to run it. But little did I know that the fun was just starting! The application would crash with an NoSuchMethodException. The missing method is an interesting one, found in the sun.misc.* Java package:


sun.misc.Unsafe.park(...)


It seems that this method is used by a built-in JSR166 implementation, from within Akka. As you may know JSR166 is the codename for the Fork/Join concurrency framework, introduced in JDK 7.

By investigating and trying to find out more about this class, I've understood that it provides high-performance, but platform-Dependent, implementations of common threading operations, such as thread state manipulation, direct memory access, etc.


As I'm not very keen on submitting bug reports (the waiting gets to me), I've had a stab at implementing this method. Apparently, the LockSupport class in the java.util.concurrent.* package provides a non-native implementation.

So I downloaded the IKVM source code and located the Unsafe.java class (the one under openjdk/sun/misc, not the one under classpath/*). I added the following method, somewhere near the unpark() method:




public void park(boolean isAbsolute, long time) {
if (!isAbsolute) {
if(time > 0)
java.util.concurrent.locks.LockSupport.parkNanos(time);
}
else
{
if(time > java.lang.System.currentTimeMillis())
java.util.concurrent.locks.LockSupport.parkUntil(time);
}
}


Then I had to re-compile IKVM, which meant I had to download the necessary dependencies (just follow the very simple instructions in the IKVM README file, found in the source IKVM package). Basically that involved downloading NAnt 0.85, JDK7 and the stripped OpenJDK package that IKVM provide as part of their downloads (click "Browse all files" in SourceForge). Ah, also you have to add to your path environment variable all of these, then run the default NAnt target and you're done.

Retrying to execute the sample Akka application was again causing NoSuchMethodException, but progress had been made! This time another method was missing...


Long story short, there were another 3 methods missing, all from within the Unsafe class. Here's how I implemented them:



public void monitorEnter(java.lang.Object o)
{
java.util.concurrent.locks.ReentrantLock lck = null;
synchronized(lckmap)
{
int hash = o.hashCode();
if(!lckmap.containsKey(hash))
lckmap.put(hash, new java.util.concurrent.locks.ReentrantLock());

lck = (java.util.concurrent.locks.ReentrantLock) lckmap.get(hash);
}

lck.lock();
}
}


public boolean tryMonitorEnter(java.lang.Object o)
{
java.util.concurrent.locks.ReentrantLock lck = null;
synchronized(lckmap)
{
int hash = o.hashCode();
if(!lckmap.containsKey(hash))
lckmap.put(hash, new java.util.concurrent.locks.ReentrantLock());

lck = (java.util.concurrent.locks.ReentrantLock) lckmap.get(hash);
}

return lck.tryLock();
}


public void monitorExit(java.lang.Object o)
{
java.util.concurrent.locks.ReentrantLock lck = null;
synchronized(lckmap)
{
int hash = o.hashCode();
if(!lckmap.containsKey(hash))
lckmap.put(hash, new java.util.concurrent.locks.ReentrantLock());

lck = (java.util.concurrent.locks.ReentrantLock) lckmap.get(hash);
}

lck.unlock();
}




You also have to declare a shared map at the top of the file somewhere:


private static Map lckmap = new HashMap();


Before anyone starts pointing out the obvious, I know there is a lot to improve in this code. But this is a temporary solution. The reason for this is that we cannot use ConcurrentHashMap as the "lckmap" type, because it creates a cyclic dependency. The JDK7 ConcurrentHashMap uses the Unsafe class internally... I plan to improve this over the coming week, so that I submit a patch to IKVM for inclusion with their next release.

So final steps now. We have to re-compile IKVM and execute the ikvmc compiler to convert again now (see first step above). From within Visual Studio, just reference all the "Akka.NET" dependencies:


IKVM.OpenJDK.Core
IKVM.OpenJDK.Text
IKVM.OpenJDK.Util
IKVM.Runtime


And you're done. You can now use Akka from within your C# / .NET projects. Have fun! You should be able to download the full completed product here (!TODO!)


13 comments:

  1. I've added the four required Unsafe methods to IKVM.

    I'll also fix the spurious warnings, but that fix takes more time to properly test.

    BTW, the Scala compiler really does emit class constant pool entries to refer to these non-existing classes.

    Thanks,
    Jeroen

    ReplyDelete
  2. If you switch to using thread-pool-executor instead of fork-join you won't need to risk loading the ForkJoinPool

    ReplyDelete
  3. @Jeroen: Many thanks for adding these methods! I will try to optimise these a bit more and submit a patch if successful. As for the constant pool entries, I wasn't aware of that, so sorry for speculating that it was a bug, when it wasn't. Is it safe to ignore these warnings? The Akka samples work just fine so far...

    ReplyDelete
  4. @Viktor: How can I do this? And is it as performant as fork/join? Thanks.

    ReplyDelete
  5. http://doc.akka.io/docs/akka/2.0/scala/dispatchers.html

    ReplyDelete
  6. This comment has been removed by a blog administrator.

    ReplyDelete
  7. most desktops and laptops come back with Windows pre-installed when you buy them, and sometimes the Windows installation disc is not included. this is often the wbsite that provides that You only need to insert a bootable CD or USB drive besides up your Windows. This emergency boot disk for Windows seven will help else up any desktop and laptop.
    boot disk for windows 7

    ReplyDelete
  8. like the post...I appreciate you share it..

    Church Software

    ReplyDelete
  9. Im inspired with the exceptional and instructive contents that you provide in such short timing.
    www.c2logix.com/

    ReplyDelete
  10. Your work article, blogs I mean over all contents is must read stuff.
    c2logix.com

    ReplyDelete
  11. Recent times when net has so often gossip mongering and clog; your proportion really refreshes me.
    per head

    ReplyDelete
  12. You completely match our expectation and the variety of our information.website

    ReplyDelete
  13. Could you share the code for this? I have been trying to get akka running on IKVM in a .NET Console Application without success.

    Thanks,

    John

    ReplyDelete