예제 #1
0
TEST(AsyncTask, RequestCoalescingMultithreaded) {
    RunLoop loop;

    unsigned count = 0;
    AsyncTask async([&count] { ++count; });

    std::vector<std::unique_ptr<Thread<TestWorker>>> threads;
    ThreadContext context = {"Test"};

    unsigned numThreads = 25;
    for (unsigned i = 0; i < numThreads; ++i) {
        std::unique_ptr<Thread<TestWorker>> thread =
            std::make_unique<Thread<TestWorker>>(context, &async);

        thread->invoke(&TestWorker::run);
        threads.push_back(std::move(thread));
    }

    // Join all the threads
    threads.clear();

    loop.runOnce();

    EXPECT_EQ(count, 1u);
}
예제 #2
0
TEST(AsyncTask, ThreadSafety) {
    RunLoop loop;

    unsigned count = 0, numThreads = 25;
    std::atomic_uint completed(numThreads);

    AsyncTask async([&count] { ++count; });

    auto retainer = Scheduler::GetBackground();
    auto mailbox = std::make_shared<Mailbox>(*retainer);

    TestWorker worker(&async);
    ActorRef<TestWorker> workerRef(worker, mailbox);

    for (unsigned i = 0; i < numThreads; ++i) {
        // The callback runs on the worker, thus the atomic type.
        workerRef.invoke(&TestWorker::runWithCallback, [&] { if (!--completed) loop.stop(); });
    }

    loop.run();

    // We expect here more than 1 but 1 would also be
    // a valid result, although very unlikely (I hope).
    EXPECT_GT(count, 0u);
}
예제 #3
0
TEST(AsyncTask, DestroyAfterSignaling) {
    RunLoop loop;

    // We're creating two tasks and signal both of them; the one that gets fired first destroys
    // the other one. Make sure that the second one we destroyed doesn't fire.

    std::unique_ptr<AsyncTask> task1, task2;

    task1 = std::make_unique<AsyncTask>([&] {
        task2.reset();
        if (!task1) {
            FAIL() << "Task was destroyed but invoked anyway";
        }
    });
    task2 = std::make_unique<AsyncTask>([&] {
        task1.reset();
        if (!task2) {
            FAIL() << "Task was destroyed but invoked anyway";
        }
    });

    task1->send();
    task2->send();

    loop.runOnce();
}
예제 #4
0
TEST(AsyncTask, ThreadSafety) {
    RunLoop loop;

    unsigned count = 0;
    AsyncTask async([&count] { ++count; });

    unsigned numThreads = 25;

    auto callback = [&] {
        if (!--numThreads) {
            loop.stop();
        }
    };

    std::vector<std::unique_ptr<Thread<TestWorker>>> threads;
    std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
    ThreadContext context = {"Test"};

    for (unsigned i = 0; i < numThreads; ++i) {
        std::unique_ptr<Thread<TestWorker>> thread =
            std::make_unique<Thread<TestWorker>>(context, &async);

        requests.push_back(
            thread->invokeWithCallback(&TestWorker::runWithCallback, callback));

        threads.push_back(std::move(thread));
    }

    loop.run();

    // We expect here more than 1 but 1 would also be
    // a valid result, although very unlikely (I hope).
    EXPECT_GT(count, 0u);
}
예제 #5
0
TEST(AsyncTask, RequestCoalescingMultithreaded) {
    RunLoop loop;

    unsigned count = 0, numThreads = 25;
    AsyncTask async([&count] { ++count; });

    auto retainer = Scheduler::GetBackground();
    auto mailbox = std::make_shared<Mailbox>(*retainer);

    TestWorker worker(&async);
    ActorRef<TestWorker> workerRef(worker, mailbox);

    for (unsigned i = 0; i < numThreads; ++i) {
        workerRef.invoke(&TestWorker::run);
    }

    std::promise<void> barrier;
    std::future<void> barrierFuture = barrier.get_future();

    workerRef.invoke(&TestWorker::sync, std::move(barrier));
    barrierFuture.wait();

    loop.runOnce();

    EXPECT_EQ(count, 1u);
}
예제 #6
0
TEST(Timer, Repeat) {
    RunLoop loop;

    Timer timer;

    unsigned count = 10;
    auto callback = [&] {
        if (!--count) {
            loop.stop();
        }
    };

    auto interval = std::chrono::milliseconds(50);
    auto expectedTotalTime = interval * count;

    auto first = mbgl::Clock::now();
    timer.start(interval, interval, callback);

    loop.run();

    using namespace std::chrono;
    auto totalTime = duration_cast<milliseconds>(mbgl::Clock::now() - first);

    EXPECT_GE(totalTime, expectedTotalTime * 0.8);
    EXPECT_LE(totalTime, expectedTotalTime * 1.2);
}
예제 #7
0
TEST(Timer, StartOverrides) {
    RunLoop loop;

    Timer timer;

    auto interval1 = std::chrono::milliseconds(50);
    auto interval2 = std::chrono::milliseconds(250);
    auto expectedTotalTime = interval1  + interval2;

    int count = 0;

    auto callback2 = [&] {
        ++count;
        loop.stop();
    };

    auto callback1 = [&] {
        ++count;
        timer.start(interval2, mbgl::Duration::zero(), callback2);
    };

    auto first = mbgl::Clock::now();
    timer.start(interval1, mbgl::Duration::zero(), callback1);

    loop.run();

    using namespace std::chrono;
    auto totalTime = duration_cast<milliseconds>(mbgl::Clock::now() - first);

    EXPECT_EQ(count, 2);

    EXPECT_GE(totalTime, expectedTotalTime * 0.8);
    EXPECT_LE(totalTime, expectedTotalTime * 1.2);
}
예제 #8
0
파일: RunLoopEfl.cpp 프로젝트: jiezh/h5vcc
void RunLoop::wakeUpEvent(void* data, void*, unsigned int)
{
    RunLoop* loop = static_cast<RunLoop*>(data);

    {
        MutexLocker locker(loop->m_wakeUpEventRequestedLock);
        loop->m_wakeUpEventRequested = false;
    }

    loop->performWork();
}
예제 #9
0
void RunLoop::run()
{
    RunLoop* mainRunLoop = RunLoop::current();
    GMainLoop* innermostLoop = mainRunLoop->innermostLoop();
    if (!g_main_loop_is_running(innermostLoop)) {
        g_main_loop_run(innermostLoop);
        return;
    }

    // Create and run a nested loop if the innermost one was already running.
    GMainLoop* nestedMainLoop = g_main_loop_new(0, FALSE);
    mainRunLoop->pushNestedMainLoop(nestedMainLoop);
    g_main_loop_run(nestedMainLoop);
    mainRunLoop->popNestedMainLoop();
}
예제 #10
0
TEST(AsyncTask, RequestCoalescing) {
    RunLoop loop;

    unsigned count = 0;
    AsyncTask async([&count] { ++count; });

    async.send();
    async.send();
    async.send();
    async.send();
    async.send();

    loop.runOnce();

    EXPECT_EQ(count, 1u);
}
예제 #11
0
TEST(Timer, DestroyShouldStop) {
    RunLoop loop;

    auto timer1 = std::make_unique<Timer>();
    Timer timer2;

    auto interval1 = std::chrono::milliseconds(50);
    auto interval2 = std::chrono::milliseconds(250);
    auto expectedTotalTime = interval2;

    int count = 0;

    auto callback1 = [&] {
        ++count;
        timer1.reset();
    };

    auto callback2 = [&] {
        ++count;
        loop.stop();
    };

    auto first = mbgl::Clock::now();
    timer1->start(interval1, interval1, callback1);
    timer2.start(interval2, mbgl::Duration::zero(), callback2);

    loop.run();

    using namespace std::chrono;
    auto totalTime = duration_cast<milliseconds>(mbgl::Clock::now() - first);

    EXPECT_EQ(count, 2);

    EXPECT_GE(totalTime, expectedTotalTime * 0.8);
    EXPECT_LE(totalTime, expectedTotalTime * 1.2);
}
예제 #12
0
TEST(Timer, Basic) {
    RunLoop loop;

    Timer timer;

    auto callback = [&loop] { loop.stop(); };

    auto interval = std::chrono::milliseconds(300);
    auto expectedTotalTime = interval;

    auto first = mbgl::Clock::now();
    timer.start(interval, mbgl::Duration::zero(), callback);

    loop.run();

    using namespace std::chrono;
    auto totalTime = duration_cast<milliseconds>(mbgl::Clock::now() - first);

    // These are not high precision timers. Especially libuv uses
    // cached time from the beginning of of the main loop iteration
    // and it is very prone to fire earlier, which is, odd.
    EXPECT_GE(totalTime, expectedTotalTime * 0.8);
    EXPECT_LE(totalTime, expectedTotalTime * 1.2);
}
예제 #13
0
int RunLoop::_ReceiveLoopEvent(int fd, int events, void* data)
{
    RunLoop* p = reinterpret_cast<RunLoop*>(data);
    auto iter = p->_handlers.find(fd);
    if ( iter == p->_handlers.end() )
        return 0;   // unregister fd from the looper
    
    if ( !iter->second )
        return 0;
    
    // consume something
    char buf[12];
    ::read(fd, buf, 12);
    
    // what type is it?
    Timer* pTimer = (Timer*)(iter->second);
    if (pTimer != nullptr)
    {
        // it's a Timer!
        // keep the timer around past any Cancel() or Remove() calls made by the callout
        RefCounted<Timer> timer(pTimer);
        if ( (events & ALOOPER_EVENT_HANGUP) == ALOOPER_EVENT_HANGUP )
        {
            // remove it from the runloop
            p->RemoveTimer(timer);
            return 0;
        }
        
        timer->_fn(*timer);                 ///////// DO CALLOUT
        
        if ( !timer->Repeats() || timer->IsCancelled() )
        {
            // the underlying Linux timer_t is already disarmed
            p->RemoveTimer(timer);
            return 0;
        }
        
        // it'll repeat, so keep processing please
        return 1;
    }
    
    // not a Timer? Must be an EventSource then
    EventSource *pSource = (EventSource*)(iter->second);
    if ( pSource != nullptr )
    {
        // it *is* an EventSource!
        // keep it around so we can check even if the callout removes it from the runloop
        RefCounted<EventSource> source(pSource);
        if ( (events & ALOOPER_EVENT_HANGUP) == ALOOPER_EVENT_HANGUP )
        {
            // calcelled, so remove it from the runloop
            p->RemoveEventSource(source);
            return 0;
        }
        
        source->_fn(*source);               /////////// DO CALLOUT
        
        if ( source->IsCancelled() )
        {
            // now we want to remove it
            p->RemoveEventSource(source);
            return 0;
        }
        
        return 1;
    }
    
    // errrrr... who to the what, now?
    return 0;
}
예제 #14
0
void Invocation1::invokeInRunLoop(RunLoop& rl, float delay)
{
	rl.addTask(etCreateObject<InvocationTask>(_target->copy()), delay);
}