1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: osl_Semaphore.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
34 //------------------------------------------------------------------------
36 //------------------------------------------------------------------------
37 #include <osl_Semaphore_Const.h>
43 //------------------------------------------------------------------------
44 // helper functions and classes
45 //------------------------------------------------------------------------
47 /** print Boolean value.
49 inline void printBool( sal_Bool bOk
)
51 t_print("#printBool# " );
52 ( sal_True
== bOk
) ? t_print("YES!\n" ): t_print("NO!\n" );
55 /** print a UNI_CODE String.
57 inline void printUString( const ::rtl::OUString
& str
)
61 t_print("#printUString_u# " );
62 aString
= ::rtl::OUStringToOString( str
, RTL_TEXTENCODING_ASCII_US
);
63 t_print("%s\n", aString
.getStr( ) );
66 /** wait _nSec seconds.
68 void thread_sleep( sal_Int32 _nSec
)
70 /// print statement in thread process must use fflush() to force display.
71 // t_print("wait %d seconds. ", _nSec );
75 Sleep( _nSec
* 1000 );
77 #if ( defined UNX ) || ( defined OS2 ) //Unix
82 void thread_sleep_tenth_sec(sal_Int32 _nTenthSec
)
85 Sleep(_nTenthSec
* 100 );
87 #if ( defined UNX ) || ( defined OS2 ) //Unix
89 nTV
.Seconds
= static_cast<sal_uInt32
>( _nTenthSec
/10 );
90 nTV
.Nanosec
= ( (_nTenthSec
%10 ) * 100000000 );
95 /** thread for testing Semaphore acquire.
97 class HoldThread
: public Thread
100 //get the Semaphores to operate
101 HoldThread( ::osl::Semaphore
& Sem
): MySem( Sem
) { }
105 CPPUNIT_ASSERT_MESSAGE( "#HoldThread does not shutdown properly.\n", sal_False
== this -> isRunning( ) );
108 ::osl::Semaphore
& MySem
;
112 // block here if it tries to decrease below zero.
114 t_print("Semaphore acquired. \n" );
119 /** thread for testing Semaphore release and tryToAcquire.
121 class WaitThread
: public Thread
124 //get the Semaphore pointer to operate
125 WaitThread( ::osl::Semaphore
& Sem
): MySem( Sem
) { }
129 CPPUNIT_ASSERT_MESSAGE( "WaitThread does not shutdown properly.\n", sal_False
== this -> isRunning( ) );
136 // block here if the semaphore has been acquired
138 thread_sleep_tenth_sec( 2 );
143 /** thread for producer-consumer model.
149 sal_Int32 Buf
[BSIZE
];
150 ::osl::Semaphore
& aSemOccupied
;
151 ::osl::Semaphore
& aSemEmpty
;
152 ::osl::Mutex
& aMutex
;
154 SemBuffer( ::osl::Semaphore
& Sem
, ::osl::Semaphore
& Sem1
, ::osl::Mutex
& Mut
)
155 :aSemOccupied( Sem
), aSemEmpty( Sem1
), aMutex( Mut
)
157 for ( sal_Int8 iCount
=0; iCount
< BSIZE
; iCount
++ )
162 class WriterThread
: public Thread
165 //get the Semaphores to operate
166 WriterThread( SemBuffer
& aSemBuffer
): MySemBuffer( aSemBuffer
){ }
170 CPPUNIT_ASSERT_MESSAGE( "WriterThread does not shutdown properly.\n", sal_False
== this -> isRunning( ) );
173 SemBuffer
& MySemBuffer
;
177 for ( sal_Int32 iCount
= 0; iCount
< BSIZE
; iCount
++ )
179 MySemBuffer
.aSemEmpty
.acquire( ) ;
180 MySemBuffer
.aMutex
.acquire( ) ;
181 MySemBuffer
.Buf
[iCount
] = iCount
;
182 MySemBuffer
.aMutex
.release( ) ;
183 MySemBuffer
.aSemOccupied
.release( ) ;
188 class ReaderThread
: public Thread
191 //get the Semaphores to operate
192 ReaderThread( SemBuffer
& aSemBuffer
): MySemBuffer( aSemBuffer
){ }
196 CPPUNIT_ASSERT_MESSAGE( "ReaderThread does not shutdown properly.\n", sal_False
== this -> isRunning( ) );
200 SemBuffer
& MySemBuffer
;
204 for ( sal_Int32 iCount
= 0; iCount
< BSIZE
; iCount
++ )
206 MySemBuffer
.aSemOccupied
.acquire( ) ;
207 MySemBuffer
.aMutex
.acquire( ) ;
208 MySemBuffer
.Buf
[iCount
] *= MySemBuffer
.Buf
[iCount
];
209 MySemBuffer
.aMutex
.release( ) ;
210 MySemBuffer
.aSemEmpty
.release( ) ;
217 //------------------------------------------------------------------------
218 // test code start here
219 //------------------------------------------------------------------------
221 namespace osl_Semaphore
224 /** testing the method:
225 Semaphore(sal_uInt32 initialCount);
227 class ctors
: public CppUnit::TestFixture
230 sal_Bool bRes
, bRes1
;
234 ::osl::Semaphore
aSem(sal_uInt32(0));
235 bRes
= aSem
.tryToAcquire( );
237 CPPUNIT_ASSERT_MESSAGE( "#test comment#: create semaphore with initialCount = 0. the first acquire will block.",
243 ::osl::Semaphore
aSem(sal_uInt32(1));
244 bRes
= aSem
.tryToAcquire( );
245 if ( sal_True
== bRes
)
248 CPPUNIT_ASSERT_MESSAGE( "#test comment#: create semaphore with initialCount = 1. the first acquire will not block.",
254 ::osl::Semaphore
aSem(sal_uInt32(1));
255 bRes
= aSem
.tryToAcquire( );
256 bRes1
= aSem
.tryToAcquire( );
258 CPPUNIT_ASSERT_MESSAGE( "#test comment#: create semaphore with initialCount = 1. acquire twice will cause block.",
259 sal_True
== bRes
&& sal_False
== bRes1
);
264 oslSemaphore hSem
= new ::osl::Semaphore(sal_uInt32(1));
266 CPPUNIT_ASSERT_MESSAGE( "#test comment#: test return value of the constructor, it should not be NULL.",
272 ::osl::Semaphore
aSemaphore(sal_uInt32(2));
273 bRes
= aSemaphore
.tryToAcquire( )&&
274 aSemaphore
.tryToAcquire( )&&
275 !aSemaphore
.tryToAcquire( );
277 CPPUNIT_ASSERT_MESSAGE( "#test comment#: create semaphore with initialCount = 2. guess what behaviour will the semaphore act like.",
281 CPPUNIT_TEST_SUITE( ctors
);
282 CPPUNIT_TEST( ctors_001
);
283 CPPUNIT_TEST( ctors_002
);
284 CPPUNIT_TEST( ctors_003
);
285 CPPUNIT_TEST( ctors_004
);
286 CPPUNIT_TEST( ctors_005
);
287 CPPUNIT_TEST_SUITE_END( );
291 /** testing the method:
294 class acquire
: public CppUnit::TestFixture
297 sal_Bool bRes
, bRes1
, bRes2
;
300 acquire semaphore in main thread, and then call acquire again in myThread,
301 the child thread should block, wait 2 secs, it still block. Then release
302 semaphore in main thread, the child thread could return from acquire, and
303 go to exec next statement, so could terminate quickly.
308 // launch the child thread
309 ::osl::Semaphore
aSemaphore(1);
310 bRes
= aSemaphore
.acquire( );
311 HoldThread
myThread( aSemaphore
);
314 // if acquire in myThread does not work, 2 secs is long enough,
315 // myThread should terminate now, and bRes1 should be sal_False
316 thread_sleep_tenth_sec( 2 );
317 bRes1
= myThread
.isRunning( );
319 // after release semaphore, myThread stops blocking and will terminate immediately
320 aSemaphore
.release( );
321 thread_sleep_tenth_sec( 1 );
322 bRes2
= myThread
.isRunning( );
325 CPPUNIT_ASSERT_MESSAGE( "#test comment#: test acquire of Semaphore.",
326 bRes
== sal_True
&& bRes1
== sal_True
&& bRes2
== sal_False
);
330 launch 3 thread for testing acquirement inter-process.
335 // launch three child threads
336 ::osl::Semaphore
aSemaphore(1);
337 bRes
= aSemaphore
.acquire( );
338 HoldThread
myThread1( aSemaphore
);
340 HoldThread
myThread2( aSemaphore
);
342 HoldThread
myThread3( aSemaphore
);
345 // if acquire in myThread does not work, 2 secs is long enough,
346 thread_sleep_tenth_sec( 2 );
347 bRes1
= myThread1
.isRunning( ) && myThread2
.isRunning( ) && myThread3
.isRunning( );
349 // after release semaphore, myThread stops blocking and will terminate immediately
350 aSemaphore
.release( );
351 thread_sleep_tenth_sec( 1 );
352 bRes2
= myThread1
.isRunning( ) || myThread2
.isRunning( ) || myThread3
.isRunning( );
357 CPPUNIT_ASSERT_MESSAGE( "#test comment#: test acquire of Semaphore in multithreaded environment.",
358 bRes
== sal_True
&& bRes1
== sal_True
&& bRes2
== sal_False
);
364 launch 3 thread for testing acquirement inter-process. in this test,
365 we use two threads as producer and consumer, operate together on an
366 array which is initialized to 0 for every item. producer takes action
368 p(A), p(M), Buf[i]=i, v(M), v(B).
369 consumer's action is like:
370 p(B), p(M), Buf[i]=Buf[i]*Buf[i], v(M), v(A).
371 consumer must operate on the array after producer does sequetially,
372 otherwise, the array will contain items remain zero after all threads
373 terminate. array will be filled with index^2 in the end.
379 ::osl::Semaphore
aSemOccupied( sal_uInt32(0) );
380 ::osl::Semaphore
aSemEmpty( BSIZE
);
383 // launch two threads.
384 SemBuffer
aBuffer( aSemOccupied
, aSemEmpty
, aMutex
);
385 WriterThread
myThread1( aBuffer
);
386 ReaderThread
myThread2( aBuffer
);
394 for ( sal_Int32 iCount
= 0; iCount
< BSIZE
; iCount
++ )
395 bRes
= bRes
&& ( aBuffer
.Buf
[iCount
] == iCount
*iCount
);
397 CPPUNIT_ASSERT_MESSAGE( "#test comment#: test acquire of Semaphore using Producer-Consumer model.",
401 CPPUNIT_TEST_SUITE( acquire
);
402 CPPUNIT_TEST( acquire_001
);
403 CPPUNIT_TEST( acquire_002
);
404 CPPUNIT_TEST( acquire_003
);
405 CPPUNIT_TEST_SUITE_END( );
409 /** testing the method:
410 sal_Bool tryToAcquire();
412 class tryToAcquire
: public CppUnit::TestFixture
415 sal_Bool bRes
, bRes1
, bRes2
;
417 First let child thread acquire the semaphore, and wait 2 secs, during the 2 secs,
418 in main thread, tryToAcquire semaphore should return False, then after the
419 child thread terminated, tryToAcquire should return True
421 void tryToAcquire_001()
423 ::osl::Semaphore
aSemaphore(1);
424 WaitThread
myThread( aSemaphore
);
427 // ensure the child thread acquire the semaphore
428 thread_sleep_tenth_sec(1);
429 bRes1
= aSemaphore
.tryToAcquire();
431 if (bRes1
== sal_True
)
432 aSemaphore
.release();
433 // wait the child thread terminate
436 bRes2
= aSemaphore
.tryToAcquire();
437 if (bRes2
== sal_True
)
438 aSemaphore
.release();
440 CPPUNIT_ASSERT_MESSAGE("#test comment#: Try to acquire Semaphore",
441 bRes1
== sal_False
&& bRes2
== sal_True
);
444 void tryToAcquire_002()
446 ::osl::Semaphore
aSem(1);
447 bRes
= aSem
.tryToAcquire( );
448 bRes1
= aSem
.tryToAcquire( );
451 CPPUNIT_ASSERT_MESSAGE("#test comment#: Try to acquire Semaphore twice should block.",
452 sal_True
== bRes
&& sal_False
== bRes1
);
455 CPPUNIT_TEST_SUITE( tryToAcquire
);
456 CPPUNIT_TEST( tryToAcquire_001
);
457 CPPUNIT_TEST( tryToAcquire_002
);
458 CPPUNIT_TEST_SUITE_END( );
459 }; // class tryToAcquire
462 /** testing the method:
465 class release
: public CppUnit::TestFixture
468 sal_Bool bRes
, bRes1
, bRes2
, bRunning
;
470 /** acquire/release are not used in pairs: after child thread acquired semaphore,
471 the main thread release it, then any thread could acquire it.
475 Semaphore
aSemaphore(1);
476 WaitThread
myThread( aSemaphore
);
479 // ensure the child thread acquire the mutex
480 thread_sleep_tenth_sec( 1 );
482 bRunning
= myThread
.isRunning( );
483 bRes1
= aSemaphore
.tryToAcquire( );
484 // wait the child thread terminate
487 bRes2
= aSemaphore
.tryToAcquire( );
488 if ( bRes2
== sal_True
)
489 aSemaphore
.release( );
491 CPPUNIT_ASSERT_MESSAGE( "release Semaphore: try to aquire before and after the semaphore has been released",
492 bRes1
== sal_False
&& bRes2
== sal_True
&& bRunning
== sal_True
);
498 Semaphore
aSemaphore(sal_uInt32(0));
500 for ( nCount
= 0; nCount
< 10; nCount
++, aSemaphore
.release( ) ) { }
501 for ( nCount
= 0; nCount
< 10; nCount
++, bRes1
= bRes1
&& aSemaphore
.tryToAcquire( ) ) { }
502 bRes
= aSemaphore
.tryToAcquire( );
504 CPPUNIT_ASSERT_MESSAGE( "release Semaphore: release ten times and acquire eleven times.",
505 sal_False
== bRes
&& sal_True
== bRes1
);
508 CPPUNIT_TEST_SUITE( release
);
509 CPPUNIT_TEST( release_001
);
510 CPPUNIT_TEST( release_002
);
511 CPPUNIT_TEST_SUITE_END( );
514 // -----------------------------------------------------------------------------
515 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Semaphore::ctors
, "osl_Semaphore");
516 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Semaphore::acquire
, "osl_Semaphore");
517 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Semaphore::tryToAcquire
, "osl_Semaphore");
518 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Semaphore::release
, "osl_Semaphore");
519 // -----------------------------------------------------------------------------
521 } // namespace osl_Semaphore
524 // -----------------------------------------------------------------------------
526 // this macro creates an empty function, which will called by the RegisterAllFunctions()
527 // to let the user the possibility to also register some functions by hand.