Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
Array_MT_UnitTests_Decl.hpp
Go to the documentation of this file.
1/*
2// @HEADER
3// ***********************************************************************
4//
5// Teuchos: Common Tools Package
6// Copyright (2004) Sandia Corporation
7//
8// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9// license for use of this work by or on behalf of the U.S. Government.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39//
40// ***********************************************************************
41// @HEADER
42*/
43
44// These unit tests are used for both a Nightly version and a Basic version
45
47
48#include "Teuchos_Array.hpp"
49#include "Teuchos_RCP.hpp"
52#include <vector>
53#include <thread>
54
55namespace {
56
57using Teuchos::Array;
58using Teuchos::RCP;
61
62// this thread method repeatedly calls the iterator loop and reads values
63// arrayType will be Array or const Array
64// iteratorType will be corresponding ::iterator or ::const_iterator
65template<typename arrayType, typename iteratorType>
66static void thread_reads_array(arrayType shared_array, int setValue) {
67 while (!ThreadTestManager::s_bAllowThreadsToRun) {}
68 for( int n = 0; n < 1000; ++n) {
69 for (iteratorType iter = shared_array->begin();
70 iter < shared_array->end(); ++iter) {
71 int readValue = *iter; // read the value
72 if(readValue != setValue) {
73 throw std::logic_error("Test failed to read proper array value.");
74 }
75 }
76 }
77}
78
79// Shared method for Array and const Array unit tests
80// See notes below for individual unit tests
81template<typename arrayType, typename iteratorType>
82void runReadArrayTest()
83{
85 const int numTests = NUM_TESTS_TO_RUN;
86 const int setArrayLength = 10; // somewhat arbitrary
87 const int setArrayValue = 3; // arbitrary
88 for (int testCycle = 0; testCycle < numTests; ++testCycle) {
89 std::vector<std::thread> threads;
90 // set up threads to be spin locked
91 ThreadTestManager::s_bAllowThreadsToRun = false;
92 // makes an array of length setArrayLength with each
93 // element set to setArrayValue
94 arrayType array_rcp =
95 rcp(new Array<int>( setArrayLength, setArrayValue ));
96 // create multiple threads which read the array
97 for (int i = 0; i < numThreads; ++i) {
98 threads.push_back(std::thread(
99 thread_reads_array<arrayType, iteratorType>,
100 array_rcp, setArrayValue));
101 }
102 // let the threads run
103 ThreadTestManager::s_bAllowThreadsToRun = true;
104 // join the threads
105 for (unsigned int i = 0; i < threads.size(); ++i) {
106 threads[i].join();
107 }
108 convenience_log_progress(testCycle, numTests); // just output
109 }
110}
111
112// RCP Thread Safety Unit Test: mtArrayMultipleReads_NonConst
113//
114// Purpose:
115// Demonstrates the Array class needs thread safety protection for debug mode
116// since the debug ArrayRCP objects are allocated in the begin() function.
117//
118// Description:
119// An Array is shared to multiple threads - they simultaneously use the
120// non-const iterator - so this calls begin(), end(), and ++iter on the
121// thread which was sufficient to demonstrate the original problem.
122// Later added reads of the iterator for more complete testing.
123// The point of this test was to validate that multiple threads can safely
124// read a shared Array. We expected it to fail originally because the begin()
125// call in Debug will set extern_arcp_ so the first strategy was to make a
126// race condition on that allocation to demonstrate we could see this problem.
127// Note that begin() is a const but the internal extern_arcp_ object is
128// mutable - that object could be changed by multiple threads simultaneously.
129//
130// Solution to the Problem:
131// A single debug-only mutex protects all changes to the member vec_ as well
132// as the debug ArrayRCP objects to avoid any simultaneous read/write
133// behavior.
134//
135// Demonstration of Original Problem:
136// Add the following define at top of this file:
137// #define REMOVE_THREAD_PROTECTION_FOR_ARRAY
138// That will remove the mutex protecting the debug mode.
139TEUCHOS_UNIT_TEST( Array, mtArrayMultipleReads_NonConst )
140{
141 try {
142 runReadArrayTest<RCP<Array<int>>, Array<int>::iterator>();
143 }
144 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
145}
146
147// RCP Thread Safety Unit Test: mtArrayMultipleReads_Const
148//
149// Purpose:
150// Similar to mtArrayMultipleReads_NonConst.
151//
152// Description:
153// Similar to mtArrayMultipleReads_NonConst.
154//
155// Solution to the Problem:
156// Similar to mtArrayMultipleReads_NonConst though the original Array form had
157// the const begin() call the non-const begin(), so this was refactored to
158// facilitate the mutex protection
159//
160// Demonstration of Original Problem:
161// Similar to mtArrayMultipleReads_NonConst.
162TEUCHOS_UNIT_TEST( Array, mtArrayMultipleReads_Const )
163{
164 try {
165 runReadArrayTest<const RCP<Array<int>>, Array<int>::const_iterator>();
166 }
167 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
168}
169
170// These tests are only meaningful in DEBUG
171// They would crash with undefined behaviors in RELEASE
172// All of this Array work was designed to make the debug tracking for Array
173// work in a thread safe way but in release those protections don't exist.
174#ifdef TEUCHOS_DEBUG
175
176// This method runs continuously inserting setValue on shared_array and then
177// removing those values. The shared_array never gets larger than maxArraySize
178// The process completes when finishWhenThisThreadCountCompletes determines
179// that all the reading threads have completed their operations.
180// For the unit tests there will only be 1 thread calling this method.
181static void call_inserts_on_array(RCP<Array<int>> shared_array, int setValue,
182 int maxArraySize, int finishWhenThisThreadCountCompletes) {
183 while (!ThreadTestManager::s_bAllowThreadsToRun) {}
184 while (true) { // runs until read threads register completion
185 const int insertCount = maxArraySize - shared_array->size();
186 // insert some values
187 for (int n = 0; n < insertCount; ++n) {
188 shared_array->push_back(setValue); // insert ints with value setValue
189 }
190 // erase some values
191 for (int n = 0; n < insertCount; ++n) {
192 shared_array->pop_back(); // remove values so it doesn't get too big
193 }
194 if (ThreadTestManager::s_countCompletedThreads >=
195 finishWhenThisThreadCountCompletes) {
196 break;
197 }
198 // track cycles - used to make sure this thread is up and running before
199 // we begin testing the read threads
200 ++ThreadTestManager::s_countWritingThreadCycles;
201 }
202}
203
204// This method runs continuously deleting and allocated memory.
205// When Weak RCP checks for a valid ptr and another strong RCP deallocates,
206// the memory may be lost after the check but before the actual read.
207// This scramble thread can claim that memory, and replace the deallocated
208// memory spot with a new scramble value. This allows the unit test to detect
209// that this bad memory event has occurred. Note that currently we do not
210// have a fix for this Debug Weak RCP check
211static void scramble_memory(int scrambleValue,
212 int finishWhenThisThreadCountCompletes) {
213 while (!ThreadTestManager::s_bAllowThreadsToRun) {}
214 while (true) {
215 // here I used a strict C array to avoid having this code interfering with
216 // any debugging of the actual Array class
217 // Allocates 100 int ptrs, sets them, then deletes the memory, then repeat
218 // Better than just new-delete repeated because we don't want to just
219 // attack the same memory slot over and over.
220 #define ARRAY_SCRAMBLE_SIZE 100
221 int * tempPtrArray[ARRAY_SCRAMBLE_SIZE];
222 for (int n = 0; n < ARRAY_SCRAMBLE_SIZE; ++n) {
223 int * pInt = new int;
224 *pInt = scrambleValue;
225 tempPtrArray[n] = pInt;
226 }
227 for (int n = 0; n < ARRAY_SCRAMBLE_SIZE; ++n) {
228 delete tempPtrArray[n];
229 }
230 if (ThreadTestManager::s_countCompletedThreads >=
231 finishWhenThisThreadCountCompletes) {
232 break;
233 }
234 }
235}
236
237// defined three modes of array testing
238// during these tests one thread will be inserting/removing values and
239// another thread will be allocating/deleting memory.
240// All other threads will perform the operation defined here.
241enum ArrayTest_Style {
242 // Will try to read array - this currently can lead to out of range errors
243 // no iteration occurs in thie mode.
244 ArrayTest_DoReadOperations,
245
246 // Iterator will trigger dangling references but this simple form may
247 // not trigger dangling the first cycle just due to random luck of the draw.
248 ArrayTest_TriggerDanglingWithIteration,
249
250 // Modified test to hit dangling reference immediately on the first cycle.
251 // It's a sanity check and the test happens in a deterministic way.
252 ArrayTest_TriggerDanglingWithIterationFirstCycle
253};
254
255// This method will be called on 2 threads and run an operation
256// defined by arrayTestStyle. While those 2 threads run there will also be
257// 2 special threads running - one is inserting/removing values while another
258// is constantly allocating/deleting memory.
259template<class arrayType>
260static void do_read_operations_on_array(RCP<arrayType> shared_array,
261 int setValue, int scrambleValue, Cycle_Index_Tracker & index_tracker,
262 int maxArraySize, ArrayTest_Style arrayTestStyle) {
263 // spin lock until the threads are released
264 while (!ThreadTestManager::s_bAllowThreadsToRun) {}
265 int cycle = 0; // track the loop cycle so we can save it
266 try {
267 // once we catch the event this loop ends so the count should not impact
268 // the time for the test. 10000 is just to have a safety exit and then the
269 // test can fail due to not detecting the events.
270 for (cycle = 0; cycle < 10000; ++cycle) {
271 switch (arrayTestStyle) {
272 case ArrayTest_DoReadOperations:
273 {
274 // read some values and check for scrambles. Two things can happen,
275 // either we get a range error and get a valid exception or perhaps
276 // we just straight out read bad memory in which case we won't get
277 // an exception but will try to trap that event here and record it.
278 int readValue = shared_array->at(0);
279 if( readValue != setValue ) {
280 // was using this to see if things were working properly - but we
281 // don't necessarily expect the scrambled int to always measure
282 // here - something else could be going on.
283 if( readValue == scrambleValue) {
284 // we detected a bad memory read and the int was set by the
285 // scrambling thread. That confirms we really did read memory
286 // which was allocated by another thread
287 index_tracker.scambledMemory = cycle;
288 }
289 else {
290 // we detected bad memory but it was not set by the scrambling
291 // thread. Anything else could be going on to have changed this.
292 // For now just do the same as above and mark we detected the
293 // error. We are not recording the distinction between this and
294 // the above case right now. I have left both entries for debug
295 // testing.
296 index_tracker.scambledMemory = cycle;
297 }
298 }
299 }
300 break;
301 case ArrayTest_TriggerDanglingWithIteration:
302 {
303 // this is perhaps the most 'natural' way to test the danglers
304 // detection using iterators. However note that this is not
305 // guaranteed to trigger a dangling reference on a particular cycle.
306 // shared_array()->begin() and shared_array->end() do not depend on
307 // the iter arrayRCP so they won't necessarily pick up the dangling
308 // reference immediately. It's possible for shared_array to be
309 // changing in a state so that iter++ never gets called after it
310 // gets set to shared_array->begin(). For example
311 // shared_array()->end() may change to be much smaller than begin(),
312 // or much larger(). Then the loop ends and we go to the next cycle.
313 // That is why this test loops in the first place.
314 // Another test bGuaranteeDanglingDetectionOnFirstCycle true is
315 // designed to always hit dangling on the first cycle for clarity
316 // and to provide a deterministic test mode.
317 for (Array<int>::const_iterator iter = shared_array->begin();
318 iter < shared_array->end(); ++iter) {
319 // empty loop because we are testing the iterators and how they
320 // behave when another thread changes the array in the middle of
321 // iterating.
322 }
323 }
324 break;
325 case ArrayTest_TriggerDanglingWithIterationFirstCycle:
326 {
327 // this deterministic mode is designed to hit the dangling reference
328 // on the very first cycle. If we got to the second cycle we didn't
329 // succeed and need to report an error.
330 if (cycle != 0) {
331 // log the event so the test can fail
332 index_tracker.missedDanglingOnFirstCycle = cycle;
333
334 // inform other threads now that this thread is completed
335 // so they can quit properly
336 ++ThreadTestManager::s_countCompletedThreads;
337
338 // this will exit the thread loop immediately
339 return;
340 }
341
342 // This is the logic to make this threead always hit the dangling
343 // reference on the first cycle. First we allocate an iterator.
344 Array<int>::const_iterator iter = shared_array->begin();
345
346 // determine what thread cycle the read/write thread is currently on
347 int getReadWriteThreadCycles =
348 ThreadTestManager::s_countWritingThreadCycles;
349
350 // spin lock this thread until the read/write thread does at
351 // least one full cycle beyond where it was 'after' the moment
352 // we created the iterator.
353 while (ThreadTestManager::s_countWritingThreadCycles <
354 getReadWriteThreadCycles + 2) { // empty loop
355 }
356
357 // Now call ++iter once - this MUST fail and detect the dangler
358 // In this condition iter is always a weak reference to a node with
359 // an invalid ptr.
360 ++iter; // the test must throw here!
361 }
362 break;
363 }
364 }
365 }
366 catch (DanglingReferenceError) {
367 // If test throws a dangling reference error, record the cycle it occurred.
368 index_tracker.danglingReference = cycle;
369 }
370 catch (RangeError) {
371 // If tests throws a range error, record the cycle it occurred.
372 index_tracker.outOfRangeError = cycle;
373 }
374 catch (std::out_of_range) {
375 // We could also get std::out_of_range
376 // Note that here were are counting Trilinos RangeError and STL
377 // std::out_of_range as all the same - they both happen since the bad
378 // memory read can be triggered at any time and it depends on exactly where
379 // we were in the call stack when things happened.
380 index_tracker.outOfRangeError = cycle;
381 }
382
383 // advertise we are done. When all these threads complete,
384 // the push/pop thread and scambler thread will quit as well.
385 ++ThreadTestManager::s_countCompletedThreads;
386}
387
388// This method will set up:
389// One thread which is constantly inserting/deleting values form shared_array.
390// Another thread will constantly allocate/delete
391// Remaining threads will all run do_read_operations_on_array (above)
392// with a read operation defined by arrayTestStyle.
393// This method is used for all the unit tests except for the two simple
394// read tests defined above.
395bool runArrayDanglingReferenceTest( bool bUseConstVersion,
396 ArrayTest_Style arrayTestStyle ) {
397 // Note that 0 is the insert thread, and 1 is the scrambler thread so set
398 // this to be 4 or more - 3 is not ideal as only have one thread reading.
399 // Using 4 because NUM_TOTAL_CORES_USED - 4
400 const int numThreads = TEUCHOS_THREAD_SAFE_UNIT_TESTS_THREADS_USED;
401
402 // how many times to repeat the entire test
403 const int numTests = NUM_TESTS_TO_RUN;
404
405 // arbitrary - set up an array filled with this value
406 const int setValue = 1;
407
408 // arbitrary - but not the same as setValue
409 // the scramble thread tries to allocate memory during the race condition
410 // which occurs for weak RCP when it checks for valid memory and then loses
411 // that memory before actually reading it. By setting a known value the unit
412 // test can confirm it is registering that event. Exactly how we will
413 // resolve that is a pending issue.
414 const int scrambleValue = 12345;
415
416 // The insert/delete thread will build the array up to this size and
417 // then start to delete elements
418 const int maxArraySize = 100;
419
420 // the maximum number of errors we can detect.
421 // One per thread which is doing read operations.
422 // Does not count the push/pop thread or the scramble thread.
423 int countTotalTestRuns = 0;
424
425 // the actual number of dangling references we detect
426 int countDetectedDanglingReferences = 0;
427
428 // if using the test designed to hit first cycle, this tracks failures
429 int countMissedFirstCycleDanglers = 0;
430
431 // this counts the times the dangling reference missed (thought memory was
432 // fine) but it was actually not and it was found to be overwritten to the
433 // scrambleValue
434 int countScrambledMemoryEvents = 0;
435
436 // this counts out of range errors which are currently triggered by reading
437 // the array with a concurrent write - currently Trilinos RangeError and
438 // STL std::out_of_range are grouped together
439 int countOutOfRangeEvents = 0;
440
441 for (int testCycle = 0; testCycle < numTests; ++testCycle) {
442 std::vector<std::thread> threads;
443 ThreadTestManager::s_bAllowThreadsToRun = false;
444 ThreadTestManager::s_countCompletedThreads = 0;
445 ThreadTestManager::s_countWritingThreadCycles = 0;
446
447 // 0 is pushing/popping, 1 is memory reading/writing.
448 // The rest are the reader threads looking for troubles
449 int finishWhenThisThreadCountCompletes = numThreads - 2;
450
451 // I avoid using general Arrays as we are testing them,
452 // makes debugging thread issues easier
453 Cycle_Index_Tracker index_tracker[numThreads];
454
455 // makes an array of length 1 - so we will cycle from size 1 to
456 // size maxArraySize then back to 1
457 RCP<Array<int>> array_rcp = rcp(new Array<int>(1, setValue));
458
459 for (int i = 0; i < numThreads; ++i) {
460 switch (i)
461 {
462 case 0:
463 // create the insert/delete thread which constantly changes the
464 // size of the array
465 threads.push_back( std::thread(call_inserts_on_array, array_rcp,
466 setValue, maxArraySize, finishWhenThisThreadCountCompletes) );
467 break;
468 case 1:
469 // create the srambler thread which puts pressure on memory
470 // with constant allocations and deletes. This allows us to detect
471 // when we read bad memory (sometimes). Eventually we may fix this
472 // and then the scamble events should no longer occur.
473 threads.push_back( std::thread(scramble_memory, scrambleValue,
474 finishWhenThisThreadCountCompletes) );
475 break;
476 default:
477 // Default threads which just do read operations
478 // We have two modes for const and non-const iterators.
479 ++countTotalTestRuns;
480 if (bUseConstVersion) {
481 threads.push_back( std::thread(
482 do_read_operations_on_array< const Array<int> >, array_rcp,
483 setValue, scrambleValue, std::ref(index_tracker[i]),
484 maxArraySize, arrayTestStyle));
485 }
486 else {
487 threads.push_back( std::thread(
488 do_read_operations_on_array< Array<int> >, array_rcp,
489 setValue, scrambleValue, std::ref(index_tracker[i]),
490 maxArraySize, arrayTestStyle));
491 }
492 break;
493 }
494 }
495
496 // let the threads run
497 ThreadTestManager::s_bAllowThreadsToRun = true;
498
499 // join all threads
500 for (unsigned int i = 0; i < threads.size(); ++i) {
501 threads[i].join();
502 }
503
504 // now count all the events from the different threads
505 for (unsigned int i = 0; i < threads.size(); ++i) {
506 // check for a danglingReference event
507 if (index_tracker[i].danglingReference != UNSET_CYCLE_INDEX ) {
508 ++countDetectedDanglingReferences;
509 }
510
511 // Check for srambled memory events.
512 // This is the flaw we don't currently have a solution for.
513 if (index_tracker[i].scambledMemory != UNSET_CYCLE_INDEX ) {
514 ++countScrambledMemoryEvents;
515 }
516
517 // Track out of range errors
518 if (index_tracker[i].outOfRangeError != UNSET_CYCLE_INDEX ) {
519 ++countOutOfRangeEvents;
520 }
521
522 // This version of the test is designed to hit the dangling reference
523 // on the first cycle so we verify that happened - it provides a
524 // mode of working which is deterministic.
525 if (arrayTestStyle == ArrayTest_TriggerDanglingWithIterationFirstCycle
526 && index_tracker[i].missedDanglingOnFirstCycle != UNSET_CYCLE_INDEX ) {
527 ++countMissedFirstCycleDanglers;
528 }
529 }
530 convenience_log_progress(testCycle, numTests); // this is just output
531 }
532
533 // some log output based on the mode of the test
534 switch (arrayTestStyle) {
535 case ArrayTest_DoReadOperations:
536 {
537 // read tests are expected to hit out of range errors
538 // We may also sometimes read bad memory - this currently does not
539 // have a solution. It happened because the weak rcp checked it was valid,
540 // thought everything was ok, then before actually reading the RCP
541 // released and the scramble thread was able to change the memory.
542 // If the scramble thread did not change the value, we may be reading
543 // bad memory which happens to still have the right stuff.
544 // So the scamble count exists to monitor that the event is taking place.
545 std::cout << "Range Errors: " << countOutOfRangeEvents <<
546 " Scrambles: " << countScrambledMemoryEvents << " ";
547 }
548 break;
549 case ArrayTest_TriggerDanglingWithIterationFirstCycle:
550 case ArrayTest_TriggerDanglingWithIteration:
551 {
552 // These two modes are expected to hit dangling references
553 // and only work with the iterators.
554 std::cout << "Danglers: " << countDetectedDanglingReferences << " ";
555 }
556 break;
557 }
558
559 // Now decide if we passed the test. For the modes with iterators,
560 // meaning arrayTestStyle != ArrayTest_DoReadOperations,
561 // we should have detected one dangling reference on every test run exactly.
562 bool bPassed_DetectDanglers = (arrayTestStyle != ArrayTest_DoReadOperations)
563 ? (countDetectedDanglingReferences == countTotalTestRuns) : true;
564
565 // If we rang the ArrayTest_TriggerDanglingWithIterationFirstCycle mode we
566 // tracked any time we did not hit the dangler on the first cycle by
567 // incrementing countMissedFirstCycleDanglers. That should never happen
568 // so countMissedFirstCycleDanglers should always be 0.
569 bool bPassed_DetectDanglersFirstCycle = (countMissedFirstCycleDanglers == 0);
570
571 // ArrayTest_DoReadOperations should find out of range errors so we test
572 // that at least one was detected. The other two types use iterators and
573 // thergore should never detect out of range errors.
574 bool bPassed_CountOutOfRangeErrors =
575 (arrayTestStyle == ArrayTest_DoReadOperations) ?
576 (countOutOfRangeEvents != 0) : (countOutOfRangeEvents == 0);
577
578 // however - there is an important difference for ArrayTest_DoReadOperations
579 // that is the only test here which has stochastic results
580 // if we are running only a few loops for the basic testing we won't
581 // necessarily pick up one of those errors and then the test can fail
582 // So here we should check if the test count is sufficiently high
583 if(NUM_TESTS_TO_RUN < 1000 && arrayTestStyle == ArrayTest_DoReadOperations) {
584 if(countOutOfRangeEvents == 0) {
585 bPassed_CountOutOfRangeErrors = true; // we allow it to go through
586 }
587 }
588
589 // Using the above 3 bools which were set based on the test results, we can
590 // now determine if the test overall has passed. We must pass all 3.
591 bool bPass = bPassed_DetectDanglersFirstCycle &&
592 bPassed_DetectDanglersFirstCycle && bPassed_CountOutOfRangeErrors;
593
594 if (!bPass) {
595 std::cout << std::endl; // cosmetic - get these errors on a new line
596 }
597
598 // If we failed any of the 3 bools, we will no log some information.
599 if (!bPassed_DetectDanglers) {
600 std::cout << "Test FAILED because it detected only " <<
601 countDetectedDanglingReferences <<
602 " Dangling References but should have detected " << countTotalTestRuns
603 << "." << std::endl;
604 }
605
606 if( !bPassed_DetectDanglersFirstCycle ) {
607 std::cout << "Test FAILED because it missed " <<
608 countMissedFirstCycleDanglers <<
609 " Dangling References but should have detected " << countTotalTestRuns
610 << " on the first cycle." << std::endl;
611 }
612
613 if( !bPassed_CountOutOfRangeErrors ) {
614 std::cout << "Test FAILED because it detected " <<
615 countOutOfRangeEvents <<
616 " out of range events but should have detected: "
617 << ( (arrayTestStyle == ArrayTest_DoReadOperations) ?
618 "More Than 0" : "0" ) << std::endl;
619 }
620
621 return bPass;
622}
623
624// RCP Thread Safety Unit Test: mtArrayDanglingReference_NonConst_ReadValues
625//
626// Purpose:
627// This mode will trigger out of range errors when we might prefer to think
628// of them as dangling reference errors. This is just due to the internal
629// setup and how Array<T>::assertIndex works.
630// This may also trigger a scrambled memory event which does not have a
631// solution implemented. This was preserved to show the event is taking
632// place and future development may eliminate these events so it is
633// impossible to have a weak rcp read bad memory without detection.
634//
635// Description:
636// An Array is shared to multiple threads - they simultaneously try to read
637// the Array data while one thread is constantly changing the array and
638// another thread is constantly allocating and deleting memory.
639//
640// Solution to the Problem:
641// Same as mtArrayMultipleReads_NonConst
642//
643// Demonstration of Original Problem
644// Same as mtArrayMultipleReads_NonConst
645TEUCHOS_UNIT_TEST( Array, mtArrayDanglingReference_NonConst_ReadValues )
646{
647 bool bPass = false;
648 try {
649 bPass = runArrayDanglingReferenceTest( false,
650 ArrayTest_DoReadOperations );
651 }
652 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
653 TEST_ASSERT( bPass )
654}
655
656// RCP Thread Safety Unit Test: mtArrayDanglingReference_Const_ReadValues
657//
658// Purpose:
659// Similar to mtArrayDanglingReference_NonConst_ReadValues except with
660// const iterators.
661//
662// Description:
663// Similar to mtArrayDanglingReference_NonConst_ReadValues
664//
665// Solution to the Problem:
666// Same as mtArrayMultipleReads_Const
667//
668// Demonstration of Original Problem
669// Same as mtArrayMultipleReads_Const
670TEUCHOS_UNIT_TEST( Array, mtArrayDanglingReference_Const_ReadValues )
671{
672 bool bPass = false;
673 try {
674 bPass = runArrayDanglingReferenceTest( true,
675 ArrayTest_DoReadOperations );
676 }
677 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
678 TEST_ASSERT( bPass )
679}
680
681// RCP Thread Safety Unit Test: mtArrayDanglingReference_NonConst
682//
683// Purpose:
684// Demonstrates thread safe detection of dangling references which occur
685// when on thread is iterating over the array while another thread is
686// changing the size of the error (which reallocates the ArrayRCP used by
687// the iterators.
688//
689// Description:
690// An Array is shared to multiple threads - they simultaneously try to
691// iterate over the array while other threads change the array.
692//
693// Solution to the Problem:
694// Same as mtArrayMultipleReads_NonConst
695//
696// Demonstration of Original Problem
697// Same as mtArrayMultipleReads_NonConst
698TEUCHOS_UNIT_TEST( Array, mtArrayDanglingReference_NonConst )
699{
700 bool bPass = false;
701 try {
702 bPass = runArrayDanglingReferenceTest( false,
703 ArrayTest_TriggerDanglingWithIteration );
704 }
705 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
706 TEST_ASSERT( bPass )
707}
708
709// RCP Thread Safety Unit Test: mtArrayDanglingReference_Const
710//
711// Purpose:
712// Same as mtArrayDanglingReference_NonConst but with const iterators.
713//
714// Description:
715// Similar to mtArrayDanglingReference_NonConst.
716//
717// Solution to the Problem:
718// Same as mtArrayMultipleReads_Const
719//
720// Demonstration of Original Problem
721// Same as mtArrayMultipleReads_Const
722TEUCHOS_UNIT_TEST( Array, mtArrayDanglingReference_Const )
723{
724 bool bPass = false;
725 try {
726 bPass = runArrayDanglingReferenceTest( true,
727 ArrayTest_TriggerDanglingWithIteration );
728 }
729 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
730 TEST_ASSERT( bPass )
731}
732
733// RCP Thread Safety Unit Test: mtArrayDanglingReferenceFirstCycle_NonConst
734//
735// Purpose:
736// Same as mtArrayDanglingReference_NonConst but the test is designed
737// so the dangling reference must occur on the first cycle.
738//
739// Description:
740// After creating an iterator, the reading thread spin locks until it
741// determines the thread responsible for changing the array size has
742// completed at least one full cycle. Then the thread continues by using
743// the iterator which is now guaranteed to be dangling.
744//
745// Solution to the Problem:
746// Same as mtArrayMultipleReads_NonConst
747//
748// Demonstration of Original Problem
749// Same as mtArrayMultipleReads_NonConst
750TEUCHOS_UNIT_TEST( Array, mtArrayDanglingReferenceFirstCycle_NonConst )
751{
752 bool bPass = false;
753 try {
754 bPass = runArrayDanglingReferenceTest( false,
755 ArrayTest_TriggerDanglingWithIterationFirstCycle );
756 }
757 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
758 TEST_ASSERT( bPass )
759}
760
761// RCP Thread Safety Unit Test: mtArrayDanglingReference_Const
762//
763// Purpose:
764// Similar to mtArrayDanglingReferenceFirstCycle_NonConst.
765//
766// Description:
767// Similar to mtArrayDanglingReferenceFirstCycle_NonConst.
768//
769// Solution to the Problem:
770// Same as mtArrayMultipleReads_Const
771//
772// Demonstration of Original Problem
773// Same as mtArrayMultipleReads_Const
774TEUCHOS_UNIT_TEST( Array, mtArrayDanglingReferenceFirstCycle_Const )
775{
776 bool bPass = false;
777 try {
778 bPass = runArrayDanglingReferenceTest( true,
779 ArrayTest_TriggerDanglingWithIterationFirstCycle );
780 }
781 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
782 TEST_ASSERT( bPass )
783}
784
785#endif // TEUCHOS_DEBUG
786
787} // end namespace
788
789
790
#define NUM_TESTS_TO_RUN
#define UNSET_CYCLE_INDEX
#define TEUCHOS_THREAD_SAFE_UNIT_TESTS_THREADS_USED
Templated array class derived from the STL std::vector.
#define TEST_ASSERT(v1)
Assert the given statement is true.
Reference-counted pointer class and non-member templated function implementations.
#define TEUCHOS_STANDARD_CATCH_STATEMENTS(VERBOSE, ERR_STREAM, SUCCESS_FLAG)
Simple macro that catches and reports standard exceptions and other exceptions.
Unit testing support.
#define TEUCHOS_UNIT_TEST(TEST_GROUP, TEST_NAME)
Macro for defining a (non-templated) unit test.
Replacement for std::vector that is compatible with the Teuchos Memory Management classes.
Dangling reference error exception class.
Smart reference counting pointer class for automatic garbage collection.
Range error exception class.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.