diff -urN glib-2.14.4.orig/armv6-test.c glib-2.14.4.atom/armv6-test.c
--- glib-2.14.4.orig/armv6-test.c	1970-01-01 02:00:00.000000000 +0200
+++ glib-2.14.4.atom/armv6-test.c	2008-01-07 16:17:40.000000000 +0200
@@ -0,0 +1,55 @@
+/*
+
+    Test for ARMv6 instruction set support.
+
+*/
+
+/* this test breaks the POSIX rules on setjmp()/longjmp() a bit, but it
+ * happens to work
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+
+void set (volatile int *atomic, int newval)
+{
+  unsigned long result;
+
+  do {
+    asm volatile (
+      "ldrex %0, [%1]\n"
+      "strex %0, %2, [%1]\n"
+      : "=&r" (result)
+      : "r" (atomic), "r" (newval)
+      : "cc", "memory");
+  } while (result);
+}
+
+static jmp_buf errjmp;
+
+void sig_handler (int signo)
+{
+	switch (signo)
+	{
+		case SIGILL:
+			longjmp(errjmp, 1);
+			break;
+	}
+}
+	
+int main (int argc, char *argv[])
+{
+	volatile int a;
+
+	signal(SIGILL, sig_handler);
+	if (setjmp(errjmp) == 0)
+	{
+		set(&a, 7);
+		return 0;
+	}
+	signal(SIGILL, SIG_DFL);
+
+	return 1;
+}
+
diff -urN glib-2.14.4.orig/configure.in glib-2.14.4.atom/configure.in
--- glib-2.14.4.orig/configure.in	2007-11-24 08:41:02.000000000 +0200
+++ glib-2.14.4.atom/configure.in	2007-12-17 11:29:29.000000000 +0200
@@ -2111,9 +2111,32 @@
       ;;	
     arm*)
       AC_MSG_RESULT([arm])
-      AC_DEFINE_UNQUOTED(G_ATOMIC_ARM, 1,
-                         [arm atomic implementation])
-      glib_memory_barrier_needed=no
+      AC_MSG_CHECKING(arm atomic operations type)
+      if test x$glib_os_linux != xyes; then
+        AC_MSG_RESULT(inline asm)
+        glib_save_CFLAGS=$CFLAGS
+        AC_MSG_CHECKING(architecture supports ARMv6 instructions)
+          cp $srcdir/armv6-test.c conftest.$ac_ext
+          CFLAGS="$CFLAGS -march=armv6"
+          AC_TRY_RUN(ac_compile,
+            [AC_DEFINE_UNQUOTED(G_ATOMIC_ARM, 6,
+                                [armv6 atomic implementation])
+             glib_memory_barrier_needed=yes
+             add_flags="-march=armv6"
+             AC_MSG_RESULT(armv6)],
+            [AC_DEFINE_UNQUOTED(G_ATOMIC_ARM, 1,
+                                [arm atomic implementation])
+             glib_memory_barrier_needed=no
+             add_flags=""
+             AC_MSG_RESULT(pre-armv6)])
+        CFLAGS=$glib_save_CFLAGS
+        CFLAGS="$CFLAGS $add_flags"
+      else
+        AC_MSG_RESULT(kernel helper)
+        AC_DEFINE_UNQUOTED(G_ATOMIC_ARM_LINUX, 1,
+                           [special arm linux implementation])
+        glib_memory_barrier_needed=yes
+      fi
       ;;
     *)
       AC_MSG_RESULT([none])
diff -urN glib-2.14.4.orig/glib/gatomic.c glib-2.14.4.atom/glib/gatomic.c
--- glib-2.14.4.orig/glib/gatomic.c	2007-11-24 08:40:59.000000000 +0200
+++ glib-2.14.4.atom/glib/gatomic.c	2007-12-17 11:27:44.000000000 +0200
@@ -21,12 +21,12 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include "config.h"
+
 #if defined (G_ATOMIC_ARM)
 #include <sched.h>
 #endif
 
-#include "config.h"
-
 #include "glib.h"
 #include "gthreadprivate.h"
 #include "galias.h"
@@ -561,6 +561,7 @@
 #    error "Your system has an unsupported pointer size"
 #  endif /* GLIB_SIZEOF_VOID_P */
 # elif defined (G_ATOMIC_ARM)
+#  if (G_ATOMIC_ARM < 6)
 static volatile int atomic_spin = 0;
 
 static int atomic_spin_trylock (void)
@@ -651,7 +652,190 @@
 
   return result;
 }
-# else /* !G_ATOMIC_ARM */
+#  else /* G_ATOMIC_ARM < 6 */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+			       gint           val)
+{
+  unsigned long result;
+  int old, tmp;
+
+  do {
+    asm volatile (
+      "ldrex %0, [%3]\n"
+      "add %1, %0, %4\n"
+      "strex %2, %1, [%3]\n"
+      : "=&r" (old), "=&r" (tmp), "=&r" (result)
+      : "r" (atomic), "Ir" (val)
+      : "cc", "memory");
+  } while (result);
+  return old;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+		  gint           val)
+{
+  unsigned long result;
+  int tmp;
+
+  do {
+    asm volatile (
+      "ldrex %0, [%2]\n"
+      "add %0, %0, %3\n"
+      "strex %1, %0, [%2]\n"
+      : "=&r" (tmp), "=&r" (result)
+      : "r" (atomic), "Ir" (val)
+      : "cc", "memory");
+  } while (result);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+				   gint           oldval, 
+				   gint           newval)
+{
+  unsigned long result;
+  int old;
+
+  asm volatile (
+    "ldrex %1, [%2]\n"
+    "mov %0, #0\n"
+    "teq %1, %3\n"
+    "strexeq %0, %4, [%2]\n"
+    : "=&r" (result), "=&r" (old)
+    : "r" (atomic), "Ir" (oldval), "r" (newval)
+    : "cc", "memory");
+  return (result) ? FALSE : TRUE;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+				       gpointer           oldval, 
+				       gpointer           newval)
+{
+  unsigned long result;
+  void *old;
+
+  asm volatile (
+    "ldrex %1, [%2]\n"
+    "mov %0, #0\n"
+    "teq %1, %3\n"
+    "strexeq %0, %4, [%2]\n"
+    : "=&r" (result), "=&r" (old)
+    : "r" (atomic), "Ir" (oldval), "r" (newval)
+    : "cc", "memory");
+  return (result) ? FALSE : TRUE;
+}
+
+gint
+g_atomic_int_get (volatile gint *atomic)
+{
+  return *atomic;
+}
+
+void
+g_atomic_int_set (volatile gint *atomic,
+                  gint           newval)
+{
+  unsigned long result;
+
+  do {
+    asm volatile (
+      "ldrex %0, [%1]\n"
+      "strex %0, %2, [%1]\n"
+      : "=&r" (result)
+      : "r" (atomic), "r" (newval)
+      : "cc", "memory");
+  } while (result);
+}
+
+gpointer
+g_atomic_pointer_get (volatile gpointer *atomic)
+{
+  return *atomic;
+}   
+
+void
+g_atomic_pointer_set (volatile gpointer *atomic,
+                      gpointer           newval)
+{
+  unsigned long result;
+
+  do {
+    asm volatile (
+      "ldrex %0, [%1]\n"
+      "strex %0, %2, [%1]\n"
+      : "=&r" (result)
+      : "r" (atomic), "r" (newval)
+      : "cc", "memory");
+  } while (result);
+}
+#  endif /* G_ATOMIC_ARM < 6 */
+# elif defined(G_ATOMIC_ARM_LINUX)
+/* use special helper functions provided by the linux kernel */
+
+typedef void (_khelper_barrier_t)(void);
+#define _khelper_barrier (*(_khelper_barrier_t *)0xffff0fa0)
+/*#define G_ATOMIC_MEMORY_BARRIER _khelper_barrier()*/
+/* scratchbox/qemu explodes on barrier */
+#define G_ATOMIC_MEMORY_BARRIER while(0)
+typedef int (_khelper_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
+#define _khelper_cmpxchg (*(_khelper_cmpxchg_t *)0xffff0fc0)
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+			       gint           val)
+{
+  int result;
+  int old, new;
+
+  do {
+    old = *atomic;
+    new = old + val;
+    result = _khelper_cmpxchg(old, new, atomic);
+  } while (result);
+  return old;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+		  gint           val)
+{
+  int result;
+  int old, new;
+
+  do {
+    old = *atomic;
+    new = old + val;
+    result = _khelper_cmpxchg(old, new, atomic);
+  } while (result);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+				   gint           oldval, 
+				   gint           newval)
+{
+  int result;
+
+  result = _khelper_cmpxchg(oldval, newval, atomic);
+  return (result) ? FALSE : TRUE;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+				       gpointer           oldval, 
+				       gpointer           newval)
+{
+  int result;
+
+  result = _khelper_cmpxchg(*((int *) &oldval),
+                            *((int *) &newval),
+                            (int *) atomic);
+  return (result) ? FALSE : TRUE;
+}
+# else /* !G_ATOMIC_ARM_LINUX */
 #  define DEFINE_WITH_MUTEXES
 # endif /* G_ATOMIC_IA64 */
 #else /* !__GNUC__ */
@@ -831,8 +1015,8 @@
   *atomic = newval;
   g_mutex_unlock (g_atomic_mutex);
 }
-#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */   
-#elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED)
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+#elif (defined(G_ATOMIC_OP_MEMORY_BARRIER_NEEDED) && !defined(G_ATOMIC_ARM))
 gint
 g_atomic_int_get (volatile gint *atomic)
 {
