common/code_environment.cc
common/dout.cc
common/signal.cc
- common/simple_spin.cc
common/Thread.cc
common/Formatter.cc
common/HTMLFormatter.cc
#include <sys/uio.h>
#include <limits.h>
+#include <atomic>
#include <ostream>
#define CEPH_BUFFER_ALLOC_UNIT (MIN(CEPH_PAGE_SIZE, 4096))
#define CEPH_BUFFER_APPEND_SIZE (CEPH_BUFFER_ALLOC_UNIT - sizeof(raw_combined))
#ifdef BUFFER_DEBUG
-static simple_spinlock_t buffer_debug_lock = SIMPLE_SPINLOCK_INITIALIZER;
+static std::atomic_flag buffer_debug_lock = ATOMIC_FLAG_INIT;
# define bdout { simple_spin_lock(&buffer_debug_lock); std::cout
# define bendl std::endl; simple_spin_unlock(&buffer_debug_lock); }
#else
unsigned len;
atomic_t nref;
- mutable simple_spinlock_t crc_spinlock;
+ mutable std::atomic_flag crc_spinlock = ATOMIC_FLAG_INIT;
map<pair<size_t, size_t>, pair<uint32_t, uint32_t> > crc_map;
explicit raw(unsigned l)
- : data(NULL), len(l), nref(0),
- crc_spinlock(SIMPLE_SPINLOCK_INITIALIZER)
+ : data(NULL), len(l), nref(0)
{ }
raw(char *c, unsigned l)
- : data(c), len(l), nref(0),
- crc_spinlock(SIMPLE_SPINLOCK_INITIALIZER)
+ : data(c), len(l), nref(0)
{ }
virtual ~raw() {}
+++ /dev/null
-// -*- 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>
-
-namespace {
-
-#if !defined(__i386__) && !defined(__x86_64__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__powerpc__) && !defined(__ppc__) && !defined(__s390__) && !defined(__s390x__)
-static uint32_t bar = 13;
-static uint32_t *foo = &bar;
-#endif
-
-void cpu_relax()
-{
-#if defined(__i386__) || defined(__x86_64__)
- asm volatile("pause");
-#elif defined(__arm__) || defined(__aarch64__)
- asm volatile("yield");
-#elif defined(__powerpc__) || defined(__ppc__)
- asm volatile("or 27,27,27");
-#elif defined(__s390__) || defined(__s390x__)
- asm volatile("": : :"memory");
-#else
- for (int i = 0; i < 100000; i++) {
- *foo = (*foo * 33) + 17;
- }
-#endif
-}
-
-} // namespace
-
-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;
- }
- cpu_relax();
- }
-}
-
-void simple_spin_unlock(simple_spinlock_t *lock)
-{
- __sync_bool_compare_and_swap(lock, 1, 0);
-}
#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 <atomic>
-#include <stdint.h>
+inline void simple_spin_lock(std::atomic_flag& lock)
+{
+ while(lock.test_and_set(std::memory_order_acquire))
+ ;
+}
-typedef uint32_t simple_spinlock_t;
+inline void simple_spin_unlock(std::atomic_flag& lock)
+{
+ lock.clear(std::memory_order_release);
+}
-#define SIMPLE_SPINLOCK_INITIALIZER 0
+inline void simple_spin_lock(std::atomic_flag *lock)
+{
+ simple_spin_lock(*lock);
+}
-void simple_spin_lock(simple_spinlock_t *lock);
-void simple_spin_unlock(simple_spinlock_t *lock);
+inline void simple_spin_unlock(std::atomic_flag *lock)
+{
+ simple_spin_unlock(*lock);
+}
#endif
#include "common/simple_spin.h"
+#include <future>
+
TEST(SimpleSpin, Test0)
{
- simple_spinlock_t lock0 = SIMPLE_SPINLOCK_INITIALIZER;
+ std::atomic_flag lock0 = ATOMIC_FLAG_INIT;
simple_spin_lock(&lock0);
simple_spin_unlock(&lock0);
}
-static simple_spinlock_t lock = SIMPLE_SPINLOCK_INITIALIZER;
+static std::atomic_flag lock = ATOMIC_FLAG_INIT;
static uint32_t counter = 0;
static void* mythread(void *v)
TEST(SimpleSpin, Test1)
{
+ counter = 0;
+ const auto n = 2000000U;
+
int ret;
pthread_t thread1;
pthread_t thread2;
ASSERT_EQ(ret, 0);
ret = pthread_join(thread2, NULL);
ASSERT_EQ(ret, 0);
- ASSERT_EQ(counter, 2000000U);
+ ASSERT_EQ(counter, n);
+
+
+ // Should also work with pass-by-reference:
+ // (Note that we don't care about cross-threading here as-such.)
+ counter = 0;
+ ASSERT_EQ(counter, 0);
+ async(std::launch::async, []() {
+ for(int i = 0; n != i; ++i) {
+ simple_spin_lock(lock);
+ counter++;
+ simple_spin_unlock(lock);
+ }
+ });
+ ASSERT_EQ(counter, n);
}
+