1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <sal/types.h>
23 #include "cppunit/TestAssert.h"
24 #include "cppunit/TestFixture.h"
25 #include "cppunit/extensions/HelperMacros.h"
26 #include "cppunit/plugin/TestPlugIn.h"
27 #include <osl_Mutex_Const.h>
31 /** pause nSec seconds helper function.
33 namespace ThreadHelper
35 void thread_sleep_tenth_sec(sal_uInt32 _nTenthSec
)
38 nTV
.Seconds
= _nTenthSec
/10;
39 nTV
.Nanosec
= ( (_nTenthSec
%10 ) * 100000000 );
42 void thread_sleep( sal_uInt32 _nSec
)
44 /// print statement in thread process must use fflush() to force display.
45 // t_print("# wait %d seconds. ", _nSec );
48 thread_sleep_tenth_sec( _nSec
* 10 );
49 // printf("# done\n" );
53 // Beginning of the test cases for osl_Mutex class
55 /** mutually exclusive data
63 /** IncreaseThread provide data.
65 class IncreaseThread
: public Thread
68 IncreaseThread( struct resource
*pData
): pResource( pData
) { }
70 virtual ~IncreaseThread( )
72 CPPUNIT_ASSERT_MESSAGE( "#IncreaseThread does not shutdown properly.\n", !isRunning( ) );
75 struct resource
*pResource
;
77 void SAL_CALL
run( ) SAL_OVERRIDE
79 pResource
->lock
.acquire( );
80 for( sal_Int8 i
= 0; i
< 3; i
++ )
83 yield( ); //yield() give CPU time to other thread, other thread if not block, they will change the data;
85 if ( pResource
->data2
== 0 )
86 pResource
->data2
= ( pResource
->data1
> 0 ? pResource
->data1
: 0 - pResource
->data1
);
87 pResource
->lock
.release();
91 /** DecreaseThread consume data.
93 class DecreaseThread
: public Thread
96 DecreaseThread( struct resource
*pData
): pResource( pData
) { }
98 virtual ~DecreaseThread( )
100 CPPUNIT_ASSERT_MESSAGE( "#DecreaseThread does not shutdown properly.\n", !isRunning( ) );
103 struct resource
*pResource
;
105 void SAL_CALL
run( ) SAL_OVERRIDE
107 pResource
->lock
.acquire( );
108 for( sal_Int8 i
= 0; i
< 3; i
++ )
111 yield( ); //yield() give CPU time to other thread, other thread if not block, they will change the data;
113 if ( pResource
->data2
== 0 )
114 pResource
->data2
= ( pResource
->data1
> 0 ? pResource
->data1
: 0 - pResource
->data1
);
115 pResource
->lock
.release();
119 /** chain structure used in Threads as critical resource
122 sal_Int32 buffer
[ BUFFER_SIZE
];
127 /** PutThread write to the chain structure in a mutex manner.
129 class PutThread
: public Thread
132 //get the struct pointer to write data to buffer
133 PutThread( struct chain
* pData
): pChain( pData
) { }
135 virtual ~PutThread( )
137 CPPUNIT_ASSERT_MESSAGE( "#PutThread does not shutdown properly.\n", !isRunning( ) );
140 struct chain
* pChain
;
142 void SAL_CALL
run( ) SAL_OVERRIDE
144 //block here if the mutex has been acquired
145 pChain
->lock
.acquire( );
147 //current position in buffer to write
148 sal_Int8 nPos
= pChain
->pos
;
149 oslThreadIdentifier oId
= getIdentifier( );
152 for ( i
= 0; i
< 5; i
++ )
154 pChain
->buffer
[ nPos
+ i
] = oId
;
157 //revise the position
158 pChain
->pos
= nPos
+ i
;
160 //finish writing, release the mutex
161 pChain
->lock
.release();
165 /** thread for testing Mutex acquire.
167 class HoldThread
: public Thread
170 //get the Mutex pointer to operate
171 HoldThread( Mutex
* pMutex
): pMyMutex( pMutex
) { }
173 virtual ~HoldThread( )
175 CPPUNIT_ASSERT_MESSAGE( "#HoldThread does not shutdown properly.\n", !isRunning( ) );
180 void SAL_CALL
run() SAL_OVERRIDE
182 // block here if the mutex has been acquired
183 pMyMutex
->acquire( );
184 printf("# Mutex acquired. \n" );
185 pMyMutex
->release( );
189 class WaitThread
: public Thread
192 //get the Mutex pointer to operate
193 WaitThread( Mutex
* pMutex
): pMyMutex( pMutex
) { }
195 virtual ~WaitThread( )
197 CPPUNIT_ASSERT_MESSAGE( "#WaitThread does not shutdown properly.\n", !isRunning( ) );
202 void SAL_CALL
run( ) SAL_OVERRIDE
204 // block here if the mutex has been acquired
205 pMyMutex
->acquire( );
206 ThreadHelper::thread_sleep_tenth_sec( 2 );
207 pMyMutex
->release( );
211 /** thread for testing getGlobalMutex.
213 class GlobalMutexThread
: public Thread
216 //get the Mutex pointer to operate
217 GlobalMutexThread( ){ }
219 virtual ~GlobalMutexThread( )
221 CPPUNIT_ASSERT_MESSAGE( "#GlobalMutexThread does not shutdown properly.\n", !isRunning( ) );
224 void SAL_CALL
run( ) SAL_OVERRIDE
226 // block here if the mutex has been acquired
228 pGlobalMutex
= Mutex::getGlobalMutex( );
229 pGlobalMutex
->acquire( );
230 printf("# Global Mutex acquired. \n" );
231 pGlobalMutex
->release( );
238 /** Test of the osl::Mutex::constructor
240 class ctor
: public CppUnit::TestFixture
243 // initialise your test code values here.
245 struct resource m_Res
;
247 void setUp( ) SAL_OVERRIDE
249 for ( sal_Int8 i
=0; i
< BUFFER_SIZE
; i
++ )
250 m_Data
.buffer
[i
] = 0;
257 void tearDown() SAL_OVERRIDE
261 /** Create two threads to write data to the same buffer, use Mutex to assure
262 during one thread write data five times, the other thread should not begin writing.
263 the two threads wrote two different datas: their thread ID, so we can check the datas
264 in buffer to know the order of the two threads writing
268 PutThread
myThread1( &m_Data
);
269 PutThread
myThread2( &m_Data
);
274 //wait until the two threads terminate
280 // every 5 datas should the same
281 // LLA: this is not a good check, it's too fix
282 if (m_Data
.buffer
[0] == m_Data
.buffer
[1] &&
283 m_Data
.buffer
[1] == m_Data
.buffer
[2] &&
284 m_Data
.buffer
[2] == m_Data
.buffer
[3] &&
285 m_Data
.buffer
[3] == m_Data
.buffer
[4] &&
286 m_Data
.buffer
[5] == m_Data
.buffer
[6] &&
287 m_Data
.buffer
[6] == m_Data
.buffer
[7] &&
288 m_Data
.buffer
[7] == m_Data
.buffer
[8] &&
289 m_Data
.buffer
[8] == m_Data
.buffer
[9])
292 /*for (sal_Int8 i=0; i<BUFFER_SIZE; i++)
293 printf("#data in buffer is %d\n", m_Data.buffer[i]);
296 CPPUNIT_ASSERT_MESSAGE("Mutex ctor", bRes
);
300 /** Create two threads to write data to operate on the same number , use Mutex to assure,
301 one thread increase data 3 times, the other thread decrease 3 times, store the operate
302 result when the first thread complete, if it is interrupt by the other thread, the stored
303 number will not be 3.
307 IncreaseThread
myThread1( &m_Res
);
308 DecreaseThread
myThread2( &m_Res
);
313 //wait until the two threads terminate
319 // every 5 datas should the same
320 if ( ( m_Res
.data1
== 0 ) && ( m_Res
.data2
== 3 ) )
323 CPPUNIT_ASSERT_MESSAGE( "test Mutex ctor function: increase and decrease a number 3 times without interrupt.", bRes
);
326 CPPUNIT_TEST_SUITE( ctor
);
327 CPPUNIT_TEST( ctor_001
);
328 CPPUNIT_TEST( ctor_002
);
329 CPPUNIT_TEST_SUITE_END( );
332 /** Test of the osl::Mutex::acquire method
334 class acquire
: public CppUnit::TestFixture
337 // acquire mutex in main thread, and then call acquire again in myThread,
338 // the child thread should block, wait 2 secs, it still block.
339 // Then release mutex in main thread, the child thread could return from acquire,
340 // and go to exec next statement, so could terminate quickly.
345 bool bRes
= aMutex
.acquire( );
346 // pass the pointer of mutex to child thread
347 HoldThread
myThread( &aMutex
);
350 ThreadHelper::thread_sleep_tenth_sec( 2 );
351 // if acquire in myThread does not work, 2 secs is long enough,
352 // myThread should terminate now, and bRes1 should be sal_False
353 bool bRes1
= myThread
.isRunning( );
356 ThreadHelper::thread_sleep_tenth_sec( 1 );
357 // after release mutex, myThread stops blocking and will terminate immediately
358 bool bRes2
= myThread
.isRunning( );
361 CPPUNIT_ASSERT_MESSAGE( "Mutex acquire", bRes
&& bRes1
&& !bRes2
);
364 //in the same thread, acquire twice should success
369 bool bRes
= aMutex
.acquire();
370 bool bRes1
= aMutex
.acquire();
372 bool bRes2
= aMutex
.tryToAcquire();
376 CPPUNIT_ASSERT_MESSAGE("Mutex acquire", bRes
&& bRes1
&& bRes2
);
380 CPPUNIT_TEST_SUITE( acquire
);
381 CPPUNIT_TEST( acquire_001
);
382 CPPUNIT_TEST( acquire_002
);
383 CPPUNIT_TEST_SUITE_END( );
386 /** Test of the osl::Mutex::tryToAcquire method
388 class tryToAcquire
: public CppUnit::TestFixture
391 // First let child thread acquire the mutex, and wait 2 secs, during the 2 secs,
392 // in main thread, tryToAcquire mutex should return False
393 // then after the child thread terminated, tryToAcquire should return True
394 void tryToAcquire_001()
397 WaitThread
myThread(&aMutex
);
400 // ensure the child thread acquire the mutex
401 ThreadHelper::thread_sleep_tenth_sec(1);
403 bool bRes1
= aMutex
.tryToAcquire();
407 // wait the child thread terminate
410 bool bRes2
= aMutex
.tryToAcquire();
415 CPPUNIT_ASSERT_MESSAGE("Try to acquire Mutex", !bRes1
&& bRes2
);
418 CPPUNIT_TEST_SUITE(tryToAcquire
);
419 CPPUNIT_TEST(tryToAcquire_001
);
420 CPPUNIT_TEST_SUITE_END();
421 }; // class tryToAcquire
423 /** Test of the osl::Mutex::release method
425 class release
: public CppUnit::TestFixture
428 /** acquire/release are not used in pairs: after child thread acquired mutex,
429 the main thread release it, then any thread could acquire it.
434 WaitThread
myThread( &aMutex
);
437 // ensure the child thread acquire the mutex
438 ThreadHelper::thread_sleep_tenth_sec( 1 );
440 bool bRunning
= myThread
.isRunning( );
441 bool bRes1
= aMutex
.tryToAcquire( );
442 // wait the child thread terminate
445 bool bRes2
= aMutex
.tryToAcquire( );
450 CPPUNIT_ASSERT_MESSAGE( "release Mutex: try to acquire before and after the mutex has been released",
451 !bRes1
&& bRes2
&& bRunning
);
455 // how about release twice?
460 CPPUNIT_TEST_SUITE( release
);
461 CPPUNIT_TEST( release_001
);
462 CPPUNIT_TEST( release_002
);
463 CPPUNIT_TEST_SUITE_END( );
466 /** Test of the osl::Mutex::getGlobalMutex method
468 class getGlobalMutex
: public CppUnit::TestFixture
471 // initialise your test code values here.
472 void getGlobalMutex_001()
475 pGlobalMutex
= Mutex::getGlobalMutex();
476 pGlobalMutex
->acquire();
478 GlobalMutexThread myThread
;
481 ThreadHelper::thread_sleep_tenth_sec(1);
482 bool bRes1
= myThread
.isRunning();
484 pGlobalMutex
->release();
485 ThreadHelper::thread_sleep_tenth_sec(1);
486 // after release mutex, myThread stops blocking and will terminate immediately
487 bool bRes2
= myThread
.isRunning();
489 CPPUNIT_ASSERT_MESSAGE("Global Mutex works", bRes1
&& !bRes2
);
492 void getGlobalMutex_002( )
497 pGlobalMutex
= Mutex::getGlobalMutex( );
498 pGlobalMutex
->acquire( );
500 Mutex
*pGlobalMutex1
;
501 pGlobalMutex1
= Mutex::getGlobalMutex( );
502 bRes
= pGlobalMutex1
->release( );
505 CPPUNIT_ASSERT_MESSAGE( "Global Mutex works: if the code between {} get the different mutex as the former one, it will return false when release.",
509 CPPUNIT_TEST_SUITE(getGlobalMutex
);
510 CPPUNIT_TEST(getGlobalMutex_001
);
511 CPPUNIT_TEST(getGlobalMutex_002
);
512 CPPUNIT_TEST_SUITE_END();
513 }; // class getGlobalMutex
515 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::ctor
, "osl_Mutex");
516 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::acquire
, "osl_Mutex");
517 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::tryToAcquire
, "osl_Mutex");
518 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::release
, "osl_Mutex");
519 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Mutex::getGlobalMutex
, "osl_Mutex");
520 } // namespace osl_Mutex
522 // Beginning of the test cases for osl_Guard class
524 class GuardThread
: public Thread
527 //get the Mutex pointer to operate
528 GuardThread( Mutex
* pMutex
): pMyMutex( pMutex
) { }
530 virtual ~GuardThread( )
532 CPPUNIT_ASSERT_MESSAGE( "#GuardThread does not shutdown properly.\n", !isRunning( ) );
537 void SAL_CALL
run( ) SAL_OVERRIDE
539 // block here if the mutex has been acquired
540 MutexGuard
aGuard( pMyMutex
);
541 ThreadHelper::thread_sleep_tenth_sec( 2 );
547 class ctor
: public CppUnit::TestFixture
550 // insert your test code here.
554 GuardThread
myThread(&aMutex
);
557 ThreadHelper::thread_sleep_tenth_sec(1);
558 bool bRes
= aMutex
.tryToAcquire();
559 // after 1 second, the mutex has been guarded, and the child thread should be running
560 bool bRes1
= myThread
.isRunning();
563 bool bRes2
= aMutex
.tryToAcquire();
565 CPPUNIT_ASSERT_MESSAGE("GuardThread constructor",
566 !bRes
&& bRes1
&& bRes2
);
573 /// use reference constructor here
574 MutexGuard
myGuard( aMutex
);
576 /// the GuardThread will block here when it is initialised.
577 GuardThread
myThread( &aMutex
);
580 /// is it still blocking?
581 ThreadHelper::thread_sleep_tenth_sec( 2 );
582 bool bRes
= myThread
.isRunning( );
588 CPPUNIT_ASSERT_MESSAGE("GuardThread constructor: reference initialization, acquire the mutex before running the thread, then check if it is blocking.",
592 CPPUNIT_TEST_SUITE(ctor
);
593 CPPUNIT_TEST(ctor_001
);
594 CPPUNIT_TEST(ctor_002
);
595 CPPUNIT_TEST_SUITE_END();
598 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Guard::ctor
, "osl_Guard");
599 } // namespace osl_Guard
601 // Beginning of the test cases for osl_ClearableGuard class
603 /** Thread for test ClearableGuard
605 class ClearGuardThread
: public Thread
608 //get the Mutex pointer to operate
609 ClearGuardThread( Mutex
* pMutex
): pMyMutex( pMutex
) {}
611 virtual ~ClearGuardThread( )
613 CPPUNIT_ASSERT_MESSAGE( "#ClearGuardThread does not shutdown properly.\n", !isRunning( ) );
618 void SAL_CALL
run( ) SAL_OVERRIDE
621 // printf("# ClearGuardThread" );
622 ClearableMutexGuard
aGuard( pMyMutex
);
623 ThreadHelper::thread_sleep( 5 );
627 ThreadHelper::thread_sleep( 2 );
631 namespace osl_ClearableGuard
634 class ctor
: public CppUnit::TestFixture
641 /// now, the aMutex has been guarded.
642 ClearableMutexGuard
myMutexGuard( &aMutex
);
644 /// it will return sal_False if the aMutex has not been Guarded.
645 bool bRes
= aMutex
.release( );
647 CPPUNIT_ASSERT_MESSAGE("ClearableMutexGuard constructor, test the acquire operation when initilized.",
655 /// now, the aMutex has been guarded, this time, we use reference constructor.
656 ClearableMutexGuard
myMutexGuard( aMutex
);
658 /// it will return sal_False if the aMutex has not been Guarded.
659 bool bRes
= aMutex
.release( );
661 CPPUNIT_ASSERT_MESSAGE("ClearableMutexGuard constructor, test the acquire operation when initilized, we use reference constructor this time.",
665 CPPUNIT_TEST_SUITE(ctor
);
666 CPPUNIT_TEST(ctor_001
);
667 CPPUNIT_TEST(ctor_002
);
668 CPPUNIT_TEST_SUITE_END();
671 class clear
: public CppUnit::TestFixture
677 ClearGuardThread
myThread(&aMutex
);
680 TimeValue aTimeVal_befor
;
681 osl_getSystemTime( &aTimeVal_befor
);
682 // wait 1 second to assure the child thread has begun
683 ThreadHelper::thread_sleep(1);
687 if (aMutex
.tryToAcquire())
691 ThreadHelper::thread_sleep(1);
693 TimeValue aTimeVal_after
;
694 osl_getSystemTime( &aTimeVal_after
);
695 sal_Int32 nSec
= aTimeVal_after
.Seconds
- aTimeVal_befor
.Seconds
;
696 printf("nSec is %" SAL_PRIdINT32
"\n", nSec
);
700 CPPUNIT_ASSERT_MESSAGE("ClearableGuard method: clear",
701 nSec
< 7 && nSec
> 1);
708 /// now, the aMutex has been guarded.
709 ClearableMutexGuard
myMutexGuard( &aMutex
);
711 /// launch the HoldThread, it will be blocked here.
712 HoldThread
myThread( &aMutex
);
716 ThreadHelper::thread_sleep_tenth_sec( 4 );
717 bool bRes
= myThread
.isRunning( );
719 /// use clear to release.
720 myMutexGuard
.clear( );
722 bool bRes1
= myThread
.isRunning( );
724 CPPUNIT_ASSERT_MESSAGE( "ClearableGuard method: clear, control the HoldThread's running status!",
728 CPPUNIT_TEST_SUITE( clear
);
729 CPPUNIT_TEST( clear_001
);
730 CPPUNIT_TEST( clear_002
);
731 CPPUNIT_TEST_SUITE_END( );
734 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( osl_ClearableGuard::ctor
, "osl_ClearableGuard" );
735 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( osl_ClearableGuard::clear
, "osl_ClearableGuard" );
736 } // namespace osl_ClearableGuard
738 // Beginning of the test cases for osl_ResettableGuard class
740 /** Thread for test ResettableGuard
742 class ResetGuardThread
: public Thread
745 //get the Mutex pointer to operate
746 ResetGuardThread( Mutex
* pMutex
): pMyMutex( pMutex
) {}
748 virtual ~ResetGuardThread( )
750 CPPUNIT_ASSERT_MESSAGE( "#ResetGuardThread does not shutdown properly.\n", !isRunning( ) );
755 void SAL_CALL
run( ) SAL_OVERRIDE
758 printf("# ResettableGuard\n" );
759 ResettableMutexGuard
aGuard( pMyMutex
);
762 ThreadHelper::thread_sleep_tenth_sec( 2 );
766 namespace osl_ResettableGuard
768 class ctor
: public CppUnit::TestFixture
775 /// now, the aMutex has been guarded.
776 ResettableMutexGuard
myMutexGuard( &aMutex
);
778 /// it will return sal_False if the aMutex has not been Guarded.
779 bool bRes
= aMutex
.release( );
781 CPPUNIT_ASSERT_MESSAGE("ResettableMutexGuard constructor, test the acquire operation when initilized.",
789 /// now, the aMutex has been guarded, this time, we use reference constructor.
790 ResettableMutexGuard
myMutexGuard( aMutex
);
792 /// it will return sal_False if the aMutex has not been Guarded.
793 bool bRes
= aMutex
.release( );
795 CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard constructor, test the acquire operation when initilized, we use reference constructor this time.",
799 CPPUNIT_TEST_SUITE(ctor
);
800 CPPUNIT_TEST(ctor_001
);
801 CPPUNIT_TEST(ctor_002
);
802 CPPUNIT_TEST_SUITE_END();
805 class reset
: public CppUnit::TestFixture
811 ResetGuardThread
myThread( &aMutex
);
812 ResettableMutexGuard
myMutexGuard( aMutex
);
815 /// is it running? and clear done?
816 bool bRes
= myThread
.isRunning( );
817 myMutexGuard
.clear( );
818 ThreadHelper::thread_sleep_tenth_sec( 1 );
820 /// if reset is not success, the release will return sal_False
821 myMutexGuard
.reset( );
822 bool bRes1
= aMutex
.release( );
825 CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard method: reset",
833 ResettableMutexGuard
myMutexGuard( &aMutex
);
835 /// shouldn't release after clear;
836 myMutexGuard
.clear( );
837 bool bRes
= aMutex
.release( );
839 /// can release after reset.
840 myMutexGuard
.reset( );
841 bool bRes1
= aMutex
.release( );
843 CPPUNIT_ASSERT_MESSAGE( "ResettableMutexGuard method: reset, release after clear and reset, on Solaris, the mutex can be release without acquire, so it can not passed on (SOLARIS), but not the reason for reset_002",
848 CPPUNIT_TEST_SUITE(reset
);
849 CPPUNIT_TEST(reset_001
);
851 CPPUNIT_TEST(reset_002
);
853 CPPUNIT_TEST_SUITE_END();
856 CPPUNIT_TEST_SUITE_REGISTRATION(osl_ResettableGuard::ctor
);
857 CPPUNIT_TEST_SUITE_REGISTRATION(osl_ResettableGuard::reset
);
858 } // namespace osl_ResettableGuard
860 CPPUNIT_PLUGIN_IMPLEMENT();
862 // The following sets variables for GNU EMACS
867 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */