2014-09-25 11:22:39 +01:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
/*
|
2015-10-01 13:20:07 +02:00
|
|
|
* Timers are evil beasts across platforms...
|
2014-09-25 11:22:39 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <test/bootstrapfixture.hxx>
|
|
|
|
|
|
|
|
#include <osl/thread.hxx>
|
2016-03-22 03:25:02 +05:30
|
|
|
#include <chrono>
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
#include <vcl/timer.hxx>
|
2015-01-14 13:11:28 +00:00
|
|
|
#include <vcl/idle.hxx>
|
2014-09-25 11:22:39 +01:00
|
|
|
#include <vcl/svapp.hxx>
|
2016-09-14 15:33:54 +02:00
|
|
|
#include <vcl/scheduler.hxx>
|
2017-10-23 22:28:18 +02:00
|
|
|
#include <svdata.hxx>
|
|
|
|
#include <salinst.hxx>
|
2015-06-10 12:08:00 +01:00
|
|
|
|
|
|
|
// #define TEST_WATCHDOG
|
2015-08-28 08:00:20 +01:00
|
|
|
|
|
|
|
// Enables timer tests that appear to provoke windows under load unduly.
|
2015-08-25 11:04:38 +02:00
|
|
|
//#define TEST_TIMERPRECISION
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
/// Avoid our timer tests just wedging the build if they fail.
|
|
|
|
class WatchDog : public osl::Thread
|
|
|
|
{
|
2018-09-13 13:08:33 +02:00
|
|
|
sal_Int32 const mnSeconds;
|
2014-09-25 11:22:39 +01:00
|
|
|
public:
|
2015-05-25 09:35:57 +01:00
|
|
|
explicit WatchDog(sal_Int32 nSeconds) :
|
2014-09-25 11:22:39 +01:00
|
|
|
Thread(),
|
|
|
|
mnSeconds( nSeconds )
|
|
|
|
{
|
|
|
|
create();
|
|
|
|
}
|
2015-10-12 16:04:04 +02:00
|
|
|
virtual void SAL_CALL run() override
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
2016-03-22 03:25:02 +05:30
|
|
|
osl::Thread::wait( std::chrono::seconds(mnSeconds) );
|
2015-08-28 09:40:02 +03:00
|
|
|
fprintf(stderr, "ERROR: WatchDog timer thread expired, failing the test!\n");
|
|
|
|
fflush(stderr);
|
2014-09-25 11:22:39 +01:00
|
|
|
CPPUNIT_ASSERT_MESSAGE("watchdog triggered", false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
Avoid "ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call)"
...during CppunitTest_vcl_timer:
> WARNING: ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call) (pid=3753)
> Write of size 8 at 0x7ffa5fa31348 by main thread:
> #0 ~Thread include/osl/thread.hxx:66 (libtest_vcl_timer.so+0xcbae)
> #1 ~WatchDog vcl/qa/cppunit/timer.cxx:32 (libtest_vcl_timer.so+0xaa08)
> #2 at_exit_wrapper(void*) compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:361 (cppunittester+0x44c823)
>
> Previous read of size 8 at 0x7ffa5fa31348 by thread T2:
> #0 threadFunc include/osl/thread.hxx:185 (libtest_vcl_timer.so+0xcc54)
> #1 osl_thread_start_Impl(void*) sal/osl/unx/thread.cxx:237 (libuno_sal.so.3+0xeb5c5)
>
> As if synchronized via sleep:
> #0 nanosleep compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:343 (cppunittester+0x474d47)
> #1 osl_waitThread sal/osl/unx/thread.cxx:520 (libuno_sal.so.3+0xea531)
> #2 osl::Thread::wait(TimeValue const&) include/osl/thread.hxx:143 (libtest_vcl_timer.so+0xcd68)
> #3 SlowCallbackTimer::Invoke() vcl/qa/cppunit/timer.cxx:372 (libtest_vcl_timer.so+0xdb0a)
> #4 Scheduler::ProcessTaskScheduling() vcl/source/app/scheduler.cxx:381 (libvcllo.so+0x1074fff)
> #5 Scheduler::CallbackTaskScheduling() vcl/source/app/scheduler.cxx:204 (libvcllo.so+0x1073ba5)
> #6 SalTimer::CallCallback() vcl/inc/saltimer.hxx:54 (libvcllo.so+0x138548f)
> #7 SvpSalInstance::CheckTimeout(bool) vcl/headless/svpinst.cxx:242 (libvcllo.so+0x1382742)
> #8 SvpSalInstance::DoYield(bool, bool, unsigned long) vcl/headless/svpinst.cxx:349 (libvcllo.so+0x1383403)
> #9 ImplYield(bool, bool, unsigned long) vcl/source/app/svapp.cxx:470 (libvcllo.so+0x10c344e)
> #10 Application::Yield() vcl/source/app/svapp.cxx:540 (libvcllo.so+0x10bad80)
> #11 TimerTest::testSlowTimerCallback() vcl/qa/cppunit/timer.cxx:385 (libtest_vcl_timer.so+0x8506)
> #12 void std::__invoke_impl<void, void (TimerTest::* const&)(), TimerTest*&>(std::__invoke_memfun_deref, void (TimerTest::* const&)(), TimerTest*&) /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:227 (libtest_vcl_timer.so+0x15e2e)
> #13 std::result_of<void (TimerTest::* const&(TimerTest*&))()>::type std::__invoke<void (TimerTest::* const&)(), TimerTest*&>(void (TimerTest::* const&)(), TimerTest*&) /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:250 (libtest_vcl_timer.so+0x15d1d)
> #14 _ZNKSt12_Mem_fn_baseIM9TimerTestFvvELb1EEclIJRPS0_EEEDTclsr3stdE8__invokedtdefpT6_M_pmfspclsr3stdE7forwardIT_Efp_EEEDpOS7_ /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:604 (libtest_vcl_timer.so+0x15bfb)
> #15 void std::_Bind<std::_Mem_fn<void (TimerTest::*)()> (TimerTest*)>::__call<void, , 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:933 (libtest_vcl_timer.so+0x15b5b)
> #16 void std::_Bind<std::_Mem_fn<void (TimerTest::*)()> (TimerTest*)>::operator()<, void>() /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:991 (libtest_vcl_timer.so+0x15a26)
> #17 std::_Function_handler<void (), std::_Bind<std::_Mem_fn<void (TimerTest::*)()> (TimerTest*)> >::_M_invoke(std::_Any_data const&) /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:1731 (libtest_vcl_timer.so+0x1530a)
> #18 std::function<void ()>::operator()() const /usr/lib/gcc/x86_64-redhat-linux/6.4.1/../../../../include/c++/6.4.1/functional:2127 (libtest_vcl_timer.so+0x1616e)
> #19 CppUnit::TestCaller<TimerTest>::runTest() workdir/UnpackedTarball/cppunit/include/cppunit/TestCaller.h:175 (libtest_vcl_timer.so+0x14a5c)
> #20 CppUnit::TestCaseMethodFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/TestCase.cpp:32 (libcppunit-1.14.so.0+0xd61d2)
> #21 (anonymous namespace)::Protector::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) test/source/vclbootstrapprotector.cxx:39 (libvclbootstrapprotector.so+0x1114)
> #22 CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20 (libcppunit-1.14.so.0+0xc7614)
> #23 (anonymous namespace)::Prot::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) unotest/source/cpp/unobootstrapprotector/unobootstrapprotector.cxx:89 (unobootstrapprotector.so+0x2204)
> #24 CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20 (libcppunit-1.14.so.0+0xc7614)
> #25 (anonymous namespace)::Prot::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) unotest/source/cpp/unoexceptionprotector/unoexceptionprotector.cxx:63 (unoexceptionprotector.so+0x23e9)
> #26 CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20 (libcppunit-1.14.so.0+0xc7614)
> #27 CppUnit::DefaultProtector::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) workdir/UnpackedTarball/cppunit/src/cppunit/DefaultProtector.cpp:15 (libcppunit-1.14.so.0+0xa57ad)
> #28 CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20 (libcppunit-1.14.so.0+0xc7614)
> #29 CppUnit::ProtectorChain::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:86 (libcppunit-1.14.so.0+0xc4a96)
> #30 CppUnit::TestResult::protect(CppUnit::Functor const&, CppUnit::Test*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) workdir/UnpackedTarball/cppunit/src/cppunit/TestResult.cpp:182 (libcppunit-1.14.so.0+0xf4714)
> #31 CppUnit::TestCase::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestCase.cpp:91 (libcppunit-1.14.so.0+0xd5750)
> #32 CppUnit::TestComposite::doRunChildTests(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:64 (libcppunit-1.14.so.0+0xd6d5a)
> #33 CppUnit::TestComposite::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:23 (libcppunit-1.14.so.0+0xd6a2e)
> #34 CppUnit::TestComposite::doRunChildTests(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:64 (libcppunit-1.14.so.0+0xd6d5a)
> #35 CppUnit::TestComposite::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:23 (libcppunit-1.14.so.0+0xd6a2e)
> #36 CppUnit::TestRunner::WrappingSuite::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestRunner.cpp:47 (libcppunit-1.14.so.0+0x10282c)
> #37 CppUnit::TestResult::runTest(CppUnit::Test*) workdir/UnpackedTarball/cppunit/src/cppunit/TestResult.cpp:149 (libcppunit-1.14.so.0+0xf4223)
> #38 CppUnit::TestRunner::run(CppUnit::TestResult&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) workdir/UnpackedTarball/cppunit/src/cppunit/TestRunner.cpp:96 (libcppunit-1.14.so.0+0x102c76)
> #39 (anonymous namespace)::ProtectedFixtureFunctor::run() const sal/cppunittester/cppunittester.cxx:316 (cppunittester+0x4bd1e8)
> #40 sal_main() sal/cppunittester/cppunittester.cxx:466 (cppunittester+0x4bbe1e)
> #41 main sal/cppunittester/cppunittester.cxx:373 (cppunittester+0x4bb695)
>
> Location is global '<null>' at 0x000000000000 (libtest_vcl_timer.so+0x00000021d348)
>
> Thread T2 (tid=3925, running) created by main thread at:
> #0 pthread_create compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:887 (cppunittester+0x451186)
> #1 osl_thread_create_Impl(void (*)(void*), void*, short) sal/osl/unx/thread.cxx:286 (libuno_sal.so.3+0xe93ee)
> #2 osl_createSuspendedThread sal/osl/unx/thread.cxx:337 (libuno_sal.so.3+0xe974d)
> #3 osl::Thread::create() include/osl/thread.hxx:73 (libtest_vcl_timer.so+0xc349)
> #4 WatchDog vcl/qa/cppunit/timer.cxx:40 (libtest_vcl_timer.so+0xa99f)
> #5 __cxx_global_var_init.1 vcl/qa/cppunit/timer.cxx:51 (libtest_vcl_timer.so+0x6fd1)
> #6 _GLOBAL__sub_I_timer.cxx vcl/qa/cppunit/timer.cxx:? (libtest_vcl_timer.so+0x70af)
> #7 call_init /usr/src/debug/glibc-2.24-61-g605e6f9/elf/dl-init.c:72 (ld-linux-x86-64.so.2+0x10d99)
> #8 CppUnit::DynamicLibraryManager::doLoadLibrary(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) workdir/UnpackedTarball/cppunit/src/cppunit/UnixDynamicLibraryManager.cpp:16 (libcppunit-1.14.so.0+0x10ee31)
> #9 CppUnit::DynamicLibraryManager::loadLibrary(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) workdir/UnpackedTarball/cppunit/src/cppunit/DynamicLibraryManager.cpp:49 (libcppunit-1.14.so.0+0xa5f6d)
> #10 DynamicLibraryManager workdir/UnpackedTarball/cppunit/src/cppunit/DynamicLibraryManager.cpp:13 (libcppunit-1.14.so.0+0xa5eb9)
> #11 CppUnit::PlugInManager::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, CppUnit::PlugInParameters const&) workdir/UnpackedTarball/cppunit/src/cppunit/PlugInManager.cpp:34 (libcppunit-1.14.so.0+0xba57c)
> #12 (anonymous namespace)::ProtectedFixtureFunctor::run() const sal/cppunittester/cppunittester.cxx:259 (cppunittester+0x4bc55b)
> #13 sal_main() sal/cppunittester/cppunittester.cxx:466 (cppunittester+0x4bbe1e)
> #14 main sal/cppunittester/cppunittester.cxx:373 (cppunittester+0x4bb695)
Change-Id: I80f83d2e54f3bae61c1a896a5f9be9f0b5bce582
2017-08-29 18:22:15 +02:00
|
|
|
static WatchDog * aWatchDog = new WatchDog( 120 ); // random high number in secs
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
class TimerTest : public test::BootstrapFixture
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TimerTest() : BootstrapFixture(true, false) {}
|
|
|
|
|
2014-11-05 17:57:15 +01:00
|
|
|
void testIdle();
|
2017-07-20 12:56:24 +02:00
|
|
|
void testIdleMainloop();
|
2014-09-25 23:00:59 +02:00
|
|
|
#ifdef TEST_WATCHDOG
|
2014-09-25 11:22:39 +01:00
|
|
|
void testWatchdog();
|
2014-09-25 23:00:59 +02:00
|
|
|
#endif
|
2014-09-25 11:22:39 +01:00
|
|
|
void testDurations();
|
2015-08-28 08:00:20 +01:00
|
|
|
#ifdef TEST_TIMERPRECISION
|
2014-09-25 11:22:39 +01:00
|
|
|
void testAutoTimer();
|
2015-08-20 21:06:06 -04:00
|
|
|
void testMultiAutoTimers();
|
2015-08-28 08:00:20 +01:00
|
|
|
#endif
|
2017-01-23 11:56:41 +01:00
|
|
|
void testAutoTimerStop();
|
|
|
|
void testNestedTimer();
|
2014-09-25 11:22:39 +01:00
|
|
|
void testSlowTimerCallback();
|
2016-12-09 12:12:29 +02:00
|
|
|
void testTriggerIdleFromIdle();
|
2017-01-23 11:56:41 +01:00
|
|
|
void testInvokedReStart();
|
|
|
|
void testPriority();
|
2017-01-25 15:53:15 +01:00
|
|
|
void testRoundRobin();
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
CPPUNIT_TEST_SUITE(TimerTest);
|
2014-11-05 17:57:15 +01:00
|
|
|
CPPUNIT_TEST(testIdle);
|
2015-06-10 12:08:00 +01:00
|
|
|
CPPUNIT_TEST(testIdleMainloop);
|
2014-09-25 23:00:59 +02:00
|
|
|
#ifdef TEST_WATCHDOG
|
|
|
|
CPPUNIT_TEST(testWatchdog);
|
|
|
|
#endif
|
2014-09-25 11:22:39 +01:00
|
|
|
CPPUNIT_TEST(testDurations);
|
2015-08-28 08:00:20 +01:00
|
|
|
#ifdef TEST_TIMERPRECISION
|
2014-09-25 11:22:39 +01:00
|
|
|
CPPUNIT_TEST(testAutoTimer);
|
2015-08-20 21:06:06 -04:00
|
|
|
CPPUNIT_TEST(testMultiAutoTimers);
|
2015-08-28 08:00:20 +01:00
|
|
|
#endif
|
2017-01-23 11:56:41 +01:00
|
|
|
CPPUNIT_TEST(testAutoTimerStop);
|
|
|
|
CPPUNIT_TEST(testNestedTimer);
|
2014-09-25 11:22:39 +01:00
|
|
|
CPPUNIT_TEST(testSlowTimerCallback);
|
2016-12-09 12:12:29 +02:00
|
|
|
CPPUNIT_TEST(testTriggerIdleFromIdle);
|
2017-01-23 11:56:41 +01:00
|
|
|
CPPUNIT_TEST(testInvokedReStart);
|
|
|
|
CPPUNIT_TEST(testPriority);
|
2017-01-25 15:53:15 +01:00
|
|
|
CPPUNIT_TEST(testRoundRobin);
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
};
|
|
|
|
|
2014-09-25 23:00:59 +02:00
|
|
|
#ifdef TEST_WATCHDOG
|
2014-09-25 11:22:39 +01:00
|
|
|
void TimerTest::testWatchdog()
|
|
|
|
{
|
|
|
|
// out-wait the watchdog.
|
2016-03-22 03:25:02 +05:30
|
|
|
osl::Thread::wait( std::chrono::seconds(12) );
|
2014-09-25 11:22:39 +01:00
|
|
|
}
|
2014-09-25 23:00:59 +02:00
|
|
|
#endif
|
2014-09-25 11:22:39 +01:00
|
|
|
|
2014-11-05 17:57:15 +01:00
|
|
|
|
2014-11-05 20:51:21 +00:00
|
|
|
class IdleBool : public Idle
|
2014-11-05 17:57:15 +01:00
|
|
|
{
|
2014-11-05 20:51:21 +00:00
|
|
|
bool &mrBool;
|
|
|
|
public:
|
2015-05-25 09:35:57 +01:00
|
|
|
explicit IdleBool( bool &rBool ) :
|
2017-01-23 11:56:41 +01:00
|
|
|
Idle( "IdleBool" ), mrBool( rBool )
|
2014-11-05 20:51:21 +00:00
|
|
|
{
|
2017-01-04 12:06:42 +01:00
|
|
|
SetPriority( TaskPriority::LOWEST );
|
2014-11-05 20:51:21 +00:00
|
|
|
Start();
|
|
|
|
mrBool = false;
|
|
|
|
}
|
2015-10-12 16:04:04 +02:00
|
|
|
virtual void Invoke() override
|
2014-11-05 20:51:21 +00:00
|
|
|
{
|
|
|
|
mrBool = true;
|
|
|
|
Application::EndYield();
|
|
|
|
}
|
|
|
|
};
|
2014-11-05 17:57:15 +01:00
|
|
|
|
2014-11-05 20:51:21 +00:00
|
|
|
void TimerTest::testIdle()
|
|
|
|
{
|
|
|
|
bool bTriggered = false;
|
|
|
|
IdleBool aTest( bTriggered );
|
2016-09-14 15:33:54 +02:00
|
|
|
Scheduler::ProcessEventsToIdle();
|
2015-06-10 12:08:00 +01:00
|
|
|
CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimerTest::testIdleMainloop()
|
|
|
|
{
|
|
|
|
bool bTriggered = false;
|
|
|
|
IdleBool aTest( bTriggered );
|
2015-06-12 13:08:44 +01:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and toggle bDone
|
2015-06-10 12:08:00 +01:00
|
|
|
while (!bTriggered)
|
|
|
|
{
|
|
|
|
ImplSVData* pSVData = ImplGetSVData();
|
|
|
|
|
|
|
|
// can't test this via Application::Yield since this
|
|
|
|
// also processes all tasks directly via the scheduler.
|
|
|
|
pSVData->maAppData.mnDispatchLevel++;
|
2017-08-28 19:58:32 +02:00
|
|
|
pSVData->mpDefInst->DoYield(true, false);
|
2015-06-10 12:08:00 +01:00
|
|
|
pSVData->maAppData.mnDispatchLevel--;
|
|
|
|
}
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered);
|
2014-11-05 17:57:15 +01:00
|
|
|
}
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
class TimerBool : public Timer
|
|
|
|
{
|
|
|
|
bool &mrBool;
|
|
|
|
public:
|
|
|
|
TimerBool( sal_uLong nMS, bool &rBool ) :
|
2017-01-23 11:56:41 +01:00
|
|
|
Timer( "TimerBool" ), mrBool( rBool )
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
SetTimeout( nMS );
|
|
|
|
Start();
|
|
|
|
mrBool = false;
|
|
|
|
}
|
2015-10-12 16:04:04 +02:00
|
|
|
virtual void Invoke() override
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
mrBool = true;
|
|
|
|
Application::EndYield();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void TimerTest::testDurations()
|
|
|
|
{
|
|
|
|
static const sal_uLong aDurations[] = { 0, 1, 500, 1000 };
|
|
|
|
for (size_t i = 0; i < SAL_N_ELEMENTS( aDurations ); i++)
|
|
|
|
{
|
|
|
|
bool bDone = false;
|
|
|
|
TimerBool aTimer( aDurations[i], bDone );
|
2014-11-05 10:15:38 +00:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and toggle bDone
|
2014-09-25 11:22:39 +01:00
|
|
|
while( !bDone )
|
|
|
|
{
|
|
|
|
Application::Yield();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class AutoTimerCount : public AutoTimer
|
|
|
|
{
|
|
|
|
sal_Int32 &mrCount;
|
2017-01-23 11:56:41 +01:00
|
|
|
const sal_Int32 mnMaxCount;
|
|
|
|
|
2014-09-25 11:22:39 +01:00
|
|
|
public:
|
2017-01-23 11:56:41 +01:00
|
|
|
AutoTimerCount( sal_uLong nMS, sal_Int32 &rCount,
|
|
|
|
const sal_Int32 nMaxCount = -1 )
|
|
|
|
: AutoTimer( "AutoTimerCount" )
|
|
|
|
, mrCount( rCount )
|
|
|
|
, mnMaxCount( nMaxCount )
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
SetTimeout( nMS );
|
|
|
|
Start();
|
|
|
|
mrCount = 0;
|
|
|
|
}
|
2017-01-23 11:56:41 +01:00
|
|
|
|
2015-10-12 16:04:04 +02:00
|
|
|
virtual void Invoke() override
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
2017-01-23 11:56:41 +01:00
|
|
|
++mrCount;
|
|
|
|
CPPUNIT_ASSERT( mnMaxCount < 0 || mrCount <= mnMaxCount );
|
|
|
|
if ( mrCount == mnMaxCount )
|
|
|
|
Stop();
|
2014-09-25 11:22:39 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-28 08:00:20 +01:00
|
|
|
#ifdef TEST_TIMERPRECISION
|
|
|
|
|
2014-09-25 11:22:39 +01:00
|
|
|
void TimerTest::testAutoTimer()
|
|
|
|
{
|
2015-08-20 21:06:06 -04:00
|
|
|
const sal_Int32 nDurationMs = 30;
|
|
|
|
const sal_Int32 nEventsCount = 5;
|
|
|
|
const double exp = (nDurationMs * nEventsCount);
|
|
|
|
|
2014-09-25 11:22:39 +01:00
|
|
|
sal_Int32 nCount = 0;
|
2015-08-20 21:06:06 -04:00
|
|
|
std::ostringstream msg;
|
|
|
|
|
|
|
|
// Repeat when we have random latencies.
|
|
|
|
// This is expected on non-realtime OSes.
|
|
|
|
for (int i = 0; i < 10; ++i)
|
|
|
|
{
|
|
|
|
const auto start = std::chrono::high_resolution_clock::now();
|
|
|
|
nCount = 0;
|
|
|
|
AutoTimerCount aCount(nDurationMs, nCount);
|
|
|
|
while (nCount < nEventsCount) {
|
|
|
|
Application::Yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto end = std::chrono::high_resolution_clock::now();
|
2015-10-14 02:51:05 +02:00
|
|
|
double dur = std::chrono::duration<double, std::milli>(end - start).count();
|
2015-08-20 21:06:06 -04:00
|
|
|
|
|
|
|
msg << std::setprecision(2) << std::fixed
|
|
|
|
<< "periodic multi-timer - dur: "
|
|
|
|
<< dur << " (" << exp << ") ms." << std::endl;
|
|
|
|
|
|
|
|
// +/- 20% should be reasonable enough a margin.
|
|
|
|
if (dur >= (exp * 0.8) && dur <= (exp * 1.2))
|
|
|
|
{
|
|
|
|
// Success.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_FAIL(msg.str().c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimerTest::testMultiAutoTimers()
|
|
|
|
{
|
|
|
|
// The behavior of the timers change drastically
|
|
|
|
// when multiple timers are present.
|
|
|
|
// The worst, in my tests, is when two
|
|
|
|
// timers with 1ms period exist with a
|
|
|
|
// third of much longer period.
|
|
|
|
|
|
|
|
const sal_Int32 nDurationMsX = 5;
|
|
|
|
const sal_Int32 nDurationMsY = 10;
|
|
|
|
const sal_Int32 nDurationMs = 40;
|
|
|
|
const sal_Int32 nEventsCount = 5;
|
|
|
|
const double exp = (nDurationMs * nEventsCount);
|
|
|
|
const double expX = (exp / nDurationMsX);
|
|
|
|
const double expY = (exp / nDurationMsY);
|
|
|
|
|
|
|
|
sal_Int32 nCountX = 0;
|
|
|
|
sal_Int32 nCountY = 0;
|
|
|
|
sal_Int32 nCount = 0;
|
|
|
|
std::ostringstream msg;
|
|
|
|
|
|
|
|
// Repeat when we have random latencies.
|
|
|
|
// This is expected on non-realtime OSes.
|
|
|
|
for (int i = 0; i < 10; ++i)
|
|
|
|
{
|
|
|
|
nCountX = 0;
|
|
|
|
nCountY = 0;
|
|
|
|
nCount = 0;
|
|
|
|
|
|
|
|
const auto start = std::chrono::high_resolution_clock::now();
|
|
|
|
AutoTimerCount aCountX(nDurationMsX, nCountX);
|
|
|
|
AutoTimerCount aCountY(nDurationMsY, nCountY);
|
|
|
|
|
|
|
|
AutoTimerCount aCount(nDurationMs, nCount);
|
2015-08-27 08:09:18 +01:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and toggle nCount
|
2015-08-20 21:06:06 -04:00
|
|
|
while (nCount < nEventsCount) {
|
|
|
|
Application::Yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto end = std::chrono::high_resolution_clock::now();
|
2015-10-14 02:51:05 +02:00
|
|
|
double dur = std::chrono::duration<double, std::milli>(end - start).count();
|
2015-08-20 21:06:06 -04:00
|
|
|
|
|
|
|
msg << std::setprecision(2) << std::fixed << "periodic multi-timer - dur: "
|
|
|
|
<< dur << " (" << exp << ") ms, nCount: " << nCount
|
|
|
|
<< " (" << nEventsCount << "), nCountX: " << nCountX
|
|
|
|
<< " (" << expX << "), nCountY: " << nCountY
|
|
|
|
<< " (" << expY << ")." << std::endl;
|
|
|
|
|
|
|
|
// +/- 20% should be reasonable enough a margin.
|
|
|
|
if (dur >= (exp * 0.8) && dur <= (exp * 1.2) &&
|
|
|
|
nCountX >= (expX * 0.8) && nCountX <= (expX * 1.2) &&
|
|
|
|
nCountY >= (expY * 0.8) && nCountY <= (expY * 1.2))
|
|
|
|
{
|
|
|
|
// Success.
|
|
|
|
return;
|
|
|
|
}
|
2014-09-25 11:22:39 +01:00
|
|
|
}
|
2015-08-20 21:06:06 -04:00
|
|
|
|
|
|
|
CPPUNIT_FAIL(msg.str().c_str());
|
2014-09-25 11:22:39 +01:00
|
|
|
}
|
2015-08-28 08:00:20 +01:00
|
|
|
#endif // TEST_TIMERPRECISION
|
2014-09-25 11:22:39 +01:00
|
|
|
|
2017-01-23 11:56:41 +01:00
|
|
|
void TimerTest::testAutoTimerStop()
|
|
|
|
{
|
|
|
|
sal_Int32 nTimerCount = 0;
|
|
|
|
const sal_Int32 nMaxCount = 5;
|
|
|
|
AutoTimerCount aAutoTimer( 0, nTimerCount, nMaxCount );
|
2017-07-15 15:39:10 +01:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and increment TimerCount
|
|
|
|
while (nMaxCount != nTimerCount)
|
2017-01-23 11:56:41 +01:00
|
|
|
Application::Yield();
|
|
|
|
CPPUNIT_ASSERT( !aAutoTimer.IsActive() );
|
|
|
|
CPPUNIT_ASSERT( !Application::Reschedule() );
|
|
|
|
}
|
|
|
|
|
2014-09-25 11:22:39 +01:00
|
|
|
|
|
|
|
class YieldTimer : public Timer
|
|
|
|
{
|
|
|
|
public:
|
2017-01-23 11:56:41 +01:00
|
|
|
explicit YieldTimer( sal_uLong nMS ) : Timer( "YieldTimer" )
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
SetTimeout( nMS );
|
|
|
|
Start();
|
|
|
|
}
|
2015-10-12 16:04:04 +02:00
|
|
|
virtual void Invoke() override
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
|
|
Application::Yield();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-23 11:56:41 +01:00
|
|
|
void TimerTest::testNestedTimer()
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
sal_Int32 nCount = 0;
|
|
|
|
YieldTimer aCount(5);
|
|
|
|
AutoTimerCount aCountUp( 3, nCount );
|
2014-11-05 10:15:38 +00:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and increment nCount
|
2014-09-25 11:22:39 +01:00
|
|
|
while (nCount < 20)
|
|
|
|
Application::Yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class SlowCallbackTimer : public Timer
|
|
|
|
{
|
|
|
|
bool &mbSlow;
|
|
|
|
public:
|
|
|
|
SlowCallbackTimer( sal_uLong nMS, bool &bBeenSlow ) :
|
2017-01-23 11:56:41 +01:00
|
|
|
Timer( "SlowCallbackTimer" ), mbSlow( bBeenSlow )
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
|
|
|
SetTimeout( nMS );
|
|
|
|
Start();
|
|
|
|
mbSlow = false;
|
|
|
|
}
|
2015-10-12 16:04:04 +02:00
|
|
|
virtual void Invoke() override
|
2014-09-25 11:22:39 +01:00
|
|
|
{
|
2016-03-22 03:25:02 +05:30
|
|
|
osl::Thread::wait( std::chrono::seconds(1) );
|
2014-09-25 11:22:39 +01:00
|
|
|
mbSlow = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void TimerTest::testSlowTimerCallback()
|
|
|
|
{
|
|
|
|
bool bBeenSlow = false;
|
|
|
|
sal_Int32 nCount = 0;
|
|
|
|
AutoTimerCount aHighFreq(1, nCount);
|
|
|
|
SlowCallbackTimer aSlow(250, bBeenSlow);
|
2014-11-05 10:15:38 +00:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and toggle bBeenSlow
|
2014-09-25 11:22:39 +01:00
|
|
|
while (!bBeenSlow)
|
|
|
|
Application::Yield();
|
2014-11-05 10:15:38 +00:00
|
|
|
// coverity[loop_top] - Application::Yield allows the timer to fire and increment nCount
|
2014-09-25 11:22:39 +01:00
|
|
|
while (nCount < 200)
|
|
|
|
Application::Yield();
|
|
|
|
}
|
|
|
|
|
2016-12-09 12:12:29 +02:00
|
|
|
|
|
|
|
class TriggerIdleFromIdle : public Idle
|
|
|
|
{
|
|
|
|
bool* mpTriggered;
|
|
|
|
TriggerIdleFromIdle* mpOther;
|
|
|
|
public:
|
|
|
|
explicit TriggerIdleFromIdle( bool* pTriggered, TriggerIdleFromIdle* pOther ) :
|
2017-01-23 11:56:41 +01:00
|
|
|
Idle( "TriggerIdleFromIdle" ), mpTriggered(pTriggered), mpOther(pOther)
|
2016-12-09 12:12:29 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
virtual void Invoke() override
|
|
|
|
{
|
|
|
|
Start();
|
|
|
|
if (mpOther)
|
|
|
|
mpOther->Start();
|
|
|
|
Application::Yield();
|
|
|
|
if (mpTriggered)
|
|
|
|
*mpTriggered = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void TimerTest::testTriggerIdleFromIdle()
|
|
|
|
{
|
|
|
|
bool bTriggered1 = false;
|
|
|
|
bool bTriggered2 = false;
|
|
|
|
TriggerIdleFromIdle aTest2( &bTriggered2, nullptr );
|
|
|
|
TriggerIdleFromIdle aTest1( &bTriggered1, &aTest2 );
|
|
|
|
aTest1.Start();
|
|
|
|
Application::Yield();
|
2017-07-14 17:17:15 +02:00
|
|
|
CPPUNIT_ASSERT_MESSAGE("idle not triggered", bTriggered1);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("idle not triggered", bTriggered2);
|
2016-12-09 12:12:29 +02:00
|
|
|
}
|
|
|
|
|
2017-01-23 11:56:41 +01:00
|
|
|
|
|
|
|
class IdleInvokedReStart : public Idle
|
|
|
|
{
|
|
|
|
sal_Int32 &mrCount;
|
|
|
|
public:
|
|
|
|
IdleInvokedReStart( sal_Int32 &rCount )
|
|
|
|
: Idle( "IdleInvokedReStart" ), mrCount( rCount )
|
|
|
|
{
|
|
|
|
Start();
|
|
|
|
}
|
|
|
|
virtual void Invoke() override
|
|
|
|
{
|
|
|
|
mrCount++;
|
|
|
|
if ( mrCount < 2 )
|
|
|
|
Start();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void TimerTest::testInvokedReStart()
|
|
|
|
{
|
|
|
|
sal_Int32 nCount = 0;
|
|
|
|
IdleInvokedReStart aIdle( nCount );
|
2016-09-14 15:33:54 +02:00
|
|
|
Scheduler::ProcessEventsToIdle();
|
2018-05-31 13:20:41 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL( sal_Int32(2), nCount );
|
2017-01-23 11:56:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class IdleSerializer : public Idle
|
|
|
|
{
|
2018-09-13 13:08:33 +02:00
|
|
|
sal_uInt32 const mnPosition;
|
2017-01-23 11:56:41 +01:00
|
|
|
sal_uInt32 &mrProcesed;
|
|
|
|
public:
|
2018-09-16 19:17:31 +00:00
|
|
|
IdleSerializer(const sal_Char *pDebugName, TaskPriority ePrio,
|
|
|
|
sal_uInt32 nPosition, sal_uInt32 &rProcesed)
|
2017-01-23 11:56:41 +01:00
|
|
|
: Idle( pDebugName )
|
|
|
|
, mnPosition( nPosition )
|
|
|
|
, mrProcesed( rProcesed )
|
|
|
|
{
|
2018-09-16 19:17:31 +00:00
|
|
|
SetPriority(ePrio);
|
2017-01-23 11:56:41 +01:00
|
|
|
Start();
|
|
|
|
}
|
|
|
|
virtual void Invoke() override
|
|
|
|
{
|
|
|
|
++mrProcesed;
|
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Ignored prio", mnPosition, mrProcesed );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void TimerTest::testPriority()
|
|
|
|
{
|
|
|
|
// scope, so tasks are deleted
|
|
|
|
{
|
|
|
|
// Start: 1st Idle low, 2nd high
|
|
|
|
sal_uInt32 nProcessed = 0;
|
2018-09-16 19:17:31 +00:00
|
|
|
IdleSerializer aLowPrioIdle("IdleSerializer LowPrio",
|
|
|
|
TaskPriority::LOWEST, 2, nProcessed);
|
|
|
|
IdleSerializer aHighPrioIdle("IdleSerializer HighPrio",
|
|
|
|
TaskPriority::HIGHEST, 1, nProcessed);
|
2016-09-14 15:33:54 +02:00
|
|
|
Scheduler::ProcessEventsToIdle();
|
2017-01-23 11:56:41 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed );
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Start: 1st Idle high, 2nd low
|
|
|
|
sal_uInt32 nProcessed = 0;
|
2018-09-16 19:17:31 +00:00
|
|
|
IdleSerializer aHighPrioIdle("IdleSerializer HighPrio",
|
|
|
|
TaskPriority::HIGHEST, 1, nProcessed);
|
|
|
|
IdleSerializer aLowPrioIdle("IdleSerializer LowPrio",
|
|
|
|
TaskPriority::LOWEST, 2, nProcessed);
|
2016-09-14 15:33:54 +02:00
|
|
|
Scheduler::ProcessEventsToIdle();
|
2017-01-23 11:56:41 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-25 15:53:15 +01:00
|
|
|
|
|
|
|
class TestAutoIdleRR : public AutoIdle
|
|
|
|
{
|
|
|
|
sal_uInt32 &mrCount;
|
|
|
|
|
|
|
|
DECL_LINK( IdleRRHdl, Timer *, void );
|
|
|
|
|
|
|
|
public:
|
|
|
|
TestAutoIdleRR( sal_uInt32 &rCount,
|
|
|
|
const sal_Char *pDebugName )
|
|
|
|
: AutoIdle( pDebugName )
|
|
|
|
, mrCount( rCount )
|
|
|
|
{
|
2018-05-31 13:20:41 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL( sal_uInt32(0), mrCount );
|
2017-01-25 15:53:15 +01:00
|
|
|
SetInvokeHandler( LINK( this, TestAutoIdleRR, IdleRRHdl ) );
|
|
|
|
Start();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPL_LINK_NOARG(TestAutoIdleRR, IdleRRHdl, Timer *, void)
|
|
|
|
{
|
|
|
|
++mrCount;
|
|
|
|
if ( mrCount == 3 )
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimerTest::testRoundRobin()
|
|
|
|
{
|
|
|
|
sal_uInt32 nCount1 = 0, nCount2 = 0;
|
|
|
|
TestAutoIdleRR aIdle1( nCount1, "TestAutoIdleRR aIdle1" ),
|
|
|
|
aIdle2( nCount2, "TestAutoIdleRR aIdle2" );
|
|
|
|
while ( Application::Reschedule() )
|
|
|
|
{
|
|
|
|
CPPUNIT_ASSERT( nCount1 == nCount2 || nCount1 - 1 == nCount2 );
|
|
|
|
CPPUNIT_ASSERT( nCount1 <= 3 );
|
|
|
|
CPPUNIT_ASSERT( nCount2 <= 3 );
|
|
|
|
}
|
|
|
|
CPPUNIT_ASSERT( 3 == nCount1 && 3 == nCount2 );
|
|
|
|
}
|
|
|
|
|
2014-09-25 11:22:39 +01:00
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest);
|
|
|
|
|
|
|
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|