Skip to content

Commit ec0d238

Browse files
committed
Initial
0 parents  commit ec0d238

File tree

21 files changed

+483
-0
lines changed

21 files changed

+483
-0
lines changed

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.cppsm/.clang-format

.cppsm

Submodule .cppsm added at ea2cd9a

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.cppsm/.gitignore

.gitmodules

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[submodule ".cppsm"]
2+
path = .cppsm
3+
url = https://github.com/cppsm/cppsm-boilerplate.git
4+
branch = master
5+
[submodule "requires/polyfill.cpp/v1"]
6+
path = requires/polyfill.cpp/v1
7+
url = https://github.com/per-framework/polyfill.cpp.git
8+
branch = v1
9+
[submodule "equipment/testing.cpp/v1"]
10+
path = equipment/testing.cpp/v1
11+
url = https://github.com/per-framework/testing.cpp.git
12+
branch = v1
13+
[submodule "requires/intrinsics.cpp/v1"]
14+
path = requires/intrinsics.cpp/v1
15+
url = https://github.com/per-framework/intrinsics.cpp.git
16+
branch = v1
17+
[submodule "requires/dumpster.cpp/v1"]
18+
path = requires/dumpster.cpp/v1
19+
url = https://github.com/per-framework/dumpster.cpp.git
20+
branch = v1
21+
[submodule "requires/lax.cpp/v1"]
22+
path = requires/lax.cpp/v1
23+
url = https://github.com/per-framework/lax.cpp.git
24+
branch = v1

.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.cppsm/.prettierrc

.travis.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
language: cpp
2+
3+
notifications:
4+
email: false
5+
6+
matrix:
7+
include:
8+
- os: linux
9+
dist: trusty
10+
addons:
11+
apt:
12+
sources:
13+
- ubuntu-toolchain-r-test
14+
- llvm-toolchain-trusty-7
15+
packages:
16+
- g++-8
17+
- clang-7
18+
- os: osx
19+
osx_image: xcode10.2
20+
- os: windows
21+
22+
git:
23+
submodules: false
24+
25+
before_install:
26+
- git submodule update --init
27+
28+
script:
29+
- .cppsm/travis-ci || ./test

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cmake_minimum_required(VERSION 3.9)
2+
include(.cppsm/c++17-no-rtti-no-exns.cmake)

LICENSE.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Copyright © 2019 Vesa Karvonen
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
this software and associated documentation files (the "Software"), to deal in
5+
the Software without restriction, including without limitation the rights to
6+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+
the Software, and to permit persons to whom the Software is furnished to do so,
8+
subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# [](#contents) [RDCSS.C++](#) [![Build Status](https://travis-ci.org/per-framework/rdcss.cpp.svg?branch=v1)](https://travis-ci.org/per-framework/rdcss.cpp)
2+
3+
[RDCSS](https://www.cl.cam.ac.uk/research/srg/netos/papers/2002-casn.pdf) based
4+
multi-word compare-and-swap for C++.
5+
6+
## <a id="contents"></a> [](#contents) [Contents](#contents)
7+
8+
- [References](#references)
9+
10+
## <a id="references"></a> [](#contents) [References](#references)
11+
12+
- [A Practical Multi-Word Compare-and-Swap Operation](https://www.cl.cam.ac.uk/research/srg/netos/papers/2002-casn.pdf)
13+
- [Lock-Free Linked Lists Using Compare-and-Swap](http://people.csail.mit.edu/bushl2/rpi/portfolio/lockfree-grape/documents/lock-free-linked-lists.pdf)
14+
- [Easy Lock-Free Indexing in Non-Volatile Memory](http://justinlevandoski.org/papers/mwcas.pdf)
15+
- [Persistent Multi-Word Compare-and-Swap (PMwCAS) for NVRAM](https://github.com/Microsoft/pmwcas)
16+
- [A Practical Wait-Free Multi-Word Compare-and-Swap Operation](https://www.osti.gov/servlets/purl/1110662)
17+
- [Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors](http://web.mit.edu/6.173/www/currentsemester/readings/R06-scalable-synchronization-1991.pdf)
18+
- [Reagents: expressing and composing fine-grained concurrency](http://aturon.github.io/academic/reagents.pdf)
19+
- [`std::atomic`](https://en.cppreference.com/w/cpp/atomic/atomic)

equipment/testing.cpp/v1

Submodule v1 added at 7aeb198

internals/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_conventional_executable_test(rdcss_test)
2+
target_link_libraries(rdcss_test PRIVATE rdcss_v1 testing_v1)

internals/testing/test.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "rdcss_v1/casn.hpp"
2+
3+
#include "testing_v1/test.hpp"
4+
5+
using namespace testing_v1;
6+
7+
auto test_casn = test([]() {
8+
using namespace rdcss_v1;
9+
10+
auto i = CASN::atom(101);
11+
auto b = CASN::atom(false);
12+
CASN::store(b, true);
13+
verify(CASN::load(i) == 101);
14+
verify(CASN::load(b) == true);
15+
16+
verify(!CASN::casn(CASN::op(i, 101, 69), CASN::op(b, false, true)));
17+
verify(CASN::load(i) == 101);
18+
verify(CASN::load(b) == true);
19+
20+
verify(CASN::casn(CASN::op(i, 101, 69), CASN::op(b, true, false)));
21+
verify(CASN::load(i) == 69);
22+
verify(CASN::load(b) == false);
23+
});

provides/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_conventional_library(rdcss_v1)
2+
target_link_libraries(rdcss_v1 PUBLIC dumpster_v1 polyfill_v1 lax_v1 PRIVATE intrinsics_v1)

provides/include/rdcss_v1/casn.hpp

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#pragma once
2+
3+
#include "rdcss_v1/casn_synopsis.hpp"
4+
#include "rdcss_v1/config.hpp"
5+
6+
#include "lax_v1/comparison.hpp"
7+
#include "lax_v1/logical.hpp"
8+
#include "lax_v1/type_traits.hpp"
9+
10+
#include <atomic>
11+
#include <cstdint>
12+
#include <type_traits>
13+
#include <utility>
14+
15+
namespace rdcss_v1 {
16+
17+
class CASN_private : CASN {
18+
friend struct CASN;
19+
20+
template <class Value>
21+
struct is_stored_plain_m
22+
: lax::or_m<
23+
lax::and_m<
24+
lax::is_pointer_m<Value>,
25+
lax::lte_m<lax::value_t<size_t, 2>,
26+
lax::alignment_of_m<lax::remove_pointer_m<Value>>>>,
27+
lax::and_m<lax::is_array_m<Value>,
28+
is_stored_plain_m<lax::remove_all_extents_m<Value>>>> {};
29+
30+
template <class Value>
31+
static inline constexpr bool is_stored_plain_v =
32+
lax::value_of_v<is_stored_plain_m<lax::type_t<Value>>>;
33+
34+
static_assert(!is_stored_plain_v<int>);
35+
static_assert(is_stored_plain_v<int *>);
36+
static_assert(is_stored_plain_v<int * [2]>);
37+
static_assert(is_stored_plain_v<float * [2]>);
38+
static_assert(!is_stored_plain_v<float>);
39+
40+
static inline constexpr size_t align_to(size_t alignment, size_t size) {
41+
return (size + alignment - 1) & ~(alignment - 1);
42+
}
43+
44+
using elem_t = std::atomic<void *>;
45+
46+
template <class Value>
47+
static inline constexpr size_t num_elems_for =
48+
align_to(sizeof(elem_t),
49+
sizeof(Value) * (is_stored_plain_v<Value> ? 1 : 2)) /
50+
sizeof(elem_t);
51+
52+
template <class Value> struct atom_t {
53+
private:
54+
elem_t elems[num_elems_for<Value>];
55+
};
56+
};
57+
58+
class CASN_detail : CASN {
59+
friend struct CASN;
60+
61+
struct atom_base_t;
62+
63+
struct content_t;
64+
enum type_t : int_fast8_t;
65+
66+
template <class Value> struct value_t;
67+
68+
enum status_t : int_fast8_t;
69+
struct rdcss_t;
70+
struct casn_t;
71+
72+
static content_t *cas1(atom_base_t &atom, content_t *expected,
73+
content_t *desired);
74+
75+
static bool is_rdcss(content_t *content);
76+
static content_t *rdcss(rdcss_t &descriptor);
77+
static void rdcss_complete(atom_base_t &atom, rdcss_t &descriptor);
78+
static content_t *rdcss_read(atom_base_t &atom);
79+
80+
static bool is_casn(content_t *content);
81+
static bool casn(casn_t &descriptor);
82+
static content_t *casn_read(atom_base_t &atom);
83+
};
84+
85+
} // namespace rdcss_v1
86+
87+
struct rdcss_v1::CASN_detail::atom_base_t {
88+
std::atomic<content_t *> content;
89+
};
90+
91+
//
92+
93+
enum rdcss_v1::CASN_detail::type_t : int_fast8_t { RDCSS = -1, VALUE, CASN };
94+
95+
struct rdcss_v1::CASN_detail::content_t {
96+
type_t type;
97+
};
98+
99+
enum rdcss_v1::CASN_detail::status_t : int_fast8_t {
100+
FAILED = -1,
101+
UNDECIDED,
102+
SUCCEEDED
103+
};
104+
105+
struct rdcss_v1::CASN_detail::rdcss_t : content_t {
106+
std::atomic<status_t> &status; // UNDECIDED expected
107+
atom_base_t &atom;
108+
content_t *expected;
109+
content_t *desired;
110+
};
111+
112+
struct rdcss_v1::CASN_detail::casn_t : content_t {
113+
std::atomic<status_t> status;
114+
op_mono_t *ops;
115+
};
116+
117+
struct rdcss_v1::CASN::op_mono_t {
118+
CASN_detail::atom_base_t *atom;
119+
CASN_detail::content_t *before;
120+
CASN_detail::content_t *after;
121+
};
122+
123+
template <class Value> struct rdcss_v1::CASN_detail::value_t : content_t {
124+
value_t(Value &&value) : content_t{VALUE}, value(std::move(value)) {}
125+
value_t(const Value &value) : content_t{VALUE}, value(value) {}
126+
// TODO ref count?
127+
Value value;
128+
};
129+
130+
//
131+
132+
template <class Value>
133+
struct rdcss_v1::CASN::atom_t : CASN_detail::atom_base_t {};
134+
135+
template <class Value>
136+
rdcss_v1::CASN::atom_t<std::remove_cvref_t<Value>>
137+
rdcss_v1::CASN::atom(Value &&value) {
138+
return {{new CASN_detail::value_t<std::remove_cvref_t<Value>>(
139+
std::forward<Value>(value))}};
140+
}
141+
142+
template <class Value> Value rdcss_v1::CASN::load(const atom_t<Value> &atom) {
143+
CASN_detail::content_t *result =
144+
CASN_detail::casn_read(const_cast<atom_t<Value> &>(atom));
145+
return static_cast<CASN_detail::value_t<Value> *>(result)->value;
146+
}
147+
148+
template <class Value, class Forwardable_Value>
149+
void rdcss_v1::CASN::store(atom_t<Value> &atom, Forwardable_Value &&value) {
150+
CASN_detail::value_t<Value> *desired =
151+
new CASN_detail::value_t<Value>(std::forward<Forwardable_Value>(value));
152+
while (true) {
153+
CASN_detail::content_t *expected = CASN_detail::casn_read(atom);
154+
if (expected == CASN_detail::cas1(atom, expected, desired))
155+
break;
156+
}
157+
}
158+
159+
//
160+
161+
template <class Value> struct rdcss_v1::CASN::op_t : op_mono_t {};
162+
163+
template <class Value, class Forwardable_Expected, class Forwardable_Desired>
164+
rdcss_v1::CASN::op_t<Value> rdcss_v1::CASN::op(atom_t<Value> &atom,
165+
Forwardable_Expected &&expected,
166+
Forwardable_Desired &&desired) {
167+
CASN_detail::content_t *before = CASN_detail::casn_read(atom);
168+
CASN_detail::content_t *after = nullptr;
169+
if (expected == static_cast<CASN_detail::value_t<Value> *>(before)->value) {
170+
after = new CASN_detail::value_t<Value>(
171+
std::forward<Forwardable_Desired>(desired));
172+
} else {
173+
before = nullptr;
174+
}
175+
return {op_mono_t{&atom, before, after}};
176+
}
177+
178+
template <class Value>
179+
rdcss_v1::CASN::op_mono_t rdcss_v1::CASN::as_mono(op_t<Value> &op) {
180+
return op;
181+
}
182+
183+
template <class... Ops> bool rdcss_v1::CASN::casn(Ops &&... ops) {
184+
op_mono_t mono_ops[] = {std::forward<Ops>(ops)...,
185+
{nullptr, nullptr, nullptr}};
186+
return casn(mono_ops);
187+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#pragma once
2+
3+
#include "polyfill_v1/type_traits.hpp"
4+
5+
namespace rdcss_v1 {
6+
7+
// Multi-word atomic compare and set (CASN)
8+
struct CASN {
9+
// Mutable atoms -------------------------------------------------------------
10+
11+
template <class Value> struct atom_t;
12+
// A mutable atom that supports CASN operations.
13+
14+
template <class Value>
15+
static atom_t<std::remove_cvref_t<Value>> atom(Value &&value);
16+
// Creates a mutable atom.
17+
18+
template <class Value> static Value load(const atom_t<Value> &atom);
19+
// Atomically loads and returns the current value of the atom.
20+
21+
template <class Value, class Forwardable_Value>
22+
static void store(atom_t<Value> &atom, Forwardable_Value &&desired);
23+
// Atomically replaces the value of the atom with the desired value.
24+
25+
// Typed CASN ----------------------------------------------------------------
26+
27+
template <class Value> struct op_t;
28+
// Describes a single CAS operation.
29+
30+
template <class Value, class Forwardable_Expected, class Forwardable_Desired>
31+
static op_t<Value> op(atom_t<Value> &atom, Forwardable_Expected &&expected,
32+
Forwardable_Desired &&desired);
33+
// Specifies a single CAS operation.
34+
35+
template <class... Ops> static bool casn(Ops &&... ops);
36+
// Attempts the described CAS operations. Returns `true` on success and
37+
// `false` on failure.
38+
39+
// Unityped CASN -------------------------------------------------------------
40+
41+
struct op_mono_t;
42+
// Describes a single CAS operation in a unityped manner.
43+
44+
template <class Value> static op_mono_t as_mono(op_t<Value> &op);
45+
// Creates a unityped reference to the CAS operation.
46+
47+
static bool casn(op_mono_t *mono_ops);
48+
// Attempts the described unityped CAS operations. Returns `true` on success
49+
// and `false` on failure.
50+
};
51+
52+
} // namespace rdcss_v1

provides/include/rdcss_v1/config.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
#include "lax_v1/config.hpp"
4+
5+
namespace rdcss_v1 {
6+
7+
namespace lax = lax_v1;
8+
9+
}

0 commit comments

Comments
 (0)