1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_framework.hxx" 30 31 //_________________________________________________________________________________________________________________ 32 // my own includes 33 //_________________________________________________________________________________________________________________ 34 #include <macros/generic.hxx> 35 #include <macros/debug.hxx> 36 #include <threadhelp/resetableguard.hxx> 37 #include <threadhelp/transactionguard.hxx> 38 39 #ifndef __FRAMEWORK_THREADHELP_RWLOCKBASE_HXX_ 40 #include <threadhelp/rwlockbase.hxx> 41 #endif 42 43 #ifndef __FRAMEWORK_THREADHELP_TRANSACTIONBASE_HXX_ 44 #include <threadhelp/transactionbase.hxx> 45 #endif 46 #include <threadhelp/readguard.hxx> 47 #include <threadhelp/writeguard.hxx> 48 49 //_________________________________________________________________________________________________________________ 50 // interface includes 51 //_________________________________________________________________________________________________________________ 52 53 //_________________________________________________________________________________________________________________ 54 // other includes 55 //_________________________________________________________________________________________________________________ 56 #include <rtl/random.h> 57 #include <vos/process.hxx> 58 #include <vos/thread.hxx> 59 #include <rtl/ustring.hxx> 60 #include <rtl/ustrbuf.hxx> 61 #include <osl/time.h> 62 63 #ifndef _OSL_INTERLOCK_H_ 64 #include <osl/interlock.h> 65 #endif 66 67 #include <vcl/event.hxx> 68 #include <vcl/svapp.hxx> 69 #include <vcl/wrkwin.hxx> 70 #include <vcl/msgbox.hxx> 71 #include <stdio.h> 72 73 //_________________________________________________________________________________________________________________ 74 // const 75 //_________________________________________________________________________________________________________________ 76 77 #define LOGFILE "threadtest.log" 78 #define STATISTICS_FILE "threadtest_statistic.csv" 79 80 //_________________________________________________________________________________________________________________ 81 // namespace 82 //_________________________________________________________________________________________________________________ 83 84 using namespace ::rtl ; 85 using namespace ::osl ; 86 using namespace ::vos ; 87 using namespace ::framework ; 88 89 //_________________________________________________________________________________________________________________ 90 // defines 91 //_________________________________________________________________________________________________________________ 92 93 /*---------------- Use follow defines to enable/disable some special features of this little test program! -------*/ 94 95 #define ENABLE_LOG 96 //#define ENABLE_THREADDELAY 97 #define ENABLE_REQUESTCOUNT 98 99 /*----------------------------------------------------------------------------------------------------------------*/ 100 101 #ifdef ENABLE_LOG 102 #define LOG_SETA_START( NA, NID ) \ 103 { \ 104 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 105 ResetableGuard aLogGuard( m_aLogMutex ); \ 106 OStringBuffer sLog(256); \ 107 sLog.append( (sal_Int32)nTimeStamp ); \ 108 sLog.append( ": Thread[ " ); \ 109 sLog.append( NID ); \ 110 sLog.append( " ] call setA( " ); \ 111 sLog.append( NA ); \ 112 sLog.append( " )\n" ); \ 113 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 114 } 115 116 #define LOG_SETA_END( NA, EREASON, NID ) \ 117 { \ 118 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 119 ResetableGuard aLogGuard( m_aLogMutex ); \ 120 OStringBuffer sLog(256); \ 121 sLog.append( (sal_Int32)nTimeStamp ); \ 122 sLog.append( ": Thread[ " ); \ 123 sLog.append( NID ); \ 124 if( EREASON == E_NOREASON ) \ 125 sLog.append( " ] finish setA( " ); \ 126 else \ 127 sLog.append( " ] was refused at setA( "); \ 128 sLog.append( NA ); \ 129 sLog.append( " )\n" ); \ 130 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 131 } 132 133 #define LOG_GETA_START( NID ) \ 134 { \ 135 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 136 ResetableGuard aLogGuard( m_aLogMutex ); \ 137 OStringBuffer sLog(256); \ 138 sLog.append( (sal_Int32)nTimeStamp ); \ 139 sLog.append( ": Thread[ " ); \ 140 sLog.append( NID ); \ 141 sLog.append( " ] call getA()\n" ); \ 142 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 143 } 144 145 #define LOG_GETA_END( NRETURN, EREASON, NID ) \ 146 { \ 147 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 148 ResetableGuard aLogGuard( m_aLogMutex ); \ 149 OStringBuffer sLog(256); \ 150 sLog.append( (sal_Int32)nTimeStamp ); \ 151 sLog.append( ": Thread[ " ); \ 152 sLog.append( NID ); \ 153 if( EREASON == E_NOREASON ) \ 154 sLog.append( " ] finish getA() with " ); \ 155 else \ 156 sLog.append( " ] was refused at getA() with " ); \ 157 sLog.append( NRETURN ); \ 158 sLog.append( "\n" ); \ 159 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 160 } 161 162 #define LOG_WORKA_START( NA, NID ) \ 163 { \ 164 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 165 ResetableGuard aLogGuard( m_aLogMutex ); \ 166 OStringBuffer sLog(256); \ 167 sLog.append( (sal_Int32)nTimeStamp ); \ 168 sLog.append( ": Thread[ " ); \ 169 sLog.append( NID ); \ 170 sLog.append( " ] call workA( " ); \ 171 sLog.append( NA ); \ 172 sLog.append( " )\n" ); \ 173 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 174 } 175 176 #define LOG_WORKA_END( NRETURN, EREASON, NID ) \ 177 { \ 178 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 179 ResetableGuard aLogGuard( m_aLogMutex ); \ 180 OStringBuffer sLog(256); \ 181 sLog.append( (sal_Int32)nTimeStamp ); \ 182 sLog.append( ": Thread[ " ); \ 183 sLog.append( NID ); \ 184 if( EREASON == E_NOREASON ) \ 185 sLog.append( " ] finish workA() with " ); \ 186 else \ 187 sLog.append( " ] was refused at workA() with " ); \ 188 sLog.append( NRETURN ); \ 189 sLog.append( "\n" ); \ 190 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 191 } 192 193 #define LOG_INITEXCEPTION( SMETHOD, NID ) \ 194 { \ 195 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 196 ResetableGuard aLogGuard( m_aLogMutex ); \ 197 OStringBuffer sLog(256); \ 198 sLog.append( (sal_Int32)nTimeStamp ); \ 199 sLog.append( ": Thread[ " ); \ 200 sLog.append( NID ); \ 201 sLog.append( " ] get EInitException from \"" ); \ 202 sLog.append( SMETHOD ); \ 203 sLog.append( "\"\n" ); \ 204 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 205 } 206 207 #define LOG_CLOSEEXCEPTION( SMETHOD, NID ) \ 208 { \ 209 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 210 ResetableGuard aLogGuard( m_aLogMutex ); \ 211 OStringBuffer sLog(256); \ 212 sLog.append( (sal_Int32)nTimeStamp ); \ 213 sLog.append( ": Thread[ " ); \ 214 sLog.append( NID ); \ 215 sLog.append( " ] get ECloseException from \"" ); \ 216 sLog.append( SMETHOD ); \ 217 sLog.append( "\"\n" ); \ 218 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 219 } 220 221 #define LOG_INIT( NA, NID ) \ 222 { \ 223 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 224 ResetableGuard aLogGuard( m_aLogMutex ); \ 225 OStringBuffer sLog(256); \ 226 sLog.append( (sal_Int32)nTimeStamp ); \ 227 sLog.append( ": Thread[ " ); \ 228 sLog.append( NID ); \ 229 sLog.append( " ] initialize me with " ); \ 230 sLog.append( NA ); \ 231 sLog.append( "\n" ); \ 232 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 233 } 234 235 #define LOG_CLOSE( NID ) \ 236 { \ 237 sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ 238 ResetableGuard aLogGuard( m_aLogMutex ); \ 239 OStringBuffer sLog(256); \ 240 sLog.append( (sal_Int32)nTimeStamp ); \ 241 sLog.append( ": Thread[ " ); \ 242 sLog.append( NID ); \ 243 sLog.append( " ] close me\n" ); \ 244 WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ 245 } 246 #else 247 #define LOG_SETA_START( NA, NID ) 248 #define LOG_SETA_END( NA, EREASON, NID ) 249 #define LOG_GETA_START( NID ) 250 #define LOG_GETA_END( NRETURN, EREASON, NID ) 251 #define LOG_WORKA_START( NA, NID ) 252 #define LOG_WORKA_END( NRETURN, EREASON, NID ) 253 #define LOG_INITEXCEPTION( SMETHOD, NID ) 254 #define LOG_CLOSEEXCEPTION( SMETHOD, NID ) 255 #define LOG_INIT( NA, NID ) 256 #define LOG_CLOSE( NID ) 257 #endif 258 259 //_________________________________________________________________________________________________________________ 260 // declarations 261 //_________________________________________________________________________________________________________________ 262 263 sal_uInt16 getRandomValue() 264 { 265 // Get new random value for thread-sleep! 266 // See run() for further informations. 267 // Always calculate a new random number. 268 sal_uInt16 nValue; 269 rtlRandomPool aPool = rtl_random_createPool(); 270 rtl_random_getBytes ( aPool, &nValue, 2 ); 271 rtl_random_destroyPool ( aPool ); 272 return nValue; 273 } 274 275 /*-************************************************************************************************************//** 276 @descr This class is used from different threads at the same time. 277 We start working after calling init() first(!) ... 278 and finish it by calling close(). It exist two methods for reading/writing an 279 internal variable "A". Another function workA() do both things at the same time. 280 All public methods log information in a file if DO_LOG is defined. 281 282 @attention Our public base class FaiRWLockBase is a struct with a RWLock as member. 283 This member can be used by guards to safe access at internal variables 284 in interface methods. 285 Another baseclass is the TransactionBase. They support rejection of wrong calls at wrong time. 286 e.g. calls after closing object! 287 *//*-*************************************************************************************************************/ 288 289 class ThreadSafeClass : private TransactionBase 290 , private FairRWLockBase 291 { 292 public: 293 294 ThreadSafeClass (); 295 ~ThreadSafeClass(); 296 297 // This methods are used from differnt threads 298 // to test this class. 299 void init ( sal_Int32 nA , 300 sal_Int32 nThreadID ); 301 void close ( sal_Int32 nThreadID ); 302 void setA ( sal_Int32 nA , 303 sal_Int32 nThreadID ); 304 sal_Int32 getA ( sal_Int32 nThreadID ); 305 sal_Int32 workA ( sal_Int32 nA , 306 sal_Int32 nThreadID ); 307 308 #ifdef ENABLE_REQUESTCOUNT 309 // This methods are used for statistics only! 310 sal_Int32 getReadCount () { return m_nReadCount; } 311 sal_Int32 getWriteCount() { return m_nWriteCount; } 312 #endif 313 314 private: 315 316 sal_Int32 m_nA ; /// test member fro reading/writing 317 318 #ifdef ENABLE_LOG 319 ::osl::Mutex m_aLogMutex ; /// mutex to serialize writing log file! 320 #endif 321 322 #ifdef ENABLE_REQUESTCOUNT 323 oslInterlockedCount m_nReadCount ; /// statistic variables to count read/write requests 324 oslInterlockedCount m_nWriteCount ; 325 #endif 326 }; 327 328 //_________________________________________________________________________________________________________________ 329 ThreadSafeClass::ThreadSafeClass() 330 : TransactionBase ( ) 331 , FairRWLockBase ( ) 332 , m_nA ( 0 ) 333 #ifdef ENABLE_REQUESTCOUNT 334 , m_nReadCount ( 0 ) 335 , m_nWriteCount ( 0 ) 336 #endif 337 { 338 } 339 340 //_________________________________________________________________________________________________________________ 341 ThreadSafeClass::~ThreadSafeClass() 342 { 343 } 344 345 //_________________________________________________________________________________________________________________ 346 void ThreadSafeClass::init( sal_Int32 nA, sal_Int32 nThreadID ) 347 { 348 // Set write lock for setting internal member AND 349 // protect changing of working mode! 350 WriteGuard aWriteLock( m_aLock ); 351 352 LOG_INIT( nA, nThreadID ) 353 354 // Look for multiple calls of this method first! 355 // Use E_SOFTEXCEPTIONS to disable automaticly throwing of exceptions for some working modes. 356 ERejectReason eReason; 357 TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); 358 if( eReason == E_UNINITIALIZED ) 359 { 360 // OK, it must be the first call and we are synchronized with all other threads by using the write lock! 361 // Otherwise (e.g. if working mode == E_WORK) we get a exception and follow lines are never called. 362 363 // We can set our member and change the working mode now. 364 m_nA = nA; 365 m_aTransactionManager.setWorkingMode( E_WORK ); 366 } 367 } 368 369 //_________________________________________________________________________________________________________________ 370 void ThreadSafeClass::close( sal_Int32 nThreadID ) 371 { 372 // Make it threadsafe. 373 // It must be an exclusiv access! => WriteLock! 374 WriteGuard aWriteLock( m_aLock ); 375 376 LOG_CLOSE( nThreadID ) 377 378 // We must look for multiple calls of this method. 379 // Try to register this method as a transaction. 380 // In combination with E_HARDEXCEPTIONS only working mode E_WORK pass this barrier. 381 ERejectReason eReason; 382 TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); 383 if( eReason == E_NOREASON ) 384 { 385 // Change working mode to BEFORECLOSE to enable rejection of normal interface calls 386 // and enable SOFTEXCEPTION mode for some impl- or helper methods! 387 // Attention: We must stop successful registered transaction first ... 388 // because setWorkingMode() blocks and wait for all current existing ones! 389 aTransaction.stop(); 390 m_aTransactionManager.setWorkingMode( E_BEFORECLOSE ); 391 392 // Now we are alone ... 393 // All further calls to this object are rejected ... 394 // (not all ... some special ones can work by using E_SOFTEXCEPTIONS!) 395 396 // Deinitialize all member and set working mode to E_CLOSE. 397 m_nA = 0; 398 m_aTransactionManager.setWorkingMode( E_CLOSE ); 399 } 400 } 401 402 //_________________________________________________________________________________________________________________ 403 void ThreadSafeClass::setA( sal_Int32 nA, sal_Int32 nThreadID ) 404 { 405 // Make it threadsafe. 406 WriteGuard aWriteLock( m_aLock ); 407 408 LOG_SETA_START( nA, nThreadID ) 409 410 // Register this method as a transaction to prevent code against wrong calls 411 // after close() or before init()! 412 ERejectReason eReason; 413 TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); 414 if( eReason == E_NOREASON ) 415 { 416 // This object is ready for working and we have full write access. 417 // We can work with our member. 418 m_nA = nA; 419 #ifdef ENABLE_REQUESTCOUNT 420 osl_incrementInterlockedCount( &m_nWriteCount ); 421 #endif 422 } 423 LOG_SETA_END( nA, eReason, nThreadID ) 424 } 425 426 //_________________________________________________________________________________________________________________ 427 sal_Int32 ThreadSafeClass::getA( sal_Int32 nThreadID ) 428 { 429 // Make it threadsafe. 430 ReadGuard aReadLock( m_aLock ); 431 432 LOG_GETA_START( nThreadID ) 433 434 // Register this method as a transaction to prevent code against wrong calls 435 // after close() or before init()! 436 sal_Int32 nReturn = 0; 437 ERejectReason eReason; 438 TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); 439 if( eReason == E_NOREASON ) 440 { 441 // This object is ready for working and we have a read access. 442 // We can work with our member. 443 nReturn = m_nA; 444 #ifdef ENABLE_REQUESTCOUNT 445 osl_incrementInterlockedCount( &m_nReadCount ); 446 #endif 447 } 448 449 LOG_GETA_END( nReturn, eReason, nThreadID ) 450 return nReturn; 451 } 452 453 //_________________________________________________________________________________________________________________ 454 sal_Int32 ThreadSafeClass::workA( sal_Int32 nA , 455 sal_Int32 nThreadID ) 456 { 457 // This method test the downgrade-mechanism of used lock implementation! 458 // Make it threadsafe. 459 WriteGuard aWriteLock( m_aLock ); 460 461 LOG_WORKA_START( nA, nThreadID ) 462 463 // Register this method as a transaction to prevent code against wrong calls 464 // after close() or before init()! 465 sal_Int32 nReturn = 0; 466 ERejectReason eReason; 467 TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); 468 if( eReason == E_NOREASON ) 469 { 470 // We have write access to our member. 471 // Set new value. 472 m_nA = nA; 473 #ifdef ENABLE_REQUESTCOUNT 474 osl_incrementInterlockedCount( &m_nWriteCount ); 475 #endif 476 477 // Downgrade write access to read access and read the set value again. 478 // This call can't be rejected - but it can fail! 479 aWriteLock.downgrade(); 480 nReturn = m_nA; 481 #ifdef ENABLE_REQUESTCOUNT 482 osl_incrementInterlockedCount( &m_nReadCount ); 483 #endif 484 } 485 486 LOG_WORKA_END( nReturn, eReason, nThreadID ) 487 return nReturn; 488 } 489 490 /*-****************************************************************************************************//** 491 @descr Every thread instance of these class lopp from 0 up to "nLoops". 492 He sleep for a random time and work with given test class "pClass" then. 493 We use random values for waiting for better results! 494 Otherwise all threads are sychron after first 2,3...5 calls - I think! 495 *//*-*****************************************************************************************************/ 496 497 class TestThread : public OThread 498 { 499 public: 500 501 TestThread( ThreadSafeClass* pClass , 502 sal_Int32 nLoops , 503 Condition* pListener , 504 sal_Bool bOwner = sal_False ); 505 506 private: 507 508 virtual void SAL_CALL run (); 509 virtual void SAL_CALL onTerminated (); 510 511 private: 512 513 ThreadSafeClass* m_pClass ; 514 sal_Int32 m_nLoops ; 515 sal_Int32 m_nThreadID ; 516 Condition* m_pListener ; 517 sal_Bool m_bOwner ; 518 }; 519 520 //_________________________________________________________________________________________________________________ 521 TestThread::TestThread( ThreadSafeClass* pClass , 522 sal_Int32 nLoops , 523 Condition* pListener , 524 sal_Bool bOwner ) 525 : m_pClass ( pClass ) 526 , m_nLoops ( nLoops ) 527 , m_pListener ( pListener ) 528 , m_bOwner ( bOwner ) 529 { 530 } 531 532 //_________________________________________________________________________________________________________________ 533 void SAL_CALL TestThread::run() 534 { 535 // Get ID of this thread. 536 // Is used for logging information ... 537 m_nThreadID = getCurrentIdentifier(); 538 539 // If we are the owner of given pClass 540 // we must initialize ... and close 541 // it. See at the end of this method too. 542 if( m_bOwner == sal_True ) 543 { 544 m_pClass->init( 0, m_nThreadID ); 545 } 546 547 #ifdef ENABLE_THREADDELAY 548 TimeValue nDelay ; 549 #endif 550 551 sal_Int32 nA ; 552 553 for( sal_Int32 nCount=0; nCount<m_nLoops; ++nCount ) 554 { 555 // Work with class. 556 // Use random to select called method. 557 nA = (sal_Int32)getRandomValue(); 558 if( nA % 5 == 0 ) 559 { 560 nA = m_pClass->workA( nA, m_nThreadID ); 561 } 562 else 563 if( nA % 3 == 0 ) 564 { 565 m_pClass->setA( nA, m_nThreadID ); 566 } 567 else 568 { 569 nA = m_pClass->getA( m_nThreadID ); 570 } 571 #ifdef ENABLE_THREADDELAY 572 // Sleep - use random value to do that too! 573 nDelay.Seconds = 0; 574 nDelay.Nanosec = getRandomValue(); 575 sleep( nDelay ); 576 #endif 577 } 578 579 // Don't forget to "close" teset object if you are the owner! 580 if( m_bOwner == sal_True ) 581 { 582 m_pClass->close( m_nThreadID ); 583 } 584 } 585 586 //_________________________________________________________________________________________________________________ 587 void SAL_CALL TestThread::onTerminated() 588 { 589 // Destroy yourself if you finished. 590 // But don't forget to call listener before. 591 m_pListener->set(); 592 593 m_pClass = NULL; 594 m_pListener = NULL; 595 596 delete this; 597 } 598 599 /*-****************************************************************************************************//** 600 @descr This is our test application. 601 We create one ThreadSafeClass object and a lot of threads 602 which use it at different times. 603 *//*-*****************************************************************************************************/ 604 605 struct ThreadInfo 606 { 607 Condition* pCondition ; 608 TestThread* pThread ; 609 }; 610 611 class TestApplication : public Application 612 { 613 public: 614 void Main ( ); 615 sal_Int32 measureTime ( sal_Int32 nThreadCount , 616 sal_Int32 nOwner , 617 sal_Int32 nLoops=0 ); 618 }; 619 620 //_________________________________________________________________________________________________________________ 621 // definition 622 //_________________________________________________________________________________________________________________ 623 624 TestApplication aApplication; 625 626 //_________________________________________________________________________________________________________________ 627 // This function start "nThreadCount" threads to use same test class. 628 // You can specify the owner thread of this test class which start/stop it by using "nOwner". [1..nThreadcount]! 629 // If you specify "nLoops" different from 0 we use it as loop count for every started thread. 630 // Otherwise we work with random values. 631 sal_Int32 TestApplication::measureTime( sal_Int32 nThreadCount , 632 sal_Int32 nOwner , 633 sal_Int32 nLoops ) 634 { 635 // This is the class which should be tested. 636 ThreadSafeClass aClass; 637 638 // Create list of threads. 639 ThreadInfo* pThreads = new ThreadInfo[nThreadCount]; 640 sal_Int32 nLoopCount = nLoops ; 641 sal_Bool bOwner = sal_False ; 642 for( sal_Int32 nI=1; nI<=nThreadCount; ++nI ) 643 { 644 // If nLoops==0 => we must use random value; otherwise we must use given count ... 645 if( nLoops == 0 ) 646 { 647 nLoopCount = getRandomValue(); 648 } 649 // Search owner of class. 650 bOwner = sal_False; 651 if( nOwner == nI ) 652 { 653 bOwner = sal_True; 654 } 655 // initialize condition. 656 pThreads[nI].pCondition = new Condition; 657 // Initialize thread. 658 pThreads[nI].pThread = new TestThread( &aClass, nLoopCount, pThreads[nI].pCondition, bOwner ); 659 } 660 661 // Start clock to get information about used time. 662 sal_uInt32 nStartTime ; 663 sal_uInt32 nEndTime ; 664 665 nStartTime = osl_getGlobalTimer(); 666 667 // Start threads ... 668 for( nI=1; nI<=nThreadCount; ++nI ) 669 { 670 pThreads[nI].pThread->create(); 671 } 672 673 // Wait for threads ... 674 for( nI=1; nI<=nThreadCount; ++nI ) 675 { 676 pThreads[nI].pCondition->wait(); 677 delete pThreads[nI].pCondition; 678 pThreads[nI].pCondition = NULL; 679 } 680 681 delete[] pThreads; 682 pThreads = NULL; 683 684 nEndTime = osl_getGlobalTimer(); 685 686 // Calc used time and return it. [ms] 687 return( nEndTime-nStartTime ); 688 } 689 690 //_________________________________________________________________________________________________________________ 691 void TestApplication::Main() 692 { 693 sal_Int32 nTestCount = 0; /// count of calling "measureTime()" 694 sal_Int32 nThreadCount = 0; /// count of used threads by "measure..." 695 sal_Int32 nLoops = 0; /// loop count for every thread 696 sal_Int32 nOwner = 0; /// number of owner thread 697 698 // Parse command line. 699 // Attention: All parameter are required and must exist! 700 // syntax: "threadtest.exe <testcount> <threadcount> <loops> <owner>" 701 OStartupInfo aInfo ; 702 OUString sArgument ; 703 sal_Int32 nArgument ; 704 sal_Int32 nCount = aInfo.getCommandArgCount(); 705 706 LOG_ASSERT2( nCount!=4 ,"TestApplication::Main()" , "Wrong argument line detected!") 707 708 for( nArgument=0; nArgument<nCount; ++nArgument ) 709 { 710 aInfo.getCommandArg( nArgument, sArgument ); 711 if( nArgument== 0 ) nTestCount =sArgument.toInt32(); 712 if( nArgument== 1 ) nThreadCount=sArgument.toInt32(); 713 if( nArgument== 2 ) nLoops =sArgument.toInt32(); 714 if( nArgument== 3 ) nOwner =sArgument.toInt32(); 715 } 716 717 // Start test. 718 OStringBuffer sBuf(256); 719 sal_Int32 nTime=0; 720 sBuf.append( "Nr.\tTime\tThreadCount\tLoops\tOwner\n" ); 721 for( sal_Int32 nI=1; nI<=nTestCount; ++nI ) 722 { 723 nTime = measureTime( nThreadCount, nOwner, nLoops ); 724 sBuf.append( nI ); 725 sBuf.append( "\t" ); 726 sBuf.append( nTime ); 727 sBuf.append( "\t" ); 728 sBuf.append( nThreadCount ); 729 sBuf.append( "\t" ); 730 sBuf.append( nLoops ); 731 sBuf.append( "\t" ); 732 sBuf.append( nOwner ); 733 sBuf.append( "\n" ); 734 } 735 736 WRITE_LOGFILE( STATISTICS_FILE, sBuf.makeStringAndClear() ); 737 LOG_ERROR( "TApplication::Main()", "Test finish successful!" ) 738 } 739