From 6ed9a583314399ac435b25c90bbf0e65df13d842 Mon Sep 17 00:00:00 2001 From: Colin Patrick McCabe Date: Wed, 1 Jun 2011 09:35:30 -0700 Subject: [PATCH] Add simple_spin Add simple spinlock implementation that is safe to use from anywhere. Signed-off-by: Colin McCabe --- src/Makefile.am | 7 +++++++ src/common/simple_spin.cc | 43 +++++++++++++++++++++++++++++++++++++++ src/common/simple_spin.h | 39 +++++++++++++++++++++++++++++++++++ src/test/simple_spin.cc | 38 ++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 src/common/simple_spin.cc create mode 100644 src/common/simple_spin.h create mode 100644 src/test/simple_spin.cc diff --git a/src/Makefile.am b/src/Makefile.am index 12b804d09dd8..74aa67f26e42 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 000000000000..160b0fbb9cf7 --- /dev/null +++ b/src/common/simple_spin.cc @@ -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 +#include +#include + +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 index 000000000000..f2a8d78d9142 --- /dev/null +++ b/src/common/simple_spin.h @@ -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 + +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 index 000000000000..e7752658e744 --- /dev/null +++ b/src/test/simple_spin.cc @@ -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); +} -- 2.47.3