]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Add simple_spin
authorColin Patrick McCabe <cmccabe@alumni.cmu.edu>
Wed, 1 Jun 2011 16:35:30 +0000 (09:35 -0700)
committerColin Patrick McCabe <cmccabe@alumni.cmu.edu>
Fri, 3 Jun 2011 21:47:00 +0000 (14:47 -0700)
Add simple spinlock implementation that is safe to use from anywhere.

Signed-off-by: Colin McCabe <colin.mccabe@dreamhost.com>
src/Makefile.am
src/common/simple_spin.cc [new file with mode: 0644]
src/common/simple_spin.h [new file with mode: 0644]
src/test/simple_spin.cc [new file with mode: 0644]

index 12b804d09dd83aac9c0ec4744f2795dd01c88dfa..74aa67f26e42b40c03968889a94c3cccc918ab5e 100644 (file)
@@ -398,6 +398,11 @@ unittest_signals_LDADD = libceph.la ${UNITTEST_LDADD}
 unittest_signals_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
 check_PROGRAMS += unittest_signals
 
+unittest_simple_spin_SOURCES = test/simple_spin.cc
+unittest_simple_spin_LDADD = libceph.la ${UNITTEST_LDADD}
+unittest_simple_spin_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+check_PROGRAMS += unittest_simple_spin
+
 unittest_librados_SOURCES = test/librados.cc
 unittest_librados_LDFLAGS = -pthread ${AM_LDFLAGS}
 unittest_librados_LDADD = librados.la \
@@ -635,6 +640,7 @@ libcommon_files = \
        common/buffer.cc \
        common/code_environment.cc \
        common/signal.cc \
+       common/simple_spin.cc \
        common/Thread.cc \
        include/ceph_fs.cc \
        include/ceph_hash.cc \
@@ -806,6 +812,7 @@ noinst_HEADERS = \
         common/common_init.h\
        common/code_environment.h \
         common/signal.h\
+        common/simple_spin.h\
         common/dyn_snprintf.h\
         common/run_cmd.h\
        common/safe_io.h\
diff --git a/src/common/simple_spin.cc b/src/common/simple_spin.cc
new file mode 100644 (file)
index 0000000..160b0fb
--- /dev/null
@@ -0,0 +1,43 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "common/simple_spin.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <pthread.h>
+
+uint32_t bar = 13;
+uint32_t *foo = &bar;
+
+void simple_spin_lock(simple_spinlock_t *lock)
+{
+  while(1) {
+    __sync_synchronize();
+    uint32_t oldval = *lock;
+    if (oldval == 0) {
+      if (__sync_bool_compare_and_swap(lock, 0, 1))
+       return;
+    }
+    // delay
+    for (int i = 0; i < 100000; i++) {
+      *foo = (*foo * 33) + 17;
+    }
+  }
+}
+
+void simple_spin_unlock(simple_spinlock_t *lock)
+{
+  __sync_bool_compare_and_swap(lock, 1, 0);
+}
diff --git a/src/common/simple_spin.h b/src/common/simple_spin.h
new file mode 100644 (file)
index 0000000..f2a8d78
--- /dev/null
@@ -0,0 +1,39 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef CEPH_SIMPLE_SPIN_H
+#define CEPH_SIMPLE_SPIN_H
+
+/* This is a simple spinlock implementation based on atomic compare-and-swap.
+ * Like all spinlocks, it is intended to protect short, simple critical
+ * sections. It is signal-safe. Unlike pthread_spin_lock and friends, it has a
+ * static initializer so you can write:
+ *
+ * simple_spinlock_t my_spinlock = SIMPLE_SPINLOCK_INITIALIZER 
+ *
+ * This allows you to use the lock anywhere you want-- even in global
+ * constructors. Since simple_spinlock_t is a primitive type, it will start out
+ * correctly initialized.
+ */
+
+#include <stdint.h>
+
+typedef uint32_t simple_spinlock_t;
+
+#define SIMPLE_SPINLOCK_INITIALIZER 0
+
+void simple_spin_lock(simple_spinlock_t *lock);
+void simple_spin_unlock(simple_spinlock_t *lock);
+
+#endif
diff --git a/src/test/simple_spin.cc b/src/test/simple_spin.cc
new file mode 100644 (file)
index 0000000..e775265
--- /dev/null
@@ -0,0 +1,38 @@
+#include "gtest/gtest.h"
+
+#include "common/simple_spin.h"
+
+TEST(SimpleSpin, Test0)
+{
+  simple_spinlock_t lock0 = SIMPLE_SPINLOCK_INITIALIZER;
+  simple_spin_lock(&lock0);
+  simple_spin_unlock(&lock0);
+}
+
+static simple_spinlock_t lock = SIMPLE_SPINLOCK_INITIALIZER;
+static uint32_t counter = 0;
+
+static void* mythread(void *v)
+{
+  for (int j = 0; j < 1000000; ++j) {
+    simple_spin_lock(&lock);
+    counter++;
+    simple_spin_unlock(&lock);
+  }
+}
+
+TEST(SimpleSpin, Test1)
+{
+  int ret;
+  pthread_t thread1;
+  pthread_t thread2;
+  ret = pthread_create(&thread1, NULL, mythread, NULL);
+  ASSERT_EQ(ret, 0);
+  ret = pthread_create(&thread2, NULL, mythread, NULL);
+  ASSERT_EQ(ret, 0);
+  ret = pthread_join(thread1, NULL);
+  ASSERT_EQ(ret, 0);
+  ret = pthread_join(thread2, NULL);
+  ASSERT_EQ(ret, 0);
+  ASSERT_EQ(counter, 2000000);
+}