about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-09-18 06:43:19 +0000
committerEric Wong <normalperson@yhbt.net>2010-09-18 06:59:53 +0000
commitc658a2be7355ceee72736cc17754022dc7abfa9f (patch)
tree7c0e91b92270eca19ba1344f1e666e2c4c98cb96
parent7a0bb1afb81da3c83f2cc59403826e1f855d3f0d (diff)
downloadraindrops-c658a2be7355ceee72736cc17754022dc7abfa9f.tar.gz
This allows non-GCC 4.x users to experience Raindrops.
-rw-r--r--TODO1
-rw-r--r--ext/raindrops/extconf.rb26
-rw-r--r--ext/raindrops/linux_inet_diag.c2
-rw-r--r--ext/raindrops/raindrops.c1
-rw-r--r--ext/raindrops/raindrops_atomic.h23
5 files changed, 51 insertions, 2 deletions
diff --git a/TODO b/TODO
index 6935888..33f360a 100644
--- a/TODO
+++ b/TODO
@@ -1,2 +1 @@
-* more portable atomics for non-GCC systems (libatomicops?)
 * pure Ruby version for non-forking servers
diff --git a/ext/raindrops/extconf.rb b/ext/raindrops/extconf.rb
index d637287..09d6e36 100644
--- a/ext/raindrops/extconf.rb
+++ b/ext/raindrops/extconf.rb
@@ -7,5 +7,31 @@ have_func('munmap', 'sys/mman.h') or abort 'munmap() not found'
 have_func("rb_struct_alloc_noinit")
 have_func('rb_thread_blocking_region')
 
+checking_for "GCC 4+ atomic builtins" do
+  src = <<SRC
+int main(int argc, char * const argv[]) {
+        volatile unsigned long i = 0;
+        __sync_add_and_fetch(&i, argc);
+        __sync_sub_and_fetch(&i, argc);
+        return 0;
+}
+SRC
+
+  if try_run(src)
+    $defs.push(format("-DHAVE_GCC_ATOMIC_BUILTINS"))
+    true
+  else
+    false
+  end
+end or have_header('atomic_ops.h') or abort <<-SRC
+
+libatomic_ops is required if GCC 4+ is not used.
+See http://www.hpl.hp.com/research/linux/atomic_ops/
+
+Users of Debian-based distros may run:
+
+  apt-get install libatomic-ops-dev
+SRC
+
 dir_config('raindrops')
 create_makefile('raindrops_ext')
diff --git a/ext/raindrops/linux_inet_diag.c b/ext/raindrops/linux_inet_diag.c
index 954a73c..2c2978b 100644
--- a/ext/raindrops/linux_inet_diag.c
+++ b/ext/raindrops/linux_inet_diag.c
@@ -144,7 +144,7 @@ static VALUE diag(void *ptr)
         } req;
         struct msghdr msg;
         const char *err = NULL;
-        unsigned seq = __sync_add_and_fetch(&g_seq, 1);
+        unsigned seq = ++g_seq; /* not atomic, rely on GVL for now */
         int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
 
         if (fd < 0)
diff --git a/ext/raindrops/raindrops.c b/ext/raindrops/raindrops.c
index eb4694e..4b6a773 100644
--- a/ext/raindrops/raindrops.c
+++ b/ext/raindrops/raindrops.c
@@ -3,6 +3,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <stddef.h>
+#include "raindrops_atomic.h"
 
 /*
  * most modern CPUs have a cache-line size of 64 or 128.
diff --git a/ext/raindrops/raindrops_atomic.h b/ext/raindrops/raindrops_atomic.h
new file mode 100644
index 0000000..fd5f23b
--- /dev/null
+++ b/ext/raindrops/raindrops_atomic.h
@@ -0,0 +1,23 @@
+/*
+ * use wrappers around libatomic-ops for folks that don't have GCC
+ * or a new enough version of GCC
+ */
+#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#include <atomic_ops.h>
+
+static inline unsigned long
+__sync_add_and_fetch(unsigned long *dst, unsigned long incr)
+{
+        AO_t tmp = AO_fetch_and_add((AO_t *)dst, (AO_t)incr);
+
+        return (unsigned long)tmp + incr;
+}
+
+static inline unsigned long
+__sync_sub_and_fetch(unsigned long *dst, unsigned long incr)
+{
+        AO_t tmp = AO_fetch_and_add((AO_t *)dst, (AO_t)(-(long)incr));
+
+        return (unsigned long)tmp - incr;
+}
+#endif /* HAVE_GCC_ATOMIC_BUILTINS */