]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/tests/unit/semaphore_test.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / tests / unit / semaphore_test.cc
CommitLineData
11fdf7f2
TL
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18
19/*
20 * Copyright (C) 2015 Cloudius Systems, Ltd.
21 */
22
23#include <seastar/core/thread.hh>
24#include <seastar/core/do_with.hh>
25#include <seastar/testing/test_case.hh>
26#include <seastar/testing/thread_test_case.hh>
27#include <seastar/core/sstring.hh>
28#include <seastar/core/reactor.hh>
29#include <seastar/core/semaphore.hh>
30#include <seastar/core/do_with.hh>
31#include <seastar/core/future-util.hh>
32#include <seastar/core/sleep.hh>
33#include <seastar/core/shared_mutex.hh>
34#include <boost/range/irange.hpp>
35
36using namespace seastar;
37using namespace std::chrono_literals;
38
39
40SEASTAR_TEST_CASE(test_semaphore_consume) {
41 semaphore sem(0);
42 sem.consume(1);
43 BOOST_REQUIRE_EQUAL(sem.current(), 0u);
44 BOOST_REQUIRE_EQUAL(sem.waiters(), 0u);
45
46 BOOST_REQUIRE_EQUAL(sem.try_wait(0), false);
47 auto fut = sem.wait(1);
48 BOOST_REQUIRE_EQUAL(fut.available(), false);
49 BOOST_REQUIRE_EQUAL(sem.waiters(), 1u);
50 sem.signal(2);
51 BOOST_REQUIRE_EQUAL(sem.waiters(), 0u);
52 return make_ready_future<>();
53}
54
55SEASTAR_TEST_CASE(test_semaphore_1) {
56 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair<semaphore, int>& x) {
9f95a23c 57 (void)x.first.wait().then([&x] {
11fdf7f2
TL
58 x.second++;
59 });
60 x.first.signal();
61 return sleep(10ms).then([&x] {
62 BOOST_REQUIRE_EQUAL(x.second, 1);
63 });
64 });
65}
66
67SEASTAR_TEST_CASE(test_semaphore_2) {
68 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair<semaphore, int>& x) {
9f95a23c 69 (void)x.first.wait().then([&x] {
11fdf7f2
TL
70 x.second++;
71 });
72 return sleep(10ms).then([&x] {
73 BOOST_REQUIRE_EQUAL(x.second, 0);
74 });
75 });
76}
77
78SEASTAR_TEST_CASE(test_semaphore_timeout_1) {
79 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair<semaphore, int>& x) {
9f95a23c 80 (void)x.first.wait(100ms).then([&x] {
11fdf7f2
TL
81 x.second++;
82 });
9f95a23c 83 (void)sleep(3ms).then([&x] {
11fdf7f2
TL
84 x.first.signal();
85 });
9f95a23c 86 return sleep(200ms).then([&x] {
11fdf7f2
TL
87 BOOST_REQUIRE_EQUAL(x.second, 1);
88 });
89 });
90}
91
92SEASTAR_TEST_CASE(test_semaphore_timeout_2) {
93 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair<semaphore, int>& x) {
9f95a23c 94 (void)x.first.wait(3ms).then([&x] {
11fdf7f2
TL
95 x.second++;
96 });
9f95a23c 97 (void)sleep(100ms).then([&x] {
11fdf7f2
TL
98 x.first.signal();
99 });
9f95a23c 100 return sleep(200ms).then([&x] {
11fdf7f2
TL
101 BOOST_REQUIRE_EQUAL(x.second, 0);
102 });
103 });
104}
105
106SEASTAR_TEST_CASE(test_semaphore_mix_1) {
107 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair<semaphore, int>& x) {
9f95a23c 108 (void)x.first.wait(30ms).then([&x] {
11fdf7f2
TL
109 x.second++;
110 });
9f95a23c 111 (void)x.first.wait().then([&x] {
11fdf7f2
TL
112 x.second = 10;
113 });
9f95a23c 114 (void)sleep(100ms).then([&x] {
11fdf7f2
TL
115 x.first.signal();
116 });
9f95a23c 117 return sleep(200ms).then([&x] {
11fdf7f2
TL
118 BOOST_REQUIRE_EQUAL(x.second, 10);
119 });
120 });
121}
122
123SEASTAR_TEST_CASE(test_broken_semaphore) {
124 auto sem = make_lw_shared<semaphore>(0);
125 struct oops {};
126 auto check_result = [sem] (future<> f) {
127 try {
128 f.get();
129 BOOST_FAIL("expecting exception");
130 } catch (oops& x) {
131 // ok
132 return make_ready_future<>();
133 } catch (...) {
134 BOOST_FAIL("wrong exception seen");
135 }
136 BOOST_FAIL("unreachable");
137 return make_ready_future<>();
138 };
139 auto ret = sem->wait().then_wrapped(check_result);
140 sem->broken(oops());
141 return sem->wait().then_wrapped(check_result).then([ret = std::move(ret)] () mutable {
142 return std::move(ret);
143 });
144}
145
146SEASTAR_TEST_CASE(test_shared_mutex_exclusive) {
147 return do_with(shared_mutex(), unsigned(0), [] (shared_mutex& sm, unsigned& counter) {
148 return parallel_for_each(boost::irange(0, 10), [&sm, &counter] (int idx) {
149 return with_lock(sm, [&counter] {
150 BOOST_REQUIRE_EQUAL(counter, 0u);
151 ++counter;
152 return sleep(10ms).then([&counter] {
153 --counter;
154 BOOST_REQUIRE_EQUAL(counter, 0u);
155 });
156 });
157 });
158 });
159}
160
161SEASTAR_TEST_CASE(test_shared_mutex_shared) {
162 return do_with(shared_mutex(), unsigned(0), [] (shared_mutex& sm, unsigned& counter) {
163 auto running_in_parallel = [&sm, &counter] (int instance) {
164 return with_shared(sm, [&counter] {
165 ++counter;
166 return sleep(10ms).then([&counter] {
167 bool was_parallel = counter != 0;
168 --counter;
169 return was_parallel;
170 });
171 });
172 };
173 return map_reduce(boost::irange(0, 100), running_in_parallel, false, std::bit_or<bool>()).then([&counter] (bool result) {
174 BOOST_REQUIRE_EQUAL(result, true);
175 BOOST_REQUIRE_EQUAL(counter, 0u);
176 });
177 });
178}
179
180SEASTAR_TEST_CASE(test_shared_mutex_mixed) {
181 return do_with(shared_mutex(), unsigned(0), [] (shared_mutex& sm, unsigned& counter) {
182 auto running_in_parallel = [&sm, &counter] (int instance) {
183 return with_shared(sm, [&counter] {
184 ++counter;
185 return sleep(10ms).then([&counter] {
186 bool was_parallel = counter != 0;
187 --counter;
188 return was_parallel;
189 });
190 });
191 };
192 auto running_alone = [&sm, &counter] (int instance) {
193 return with_lock(sm, [&counter] {
194 BOOST_REQUIRE_EQUAL(counter, 0u);
195 ++counter;
196 return sleep(10ms).then([&counter] {
197 --counter;
198 BOOST_REQUIRE_EQUAL(counter, 0u);
199 return true;
200 });
201 });
202 };
203 auto run = [running_in_parallel, running_alone] (int instance) {
204 if (instance % 9 == 0) {
205 return running_alone(instance);
206 } else {
207 return running_in_parallel(instance);
208 }
209 };
210 return map_reduce(boost::irange(0, 100), run, false, std::bit_or<bool>()).then([&counter] (bool result) {
211 BOOST_REQUIRE_EQUAL(result, true);
212 BOOST_REQUIRE_EQUAL(counter, 0u);
213 });
214 });
215}
216
217
218SEASTAR_TEST_CASE(test_with_semaphore) {
219 return do_with(semaphore(1), 0, [] (semaphore& sem, int& counter) {
220 return with_semaphore(sem, 1, [&counter] {
221 ++counter;
222 }).then([&counter, &sem] () {
223 return with_semaphore(sem, 1, [&counter] {
224 ++counter;
225 throw 123;
226 }).then_wrapped([&counter] (auto&& fut) {
227 BOOST_REQUIRE_EQUAL(counter, 2);
228 BOOST_REQUIRE(fut.failed());
229 fut.ignore_ready_future();
230 });
231 });
232 });
233}
234
235SEASTAR_THREAD_TEST_CASE(test_semaphore_units_splitting) {
236 auto sm = semaphore(2);
237 auto units = get_units(sm, 2, 1min).get0();
238 {
239 BOOST_REQUIRE_EQUAL(sm.available_units(), 0);
240 auto split = units.split(1);
241 BOOST_REQUIRE_EQUAL(sm.available_units(), 0);
242 }
243 BOOST_REQUIRE_EQUAL(sm.available_units(), 1);
244 units.~semaphore_units();
245 units = get_units(sm, 2, 1min).get0();
246 BOOST_REQUIRE_EQUAL(sm.available_units(), 0);
247 BOOST_REQUIRE_THROW(units.split(10), std::invalid_argument);
248 BOOST_REQUIRE_EQUAL(sm.available_units(), 0);
249}
9f95a23c
TL
250
251SEASTAR_THREAD_TEST_CASE(test_named_semaphore_error) {
252 auto sem = make_lw_shared<named_semaphore>(0, named_semaphore_exception_factory{"name_of_the_semaphore"});
253 auto check_result = [sem] (future<> f) {
254 try {
255 f.get();
256 BOOST_FAIL("Expecting an exception");
257 } catch (broken_named_semaphore& ex) {
258 BOOST_REQUIRE_NE(std::string(ex.what()).find("name_of_the_semaphore"), std::string::npos);
259 } catch (...) {
260 BOOST_FAIL("Expected an instance of broken_named_semaphore with proper semaphore name");
261 }
262 return make_ready_future<>();
263 };
264 auto ret = sem->wait().then_wrapped(check_result);
265 sem->broken();
266 sem->wait().then_wrapped(check_result).then([ret = std::move(ret)] () mutable {
267 return std::move(ret);
268 }).get();
269}
270
271SEASTAR_THREAD_TEST_CASE(test_named_semaphore_timeout) {
272 auto sem = make_lw_shared<named_semaphore>(0, named_semaphore_exception_factory{"name_of_the_semaphore"});
273
274 auto f = sem->wait(named_semaphore::clock::now() + 1ms, 1);
275 try {
276 f.get();
277 BOOST_FAIL("Expecting an exception");
278 } catch (named_semaphore_timed_out& ex) {
279 BOOST_REQUIRE_NE(std::string(ex.what()).find("name_of_the_semaphore"), std::string::npos);
280 } catch (...) {
281 BOOST_FAIL("Expected an instance of named_semaphore_timed_out with proper semaphore name");
282 }
283}