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


Linux Mint (Lisa) 1680 x 1050 resolution

By default (as I'm accustomed to with Linux distros) the very useful (to me) resolution of 1680 x 1050 (@60Hz) is not supported. This could be because the Samsung SyncMaster 22" is not a very popular monitor... Here's how to get it to work with Linux Mint 12 (codename Lisa)

Type the following on a terminal:

inxi -Gx

This should show your graphics card info, for example:

Graphics: Card: ATI RV670PRO [Radeon HD 3850] bus-ID: 01:00.0
X.Org 1.10.4 drivers ati, radeon unloaded: fbdev,vesa Resolution: 1024x768@60.0hz
GLX Renderer Gallium 0.4 on AMD RV670 GLX Version 2.1 Mesa 7.11 Direct Rendering Yes


Then type this:

xrandr

Running xrandr gives us a bunch of info about the currently supported resolutions. Note that 1680x1050 is not there:

Screen 0: minimum 320 x 200, current 1024 x 768, mximum 8192 x 8192
DVI-0 unknown connection (normal left inverted right x axis y axis)
1360x768 59.8
..................
320x240 120.1
DIN disconnected (normal left inverted right x axis y axis)
DVI-1 connected 1025x768+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
1024x768 60.0*
..................
640x480 59.9


Then type this:

cvt 1680 1050 60.0Hz

This establishes an X11 "modeline":

# 1680x1050 59.95 Hz (CVT 1.76MA) hsync: 65.29 kHz; pclk: 146.25 Mhz
Modeline "1680x1050_60.00" 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync


Now let's add this new mode:

xrandr --newmode @1680x1050_60.00@ 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync
xrandr --addmode DVI-1 @1680x1050_60.00@


Note: if you use CRT, you have to replace DVI-1 above.

That's it! Now you should have this new display resolution available under Menu -> System Tools -> System Settings -> Displays -> Resolution.

Enjoy the wonderful Linux Mint 12 experience :)