1 // Copyright (C) 2019-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <exceptions/exceptions.h>
10 #include <util/multi_threading_mgr.h>
11 #include <testutils/gtest_utils.h>
12 
13 #include <gtest/gtest.h>
14 
15 using namespace isc::util;
16 using namespace isc;
17 
18 /// @brief Verifies that the default mode is false (MT disabled).
TEST(MultiThreadingMgrTest,defaultMode)19 TEST(MultiThreadingMgrTest, defaultMode) {
20     // MT should be disabled
21     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
22 }
23 
24 /// @brief Verifies that the mode setter works.
TEST(MultiThreadingMgrTest,setMode)25 TEST(MultiThreadingMgrTest, setMode) {
26     // enable MT
27     EXPECT_NO_THROW(MultiThreadingMgr::instance().setMode(true));
28     // MT should be enabled
29     EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
30     // disable MT
31     EXPECT_NO_THROW(MultiThreadingMgr::instance().setMode(false));
32     // MT should be disabled
33     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
34 }
35 
36 /// @brief Verifies that accessing the thread pool works.
TEST(MultiThreadingMgrTest,threadPool)37 TEST(MultiThreadingMgrTest, threadPool) {
38     // get the thread pool
39     EXPECT_NO_THROW(MultiThreadingMgr::instance().getThreadPool());
40 }
41 
42 /// @brief Verifies that the thread pool size setter works.
TEST(MultiThreadingMgrTest,threadPoolSize)43 TEST(MultiThreadingMgrTest, threadPoolSize) {
44     // default thread count is 0
45     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
46     // set thread count to 16
47     EXPECT_NO_THROW(MultiThreadingMgr::instance().setThreadPoolSize(16));
48     // thread count should be 16
49     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
50     // set thread count to 0
51     EXPECT_NO_THROW(MultiThreadingMgr::instance().setThreadPoolSize(0));
52     // thread count should be 0
53     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
54 }
55 
56 /// @brief Verifies that the packet queue size setter works.
TEST(MultiThreadingMgrTest,packetQueueSize)57 TEST(MultiThreadingMgrTest, packetQueueSize) {
58     // default queue size is 0
59     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
60     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPool().getMaxQueueSize(), 0);
61     // set queue size to 16
62     EXPECT_NO_THROW(MultiThreadingMgr::instance().setPacketQueueSize(16));
63     // queue size should be 16
64     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 16);
65     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPool().getMaxQueueSize(), 16);
66     // set queue size to 0
67     EXPECT_NO_THROW(MultiThreadingMgr::instance().setPacketQueueSize(0));
68     // queue size should be 0
69     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
70     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPool().getMaxQueueSize(), 0);
71 }
72 
73 /// @brief Verifies that detecting thread count works.
TEST(MultiThreadingMgrTest,detectThreadCount)74 TEST(MultiThreadingMgrTest, detectThreadCount) {
75     // detecting thread count should work
76     EXPECT_NE(MultiThreadingMgr::detectThreadCount(), 0);
77 }
78 
79 /// @brief Verifies that apply settings works.
TEST(MultiThreadingMgrTest,applyConfig)80 TEST(MultiThreadingMgrTest, applyConfig) {
81     // get the thread pool
82     auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
83     // MT should be disabled
84     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
85     // default thread count is 0
86     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
87     // thread pool should be stopped
88     EXPECT_EQ(thread_pool.size(), 0);
89     // enable MT with 16 threads and queue size 256
90     EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(true, 16, 256));
91     // MT should be enabled
92     EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
93     // thread count should be 16
94     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
95     // queue size should be 256
96     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
97     // thread pool should be started
98     EXPECT_EQ(thread_pool.size(), 16);
99     // disable MT
100     EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(false, 16, 256));
101     // MT should be disabled
102     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
103     // thread count should be 0
104     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
105     // queue size should be 0
106     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
107     // thread pool should be stopped
108     EXPECT_EQ(thread_pool.size(), 0);
109     // enable MT with auto scaling
110     EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(true, 0, 0));
111     // MT should be enabled
112     EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
113     // thread count should be detected automatically
114     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), MultiThreadingMgr::detectThreadCount());
115     // thread pool should be started
116     EXPECT_EQ(thread_pool.size(), MultiThreadingMgr::detectThreadCount());
117     // disable MT
118     EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(false, 0, 0));
119     // MT should be disabled
120     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
121     // thread count should be 0
122     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
123     // thread pool should be stopped
124     EXPECT_EQ(thread_pool.size(), 0);
125 }
126 
127 /// @brief Verifies that the critical section flag works.
TEST(MultiThreadingMgrTest,criticalSectionFlag)128 TEST(MultiThreadingMgrTest, criticalSectionFlag) {
129     // get the thread pool
130     auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
131     // MT should be disabled
132     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
133     // critical section should be disabled
134     EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
135     // thread count should be 0
136     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
137     // thread pool should be stopped
138     EXPECT_EQ(thread_pool.size(), 0);
139     // exit critical section
140     EXPECT_THROW(MultiThreadingMgr::instance().exitCriticalSection(), InvalidOperation);
141     // critical section should be disabled
142     EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
143     // enter critical section
144     EXPECT_NO_THROW(MultiThreadingMgr::instance().enterCriticalSection());
145     // critical section should be enabled
146     EXPECT_TRUE(MultiThreadingMgr::instance().isInCriticalSection());
147     // enable MT with 16 threads and queue size 256
148     EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(true, 16, 256));
149     // MT should be enabled
150     EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
151     // thread count should be 16
152     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
153     // queue size should be 256
154     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
155     // thread pool should be stopped
156     EXPECT_EQ(thread_pool.size(), 0);
157     // exit critical section
158     EXPECT_NO_THROW(MultiThreadingMgr::instance().exitCriticalSection());
159     // critical section should be disabled
160     EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
161     // exit critical section
162     EXPECT_THROW(MultiThreadingMgr::instance().exitCriticalSection(), InvalidOperation);
163     // critical section should be disabled
164     EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
165     // disable MT
166     EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(false, 0, 0));
167     // MT should be disabled
168     EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
169     // thread count should be 0
170     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
171     // queue size should be 0
172     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
173     // thread pool should be stopped
174     EXPECT_EQ(thread_pool.size(), 0);
175 }
176 
177 /// @brief Verifies that the critical section works.
TEST(MultiThreadingMgrTest,criticalSection)178 TEST(MultiThreadingMgrTest, criticalSection) {
179     // get the thread pool instance
180     auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
181     // thread pool should be stopped
182     EXPECT_EQ(thread_pool.size(), 0);
183     // apply multi-threading configuration with 16 threads and queue size 256
184     MultiThreadingMgr::instance().apply(true, 16, 256);
185     // thread count should match
186     EXPECT_EQ(thread_pool.size(), 16);
187     // thread count should be 16
188     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
189     // queue size should be 256
190     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
191     // use scope to test constructor and destructor
192     {
193         MultiThreadingCriticalSection cs;
194         // thread pool should be stopped
195         EXPECT_EQ(thread_pool.size(), 0);
196         // thread count should be 16
197         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
198         // queue size should be 256
199         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
200         // use scope to test constructor and destructor
201         {
202             MultiThreadingCriticalSection inner_cs;
203             // thread pool should be stopped
204             EXPECT_EQ(thread_pool.size(), 0);
205             // thread count should be 16
206             EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
207             // queue size should be 256
208             EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
209         }
210         // thread pool should be stopped
211         EXPECT_EQ(thread_pool.size(), 0);
212         // thread count should be 16
213         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
214         // queue size should be 256
215         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
216     }
217     // thread count should match
218     EXPECT_EQ(thread_pool.size(), 16);
219     // thread count should be 16
220     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
221     // queue size should be 256
222     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
223     // use scope to test constructor and destructor
224     {
225         MultiThreadingCriticalSection cs;
226         // thread pool should be stopped
227         EXPECT_EQ(thread_pool.size(), 0);
228         // thread count should be 16
229         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
230         // queue size should be 256
231         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
232         // apply multi-threading configuration with 64 threads and queue size 4
233         MultiThreadingMgr::instance().apply(true, 64, 4);
234         // thread pool should be stopped
235         EXPECT_EQ(thread_pool.size(), 0);
236         // thread count should be 64
237         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
238         // queue size should be 4
239         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 4);
240     }
241     // thread count should match
242     EXPECT_EQ(thread_pool.size(), 64);
243     // thread count should be 64
244     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
245     // queue size should be 4
246     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 4);
247     // use scope to test constructor and destructor
248     {
249         MultiThreadingCriticalSection cs;
250         // thread pool should be stopped
251         EXPECT_EQ(thread_pool.size(), 0);
252         // thread count should be 64
253         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
254         // queue size should be 4
255         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 4);
256         // apply multi-threading configuration with 0 threads
257         MultiThreadingMgr::instance().apply(false, 64, 256);
258         // thread pool should be stopped
259         EXPECT_EQ(thread_pool.size(), 0);
260         // thread count should be 0
261         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
262         // queue size should be 0
263         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
264     }
265     // thread count should match
266     EXPECT_EQ(thread_pool.size(), 0);
267     // thread count should be 0
268     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
269     // queue size should be 0
270     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
271     // use scope to test constructor and destructor
272     {
273         MultiThreadingCriticalSection cs;
274         // thread pool should be stopped
275         EXPECT_EQ(thread_pool.size(), 0);
276         // thread count should be 0
277         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
278         // queue size should be 0
279         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
280         // use scope to test constructor and destructor
281         {
282             MultiThreadingCriticalSection inner_cs;
283             // thread pool should be stopped
284             EXPECT_EQ(thread_pool.size(), 0);
285             // thread count should be 0
286             EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
287             // queue size should be 0
288             EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
289         }
290         // thread pool should be stopped
291         EXPECT_EQ(thread_pool.size(), 0);
292         // thread count should be 0
293         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
294         // queue size should be 0
295         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
296     }
297     // thread count should match
298     EXPECT_EQ(thread_pool.size(), 0);
299     // thread count should be 0
300     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
301     // queue size should be 0
302     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
303     // use scope to test constructor and destructor
304     {
305         MultiThreadingCriticalSection cs;
306         // thread pool should be stopped
307         EXPECT_EQ(thread_pool.size(), 0);
308         // apply multi-threading configuration with 64 threads
309         MultiThreadingMgr::instance().apply(true, 64, 256);
310         // thread pool should be stopped
311         EXPECT_EQ(thread_pool.size(), 0);
312         // thread count should be 64
313         EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
314         // queue size should be 256
315         EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
316     }
317     // thread count should match
318     EXPECT_EQ(thread_pool.size(), 64);
319     // thread count should be 64
320     EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
321     // queue size should be 256
322     EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
323     // apply multi-threading configuration with 0 threads
324     MultiThreadingMgr::instance().apply(false, 0, 0);
325 }
326 
327 /// @brief Test fixture for exercised CriticalSection callbacks.
328 class CriticalSectionCallbackTest : public ::testing::Test {
329 public:
330     /// @brief Constructor.
CriticalSectionCallbackTest()331     CriticalSectionCallbackTest() {
332         MultiThreadingMgr::instance().apply(false, 0, 0);
333     }
334 
335     /// @brief Destructor.
~CriticalSectionCallbackTest()336     ~CriticalSectionCallbackTest() {
337         MultiThreadingMgr::instance().apply(false, 0, 0);
338     }
339 
340     /// @brief A callback that adds the value 1 to invocations lists.
one()341     void one() {
342         invocations_.push_back(1);
343     }
344 
345     /// @brief A callback that adds the value 2 to invocations lists.
two()346     void two() {
347         invocations_.push_back(2);
348     }
349 
350     /// @brief A callback that adds the value 3 to invocations lists.
three()351     void three() {
352         invocations_.push_back(3);
353     }
354 
355     /// @brief A callback that adds the value 4 to invocations lists.
four()356     void four() {
357         invocations_.push_back(4);
358     }
359 
360     /// @brief A callback that throws @ref isc::Exception which is ignored.
ignoredException()361     void ignoredException() {
362         isc_throw(isc::Exception, "ignored");
363     }
364 
365     /// @brief A callback that throws @ref isc::MultiThreadingInvalidOperation
366     /// which is propagated to the scope of the
367     /// @ref MultiThreadingCriticalSection constructor.
observedException()368     void observedException() {
369         isc_throw(isc::MultiThreadingInvalidOperation, "observed");
370     }
371 
372     /// @brief Indicates whether or not the DHCP thread pool is running.
373     ///
374     /// @return True if the pool is running, false otherwise.
isThreadPoolRunning()375     bool isThreadPoolRunning() {
376         return (MultiThreadingMgr::instance().getThreadPool().size());
377     }
378 
379     /// @brief Checks callback invocations over a series of nested
380     /// CriticalSections.
381     ///
382     /// @param entries A vector of the invocation values that should
383     /// be present after entry into the outermost CriticalSection.  The
384     /// expected values should be in the order the callbacks were added
385     /// to the MultiThreadingMgr's list of callbacks.
386     /// @param exits A vector of the invocation values that should
387     /// be present after exiting the outermost CriticalSection.  The
388     /// expected values should be in the order the callbacks were added
389     /// to the MultiThreadingMgr's list of callbacks.
390     /// @param should_throw The flag indicating if the CriticalSection should
391     /// throw, simulating a dead-lock scenario when a processing thread tries
392     /// to stop the thread pool.
runCriticalSections(std::vector<int> entries,std::vector<int> exits,bool should_throw=false)393     void runCriticalSections(std::vector<int> entries, std::vector<int>exits,
394                              bool should_throw = false) {
395         // Pool must be running.
396         ASSERT_TRUE(isThreadPoolRunning());
397 
398         // Clear the invocations list.
399         invocations_.clear();
400 
401         // Use scope to create nested CriticalSections.
402         if (!should_throw) {
403             // Enter a critical section.
404             MultiThreadingCriticalSection cs;
405 
406             // Thread pool should be stopped.
407             ASSERT_FALSE(isThreadPoolRunning());
408 
409             if (entries.size()) {
410                 // We expect entry invocations.
411                 ASSERT_EQ(invocations_.size(), entries.size());
412                 ASSERT_EQ(invocations_, entries);
413             } else {
414                 // We do not expect entry invocations.
415                 ASSERT_FALSE(invocations_.size());
416             }
417 
418             // Clear the invocations list.
419             invocations_.clear();
420 
421             {
422                 // Enter another CriticalSection.
423                 MultiThreadingCriticalSection inner_cs;
424 
425                 // Thread pool should still be stopped.
426                 ASSERT_FALSE(isThreadPoolRunning());
427 
428                 // We should not have had any callback invocations.
429                 ASSERT_FALSE(invocations_.size());
430             }
431 
432             // After exiting inner section, the thread pool should
433             // still be stopped.
434             ASSERT_FALSE(isThreadPoolRunning());
435 
436             // We should not have had more callback invocations.
437             ASSERT_FALSE(invocations_.size());
438         } else {
439             ASSERT_THROW(MultiThreadingCriticalSection cs, MultiThreadingInvalidOperation);
440 
441             if (entries.size()) {
442                 // We expect entry invocations.
443                 ASSERT_EQ(invocations_.size(), entries.size());
444                 ASSERT_EQ(invocations_, entries);
445             } else {
446                 // We do not expect entry invocations.
447                 ASSERT_FALSE(invocations_.size());
448             }
449 
450             // Clear the invocations list.
451             invocations_.clear();
452         }
453 
454         // After exiting the outer section, the thread pool should
455         // match the thread count.
456         ASSERT_TRUE(isThreadPoolRunning());
457 
458         if (exits.size()) {
459             // We expect exit invocations.
460             ASSERT_EQ(invocations_, exits);
461         } else {
462             // We do not expect exit invocations.
463             ASSERT_FALSE(invocations_.size());
464         }
465     }
466 
467     /// @brief A list of values set by callback invocations.
468     std::vector<int> invocations_;
469 };
470 
471 /// @brief Verifies critical section callback maintenance:
472 /// catch invalid pairs, add pairs, remove pairs.
TEST_F(CriticalSectionCallbackTest,addAndRemove)473 TEST_F(CriticalSectionCallbackTest, addAndRemove) {
474     auto& mgr = MultiThreadingMgr::instance();
475 
476     // Cannot add with a blank name.
477     ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("", [](){}, [](){}, [](){}),
478                      BadValue, "CSCallbackSetList - name cannot be empty");
479 
480     // Cannot add with an empty check callback.
481     ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("bad", nullptr, [](){}, [](){}),
482                      BadValue, "CSCallbackSetList - check callback for bad cannot be empty");
483 
484     // Cannot add with an empty exit callback.
485     ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("bad", [](){}, nullptr, [](){}),
486                      BadValue, "CSCallbackSetList - entry callback for bad cannot be empty");
487 
488     // Cannot add with an empty exit callback.
489     ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("bad", [](){}, [](){}, nullptr),
490                      BadValue, "CSCallbackSetList - exit callback for bad cannot be empty");
491 
492     // Should be able to add foo.
493     ASSERT_NO_THROW_LOG(mgr.addCriticalSectionCallbacks("foo", [](){}, [](){}, [](){}));
494 
495     // Should not be able to add foo twice.
496     ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("foo", [](){}, [](){}, [](){}),
497                      BadValue, "CSCallbackSetList - callbacks for foo already exist");
498 
499     // Should be able to add bar.
500     ASSERT_NO_THROW_LOG(mgr.addCriticalSectionCallbacks("bar", [](){}, [](){}, [](){}));
501 
502     // Should be able to remove foo.
503     ASSERT_NO_THROW_LOG(mgr.removeCriticalSectionCallbacks("foo"));
504 
505     // Should be able to remove foo twice without issue.
506     ASSERT_NO_THROW_LOG(mgr.removeCriticalSectionCallbacks("foo"));
507 
508     // Should be able to remove all without issue.
509     ASSERT_NO_THROW_LOG(mgr.removeAllCriticalSectionCallbacks());
510 }
511 
512 /// @brief Verifies that the critical section callbacks work.
TEST_F(CriticalSectionCallbackTest,invocations)513 TEST_F(CriticalSectionCallbackTest, invocations) {
514     // get the thread pool instance
515     auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
516     // thread pool should be stopped
517     EXPECT_EQ(thread_pool.size(), 0);
518 
519     // Add two sets of CriticalSection call backs.
520     MultiThreadingMgr::instance().addCriticalSectionCallbacks("oneAndTwo",
521          std::bind(&CriticalSectionCallbackTest::ignoredException, this),
522          std::bind(&CriticalSectionCallbackTest::one, this),
523          std::bind(&CriticalSectionCallbackTest::two, this));
524 
525     MultiThreadingMgr::instance().addCriticalSectionCallbacks("threeAndFour",
526          std::bind(&CriticalSectionCallbackTest::ignoredException, this),
527          std::bind(&CriticalSectionCallbackTest::three, this),
528          std::bind(&CriticalSectionCallbackTest::four, this));
529 
530     // Apply multi-threading configuration with 16 threads and queue size 256.
531     MultiThreadingMgr::instance().apply(true, 16, 256);
532 
533     // Make three passes over nested CriticalSections to ensure
534     // callbacks execute at the appropriate times and we can do
535     // so repeatedly.
536     for (int i = 0; i < 3; ++i) {
537         runCriticalSections({1 ,3}, {4, 2});
538     }
539 
540     // Now remove the first set of callbacks.
541     MultiThreadingMgr::instance().removeCriticalSectionCallbacks("oneAndTwo");
542 
543     // Retest CriticalSections.
544     runCriticalSections({3}, {4});
545 
546     // Now remove the remaining callbacks.
547     MultiThreadingMgr::instance().removeAllCriticalSectionCallbacks();
548 
549     // Retest CriticalSections.
550     runCriticalSections({}, {});
551 }
552 
553 /// @brief Verifies that the critical section callbacks work.
TEST_F(CriticalSectionCallbackTest,invocationsWithExceptions)554 TEST_F(CriticalSectionCallbackTest, invocationsWithExceptions) {
555     // get the thread pool instance
556     auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
557     // thread pool should be stopped
558     EXPECT_EQ(thread_pool.size(), 0);
559 
560     // Apply multi-threading configuration with 16 threads and queue size 256.
561     MultiThreadingMgr::instance().apply(true, 16, 256);
562 
563     // Add two sets of CriticalSection call backs.
564     MultiThreadingMgr::instance().addCriticalSectionCallbacks("observed",
565          std::bind(&CriticalSectionCallbackTest::observedException, this),
566          std::bind(&CriticalSectionCallbackTest::one, this),
567          std::bind(&CriticalSectionCallbackTest::two, this));
568 
569     MultiThreadingMgr::instance().addCriticalSectionCallbacks("ignored",
570          std::bind(&CriticalSectionCallbackTest::ignoredException, this),
571          std::bind(&CriticalSectionCallbackTest::three, this),
572          std::bind(&CriticalSectionCallbackTest::four, this));
573 
574     // Make three passes over nested CriticalSections to ensure
575     // callbacks execute at the appropriate times and we can do
576     // so repeatedly.
577     for (int i = 0; i < 3; ++i) {
578         runCriticalSections({}, {}, true);
579     }
580 
581     // Now remove the first set of callbacks.
582     MultiThreadingMgr::instance().removeCriticalSectionCallbacks("observed");
583 
584     // Retest CriticalSections.
585     runCriticalSections({3}, {4});
586 
587     // Now remove the remaining callbacks.
588     MultiThreadingMgr::instance().removeAllCriticalSectionCallbacks();
589 
590     // Retest CriticalSections.
591     runCriticalSections({}, {});
592 }
593