Line data Source code
1 : // Copyright (c) 2006-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/cppthread
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : // self
21 : //
22 : #include "catch_main.h"
23 :
24 :
25 : // cppthread lib
26 : //
27 : #include <cppthread/exception.h>
28 : #include <cppthread/fifo.h>
29 : #include <cppthread/guard.h>
30 : #include <cppthread/item_with_predicate.h>
31 : #include <cppthread/life.h>
32 : #include <cppthread/mutex.h>
33 : #include <cppthread/pool.h>
34 : #include <cppthread/runner.h>
35 : #include <cppthread/thread.h>
36 : #include <cppthread/worker.h>
37 :
38 :
39 : // snapdev lib
40 : //
41 : #include <snapdev/not_reached.h>
42 :
43 :
44 : // C lib
45 : //
46 : #include <unistd.h>
47 :
48 :
49 :
50 5 : CATCH_TEST_CASE("fifo", "[fifo]")
51 : {
52 6 : CATCH_START_SECTION("FIFO with constraints (own implementation)")
53 : {
54 12 : struct item_t
55 : {
56 : typedef std::shared_ptr<item_t> pointer_t;
57 :
58 15 : bool valid_workload() const
59 : {
60 15 : return f_ready;
61 : }
62 :
63 : bool f_ready = true;
64 : int f_data = 0;
65 : };
66 :
67 2 : cppthread::fifo<item_t::pointer_t> msg;
68 :
69 : // no constraint, it comes out the way it went in
70 : //
71 4 : for(int count(0); count < 3; ++count)
72 : {
73 6 : item_t::pointer_t a(std::make_shared<item_t>());
74 3 : a->f_data = 1;
75 3 : msg.push_back(a);
76 :
77 6 : item_t::pointer_t b(std::make_shared<item_t>());
78 3 : b->f_data = 2;
79 3 : msg.push_back(b);
80 :
81 6 : item_t::pointer_t v;
82 3 : CATCH_REQUIRE(msg.pop_front(v, 0));
83 3 : CATCH_REQUIRE(v->f_data == 1);
84 :
85 3 : CATCH_REQUIRE(msg.pop_front(v, 0));
86 3 : CATCH_REQUIRE(v->f_data == 2);
87 : }
88 :
89 : // now add a constraint, it comes out reversed
90 : //
91 4 : for(int count(0); count < 3; ++count)
92 : {
93 6 : item_t::pointer_t a(std::make_shared<item_t>());
94 3 : a->f_data = 1;
95 3 : a->f_ready = false;
96 3 : msg.push_back(a);
97 :
98 6 : item_t::pointer_t b(std::make_shared<item_t>());
99 3 : b->f_data = 2;
100 3 : msg.push_back(b);
101 :
102 6 : item_t::pointer_t v;
103 3 : CATCH_REQUIRE(msg.pop_front(v, 0));
104 3 : CATCH_REQUIRE(v->f_data == 2);
105 :
106 : // remove the constraint
107 : //
108 3 : a->f_ready = true;
109 :
110 3 : CATCH_REQUIRE(msg.pop_front(v, 0));
111 3 : CATCH_REQUIRE(v->f_data == 1);
112 : }
113 : }
114 : CATCH_END_SECTION()
115 :
116 6 : CATCH_START_SECTION("FIFO with constraints (item_with_predicate implementation)")
117 : {
118 20 : struct item_t
119 : : public cppthread::item_with_predicate
120 : {
121 : typedef std::shared_ptr<item_t> pointer_t;
122 :
123 : int f_data = 0;
124 : };
125 :
126 2 : cppthread::fifo<item_t::pointer_t> msg;
127 :
128 : {
129 2 : item_t::pointer_t items[10];
130 11 : for(std::size_t i(0); i < sizeof(items) / sizeof(items[0]); ++i)
131 : {
132 10 : items[i] = std::make_shared<item_t>();
133 10 : items[i]->f_data = i + 1;
134 10 : msg.push_back(items[i]);
135 : }
136 :
137 : //items[0]->add_dependency(...); -- at least one item cannot have dependencies
138 1 : items[1]->add_dependency(items[0]);
139 1 : items[2]->add_dependency(items[1]);
140 1 : items[3]->add_dependency(items[0]);
141 1 : items[4]->add_dependencies({items[0], items[1], items[2], items[3]});
142 1 : items[5]->add_dependencies({items[3], items[4]});
143 1 : items[6]->add_dependency(items[2]);
144 1 : items[7]->add_dependency(items[6]);
145 1 : items[8]->add_dependency(items[6]);
146 1 : items[9]->add_dependencies({items[7], items[6]});
147 :
148 11 : for(std::size_t i(0); i < sizeof(items) / sizeof(items[0]); ++i)
149 : {
150 : // we do not want these anymore
151 : //
152 10 : items[i].reset();
153 : }
154 :
155 11 : for(std::size_t i(0); i < sizeof(items) / sizeof(items[0]); ++i)
156 : {
157 20 : item_t::pointer_t v;
158 10 : CATCH_REQUIRE(msg.pop_front(v, 0));
159 :
160 : // for this one, the order is simple
161 : //
162 10 : CATCH_REQUIRE(v->f_data == static_cast<int>(i + 1));
163 : }
164 : }
165 : }
166 : CATCH_END_SECTION()
167 :
168 6 : CATCH_START_SECTION("FIFO with constraints -- Number 2 (item_with_predicate implementation)")
169 : {
170 20 : struct item_t
171 : : public cppthread::item_with_predicate
172 : {
173 : typedef std::shared_ptr<item_t> pointer_t;
174 :
175 : int f_data = 0;
176 : };
177 :
178 2 : cppthread::fifo<item_t::pointer_t> msg;
179 :
180 : {
181 2 : item_t::pointer_t items[10];
182 11 : for(std::size_t i(0); i < sizeof(items) / sizeof(items[0]); ++i)
183 : {
184 10 : items[i] = std::make_shared<item_t>();
185 10 : items[i]->f_data = i + 1;
186 10 : msg.push_back(items[i]);
187 : }
188 :
189 : // Complex set of dependencies
190 : //
191 : // +-----------------+
192 : // | |
193 : // v |
194 : // +----+ +----+ | +----+
195 : // | 1 |<--+ 2 |<==== | ====+ 7 |
196 : // +--+-+ +----+ | +----+
197 : // | ^ | ^
198 : // v | | |
199 : // +----+ | | +-+--+
200 : // | 5 | | | | 3 |
201 : // +--+-+ | | +----+
202 : // | | | ^
203 : // v | | |
204 : // +----+ +-+--+ +--+-+ +-+--+
205 : // | 10 +-->| 4 | | 6 +-->| 8 |
206 : // +----+ +----+ +--+-+ +----+
207 : // ^ ^ |
208 : // | | |
209 : // | +-+--+ |
210 : // +-----+ 9 |<-----+
211 : // +----+
212 : //
213 1 : items[0]->add_dependency(items[5]);
214 1 : items[1]->add_dependencies({items[0], items[3]});
215 1 : items[2]->add_dependency(items[7]);
216 1 : items[3]->add_dependencies({items[8], items[9]});
217 1 : items[4]->add_dependencies({items[6], items[0]});
218 : //items[5]->add_dependencies(...);
219 1 : items[6]->add_dependency(items[2]);
220 1 : items[7]->add_dependency(items[5]);
221 1 : items[8]->add_dependency(items[5]);
222 1 : items[9]->add_dependencies({items[8], items[4]});
223 :
224 11 : for(std::size_t i(0); i < sizeof(items) / sizeof(items[0]); ++i)
225 : {
226 : // we do not want these anymore
227 : //
228 10 : items[i].reset();
229 : }
230 :
231 : // The order is well known because we always try to pop the item
232 : // with the lowest number (i.e. first that was added to the FIFO)
233 : //
234 : {
235 2 : item_t::pointer_t v;
236 :
237 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
238 1 : CATCH_REQUIRE(v->f_data == 6);
239 :
240 : // v needs to be reset otherwise the next pop "fails"
241 : //
242 1 : CATCH_REQUIRE_FALSE(msg.pop_front(v, 0));
243 : }
244 :
245 : {
246 2 : item_t::pointer_t v;
247 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
248 1 : CATCH_REQUIRE(v->f_data == 1);
249 : }
250 :
251 : {
252 2 : item_t::pointer_t v;
253 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
254 1 : CATCH_REQUIRE(v->f_data == 8);
255 : }
256 :
257 : {
258 2 : item_t::pointer_t v;
259 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
260 1 : CATCH_REQUIRE(v->f_data == 3);
261 : }
262 :
263 : {
264 2 : item_t::pointer_t v;
265 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
266 1 : CATCH_REQUIRE(v->f_data == 7);
267 : }
268 :
269 : {
270 2 : item_t::pointer_t v;
271 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
272 1 : CATCH_REQUIRE(v->f_data == 5);
273 : }
274 :
275 : {
276 2 : item_t::pointer_t v;
277 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
278 1 : CATCH_REQUIRE(v->f_data == 9);
279 : }
280 :
281 : {
282 2 : item_t::pointer_t v;
283 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
284 1 : CATCH_REQUIRE(v->f_data == 10);
285 : }
286 :
287 : {
288 2 : item_t::pointer_t v;
289 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
290 1 : CATCH_REQUIRE(v->f_data == 4);
291 : }
292 :
293 : {
294 2 : item_t::pointer_t v;
295 1 : CATCH_REQUIRE(msg.pop_front(v, 0));
296 1 : CATCH_REQUIRE(v->f_data == 2);
297 : }
298 : }
299 : }
300 : CATCH_END_SECTION()
301 9 : }
302 :
303 :
304 : // vim: ts=4 sw=4 et
|