Atomic locking in Intel® 64 and IA-32 architectures

The Intel® 64 and IA-32 architecture guarantees atomicity if one of the following conditions are met

  • Reading or writing a byte
  • Reading or writing a word aligned on a 16-bit boundary
  • Reading or writing a double word aligned on a 32-bit boundary
So what does this mean ? It means that if we are clever about it, we can implement a simple lock using atomic reading and writing of a single byte.

The following function will use the XCHG instruction to swap two registers atomically, so all we have to do is give it the address to our locking variable and check the return value. If the value returned from the function is LOCKED it means that the thread was unable to acquire the lock. The beauty about this instruction is that if it is used to reference one general purpose register and a memory address, the processor bus locking protocol will be invoked causing the operation to become atomic.

The inline assembly statement might look daunting at first, but it is not really that complicated.

Per definition the structure of such an inline extended assembly statement is like this:

       asm ( assembler template 
           : output operands
           : input operands
           : list of clobbered registers
           );

The use of the operands is optional, and we do not use and clobbered registers in this statement, we trust the compiler to figure that out.

As you can see, we provide one output operand and two input operands. The output operand is the variable where we will store the previous value of the lock, and the variable that the caller uses to check if the lock was successfully acquired.

In input and output operands we can specify various constraints:

  • As you look at the “0″(value) operand, the “0″ is the constraint telling it that the value of this input operand is ONLY allowed to be stored in the 0th output variable, which is the output variable value.
  • The “a” constraint of address specifies that the value should be stored in the EAX register.
  • The “=b” constraint of the output operand specifies that this value should be read from EBX, and the operand is write-only.
#define LOCKED   = 1
#define UNLOCKED = 0
 
static int test_and_set(int *address)
{
	int value = LOCKED;
	asm volatile ("xchg (%%eax), %%ebx"
		      :"=b" (value)
		      :"0"(value), "a"(address));
	return value;
}

So there we have it, essentially this says “Take the memory address given in the address variable and store the value given in the value variable in it, while putting the previous content of that memory address into the value variable when done.”

When the caller checks the returned value, if the value is LOCKED it will know that the lock was already taken, and if the value is UNLOCKED it will know that the previous value was unlocked, thus the locked has now been taken.

IBM Active Protection System


Playing around on my thinkpad, I discovered that the HDAPS system can be used to do more than just protect your hard drive in case of a fall.

The following application displays a 3D model of a cube representing the monitored laptop, a server running on that laptop is sending real-time updates using information it gets from the IBM Hard Drive Active Protection System (HDAPS). This allows a remote client to monitor the movement of the laptop. The application itself is not very impressive, but I included a screenshot anyway.

Hooking up to the input subsystem through JNI

Making raw input data available to Java3D through the use of JNI. The device is a 3dConnexion Space Navigator, it registers itself as an event device through the input subsystem.

Our Java class

class ReadFile {
    native static int[] readEvent();
 
    //Load the library
    static {
        System.loadLibrary("nativelib");
    }
 
    public static void main(String args[]) {
        while(true){
            int event[] = new ReadEvents().readEvent();
            System.out.print("Event: ("+event.length+" bytes): ");
            for(int b: event)
                System.out.print(new Integer(b) + " ");
                System.out.println();
        }
    }
}

The Makefile used to build the shared library

CC=gcc
JC=javac
JH=javah
 
CFLAGS= -shared -Wall
INCLUDEPATH= \
     -I/usr/lib/jvm/java-6-sun-1.6.0.16/include/ \
     -I/usr/lib/jvm/java-6-sun-1.6.0.16/include/linux
 
all:
$(JC) ReadEvents.java
$(JH) ReadEvents
$(CC) $(CFLAGS) -o libnativelib.so $(INCLUDEPATH) events.c

This is really all the C code we need to pass the axes array

#define EVENTNODE "/dev/input/event6"
 
int axes[6] = {0,0,0,0,0,0};
int btns[2] = {0,0};
int fd = 0;
 
JNIEXPORT jintArray JNICALL Java_ReadEvents_readEvent(
    JNIEnv* env, jclass cl)
{
        if(fd == 0){
                fd = open(EVENTNODE , O_RDONLY);
        }
        struct input_event ev;
        read(fd, &ev, sizeof(struct input_event));
 
        switch (ev.type){
                        case EV_KEY:
                                btns[ev.code] = ev.value;
                                break;
                        case EV_REL:
                                axes[ev.code] = ev.value;
                                break;
        }
        jintArray jb;
        jb = (*env)->NewIntArray(env, 6);
        (*env)->SetIntArrayRegion(env, jb, 0, 6, (jint *)axes);
        return (jb);
}

SmartGWT Custom Events

Ok, so working with the SmartGWT framework on top of Google Web Toolkit. The goal was to fire a custom even from a ToolStrip when one of its members fired a ClickEvent.

This is relatively easily accomplished by subclassing ToolStrip and implementing the HasDataChangedHandlers interface. The only thing that took a bit of time to figure out was that I needed to use the SmartGWT function doAddHandler in BaseWidget instead of the GWT addHandler method in order to properly register the handler with the HandlerManager

Main Class

package test.client;
 
import com.google.gwt.core.client.EntryPoint;
import com.smartgwt.client.data.events.DataChangedEvent;
import com.smartgwt.client.data.events.DataChangedHandler;
 
public class CustomEvents implements EntryPoint {
    public void onModuleLoad() {
        MyStrip t = new MyStrip();
        t.addDataChangedHandler(new DataChangedHandler() {
            @Override
            public void onDataChanged(DataChangedEvent event) {
                // Handle the event here
            }
        });
        t.test();
    }
}

Subclassed ToolStrip

package test.client;
 
import com.google.gwt.event.shared.HandlerRegistration;
import com.smartgwt.client.data.events.DataChangedEvent;
import com.smartgwt.client.data.events.DataChangedHandler;
import com.smartgwt.client.data.events.HasDataChangedHandlers;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
 
public class MyStrip extends ToolStrip implements HasDataChangedHandlers {
 
    public void test() {
        fireEvent(new DataChangedEvent(this.getJsObj()));
    }
 
    @Override
    public HandlerRegistration addDataChangedHandler(DataChangedHandler handler) {
        return doAddHandler(handler, DataChangedEvent.getType());
    }
}