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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
20 * Copyright (C) 2015 Cloudius Systems, Ltd.
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>
36 using namespace seastar
;
37 using namespace std::chrono_literals
;
40 SEASTAR_TEST_CASE(test_semaphore_consume
) {
43 BOOST_REQUIRE_EQUAL(sem
.current(), 0u);
44 BOOST_REQUIRE_EQUAL(sem
.waiters(), 0u);
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);
51 BOOST_REQUIRE_EQUAL(sem
.waiters(), 0u);
52 return make_ready_future
<>();
55 SEASTAR_TEST_CASE(test_semaphore_1
) {
56 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair
<semaphore
, int>& x
) {
57 x
.first
.wait().then([&x
] {
61 return sleep(10ms
).then([&x
] {
62 BOOST_REQUIRE_EQUAL(x
.second
, 1);
67 SEASTAR_TEST_CASE(test_semaphore_2
) {
68 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair
<semaphore
, int>& x
) {
69 x
.first
.wait().then([&x
] {
72 return sleep(10ms
).then([&x
] {
73 BOOST_REQUIRE_EQUAL(x
.second
, 0);
78 SEASTAR_TEST_CASE(test_semaphore_timeout_1
) {
79 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair
<semaphore
, int>& x
) {
80 x
.first
.wait(10ms
).then([&x
] {
83 sleep(3ms
).then([&x
] {
86 return sleep(20ms
).then([&x
] {
87 BOOST_REQUIRE_EQUAL(x
.second
, 1);
92 SEASTAR_TEST_CASE(test_semaphore_timeout_2
) {
93 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair
<semaphore
, int>& x
) {
94 x
.first
.wait(3ms
).then([&x
] {
97 sleep(10ms
).then([&x
] {
100 return sleep(20ms
).then([&x
] {
101 BOOST_REQUIRE_EQUAL(x
.second
, 0);
106 SEASTAR_TEST_CASE(test_semaphore_mix_1
) {
107 return do_with(std::make_pair(semaphore(0), 0), [] (std::pair
<semaphore
, int>& x
) {
108 x
.first
.wait(3ms
).then([&x
] {
111 x
.first
.wait().then([&x
] {
114 sleep(10ms
).then([&x
] {
117 return sleep(20ms
).then([&x
] {
118 BOOST_REQUIRE_EQUAL(x
.second
, 10);
123 SEASTAR_TEST_CASE(test_broken_semaphore
) {
124 auto sem
= make_lw_shared
<semaphore
>(0);
126 auto check_result
= [sem
] (future
<> f
) {
129 BOOST_FAIL("expecting exception");
132 return make_ready_future
<>();
134 BOOST_FAIL("wrong exception seen");
136 BOOST_FAIL("unreachable");
137 return make_ready_future
<>();
139 auto ret
= sem
->wait().then_wrapped(check_result
);
141 return sem
->wait().then_wrapped(check_result
).then([ret
= std::move(ret
)] () mutable {
142 return std::move(ret
);
146 SEASTAR_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);
152 return sleep(10ms
).then([&counter
] {
154 BOOST_REQUIRE_EQUAL(counter
, 0u);
161 SEASTAR_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
] {
166 return sleep(10ms
).then([&counter
] {
167 bool was_parallel
= counter
!= 0;
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);
180 SEASTAR_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
] {
185 return sleep(10ms
).then([&counter
] {
186 bool was_parallel
= counter
!= 0;
192 auto running_alone
= [&sm
, &counter
] (int instance
) {
193 return with_lock(sm
, [&counter
] {
194 BOOST_REQUIRE_EQUAL(counter
, 0u);
196 return sleep(10ms
).then([&counter
] {
198 BOOST_REQUIRE_EQUAL(counter
, 0u);
203 auto run
= [running_in_parallel
, running_alone
] (int instance
) {
204 if (instance
% 9 == 0) {
205 return running_alone(instance
);
207 return running_in_parallel(instance
);
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);
218 SEASTAR_TEST_CASE(test_with_semaphore
) {
219 return do_with(semaphore(1), 0, [] (semaphore
& sem
, int& counter
) {
220 return with_semaphore(sem
, 1, [&counter
] {
222 }).then([&counter
, &sem
] () {
223 return with_semaphore(sem
, 1, [&counter
] {
226 }).then_wrapped([&counter
] (auto&& fut
) {
227 BOOST_REQUIRE_EQUAL(counter
, 2);
228 BOOST_REQUIRE(fut
.failed());
229 fut
.ignore_ready_future();
235 SEASTAR_THREAD_TEST_CASE(test_semaphore_units_splitting
) {
236 auto sm
= semaphore(2);
237 auto units
= get_units(sm
, 2, 1min
).get0();
239 BOOST_REQUIRE_EQUAL(sm
.available_units(), 0);
240 auto split
= units
.split(1);
241 BOOST_REQUIRE_EQUAL(sm
.available_units(), 0);
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);