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