void run_timed_wait_regular_test() { Baton<Atom> b; auto thr = DSched::thread([&] { // To wait forever we'd like to use time_point<Clock>::max, but // std::condition_variable does math to convert the timeout to // system_clock without handling overflow. auto farFuture = Clock::now() + std::chrono::hours(1000); bool rv = b.timed_wait(farFuture); if (!std::is_same<Atom<int>, DeterministicAtomic<int>>::value) { // DeterministicAtomic ignores actual times, so doesn't guarantee // a lack of timeout EXPECT_TRUE(rv); } }); if (!std::is_same<Atom<int>, DeterministicAtomic<int>>::value) { // If we are using std::atomic (or EmulatedFutexAtomic) then // a sleep here guarantees to a large extent that 'thr' will // execute wait before we post it, thus testing late delivery. For // DeterministicAtomic, we just rely on DeterministicSchedule to do // the scheduling. The test won't fail if we lose the race, we just // don't get coverage. std::this_thread::sleep_for(std::chrono::milliseconds(2)); } b.post(); DSched::join(thr); }
TEST_F(EventBaseThreadTest, example) { EventBaseThread ebt; Baton<> done; ebt.getEventBase()->runInEventBaseThread([&] { done.post(); }); ASSERT_TRUE(done.timed_wait(seconds(1))); }
TEST(Interrupt, withinTimedOut) { Promise<int> p; Baton<> done; p.setInterruptHandler([&](const exception_wrapper& /* e */) { done.post(); }); p.getFuture().within(std::chrono::milliseconds(1)); // Give it 100ms to time out and call the interrupt handler auto t = std::chrono::steady_clock::now() + std::chrono::milliseconds(100); EXPECT_TRUE(done.timed_wait(t)); }
void after(uv_async_t *handle, int status) { pthread_mutex_lock(&queue_mutex); Baton *baton = queue_msg.front(); queue_msg.pop(); pthread_mutex_unlock(&queue_mutex); baton->afterCallBack(baton); }
TEST_F(EventBaseThreadTest, self_move) { EventBaseThread ebt0; auto ebt = std::move(ebt0); EXPECT_NE(nullptr, ebt.getEventBase()); Baton<> done; ebt.getEventBase()->runInEventBaseThread([&] { done.post(); }); ASSERT_TRUE(done.try_wait_for(seconds(1))); }
TEST_F(EventBaseThreadTest, example) { EventBaseThread ebt(true, nullptr, "monkey"); Baton<> done; ebt.getEventBase()->runInEventBaseThread([&] { EXPECT_EQ(getCurrentThreadName().value(), "monkey"); done.post(); }); ASSERT_TRUE(done.try_wait_for(seconds(1))); }
void run_timed_wait_tmo_tests() { Baton<Atom> b; auto thr = DSched::thread([&]{ bool rv = b.timed_wait(Clock::now() + std::chrono::milliseconds(1)); // main thread is guaranteed to not post until timeout occurs EXPECT_FALSE(rv); }); DSched::join(thr); }
TEST_F(FilePollerTest, TestDeleteFile) { Baton<> baton; bool updated = false; createFile(); FilePoller poller(tmpFile, std::chrono::milliseconds(1)); poller.addCallback([&]() { updated = true; baton.post(); }); remove(tmpFile.c_str()); ASSERT_TRUE(baton.timed_wait(std::chrono::seconds(5))); ASSERT_TRUE(updated); }
TEST_F(FilePollerTest, TestUpdateFileBackwards) { createFile(); Baton<> baton; bool updated = false; FilePoller poller(tmpFile, std::chrono::milliseconds(1)); poller.addCallback([&]() { updated = true; baton.post(); }); updateModifiedTime(tmpFile, false); ASSERT_TRUE(baton.timed_wait(std::chrono::seconds(5))); ASSERT_TRUE(updated); }
TEST_F(FilePollerTest, TestDeleteFile) { Baton<> baton; bool updated = false; createFile(); FilePoller poller(milliseconds(1)); poller.addFileToTrack(tmpFile, [&]() { updated = true; baton.post(); }); PCHECK(remove(tmpFile.c_str()) == 0); ASSERT_FALSE(baton.try_wait_for(seconds(1))); ASSERT_FALSE(updated); }
TEST_F(EventBaseThreadTest, move) { auto ebt0 = EventBaseThread(); auto ebt1 = std::move(ebt0); auto ebt2 = std::move(ebt1); EXPECT_EQ(nullptr, ebt0.getEventBase()); EXPECT_EQ(nullptr, ebt1.getEventBase()); EXPECT_NE(nullptr, ebt2.getEventBase()); Baton<> done; ebt2.getEventBase()->runInEventBaseThread([&] { done.post(); }); ASSERT_TRUE(done.try_wait_for(seconds(1))); }
TEST_F(FilePollerTest, TestUpdateFile) { createFile(); Baton<> baton; bool updated = false; FilePoller poller(milliseconds(1)); poller.addFileToTrack(tmpFile, [&]() { updated = true; baton.post(); }); updateModifiedTime(tmpFile); ASSERT_TRUE(baton.try_wait_for(seconds(5))); ASSERT_TRUE(updated); }
TEST_F(ProcessTicketTest, TestUpdateTicketFile) { Baton<> baton; TLSTicketProcessor processor(ticketFile); bool updated = false; processor.addCallback([&](TLSTicketKeySeeds) { updated = true; baton.post(); }); CHECK(writeFile(validTicketData, ticketFile.c_str())); updateModifiedTime(ticketFile); baton.timed_wait(std::chrono::seconds(30)); ASSERT_TRUE(updated); }
TEST(ThreadPoolExecutorTest, DynamicThreadAddRemoveRace) { CPUThreadPoolExecutor e(1); e.setThreadDeathTimeout(std::chrono::milliseconds(0)); std::atomic<uint64_t> count{0}; for (int i = 0; i < 10000; i++) { Baton<> b; e.add([&]() { count.fetch_add(1, std::memory_order_relaxed); b.post(); }); b.wait(); } e.join(); EXPECT_EQ(count, 10000); }
bool EventBase::runInEventBaseThreadAndWait(Func fn) { if (inRunningEventBaseThread()) { LOG(ERROR) << "EventBase " << this << ": Waiting in the event loop is not " << "allowed"; return false; } Baton<> ready; runInEventBaseThread([&ready, fn = std::move(fn)]() mutable { SCOPE_EXIT { ready.post(); }; // A trick to force the stored functor to be executed and then destructed // before posting the baton and waking the waiting thread. copy(std::move(fn))(); });
TEST_F(EventBaseThreadTest, start_stop) { EventBaseThread ebt(false); for (size_t i = 0; i < 4; ++i) { EXPECT_EQ(nullptr, ebt.getEventBase()); ebt.start(); EXPECT_NE(nullptr, ebt.getEventBase()); Baton<> done; ebt.getEventBase()->runInEventBaseThread([&] { done.post(); }); ASSERT_TRUE(done.try_wait_for(seconds(1))); EXPECT_NE(nullptr, ebt.getEventBase()); ebt.stop(); EXPECT_EQ(nullptr, ebt.getEventBase()); } }
void run_timed_wait_regular_test() { Baton<Atom> b; auto thr = DSched::thread([&] { bool rv = b.timed_wait( std::chrono::time_point<std::chrono::system_clock>::max()); if (std::is_same<Atom<int>, std::atomic<int>>::value) { // We can only ensure this for std::atomic EXPECT_TRUE(rv); } }); if (std::is_same<Atom<int>, std::atomic<int>>::value) { // If we are using std::atomic, then a sleep here guarantees to a large // extent that 'thr' will execute wait before we post it, thus testing // late delivery. For DeterministicAtomic, we just rely on // DeterministicSchedule to do the scheduling std::this_thread::sleep_for(std::chrono::milliseconds(2)); } b.post(); DSched::join(thr); }
TEST(Baton, basic) { Baton<> b; b.post(); b.wait(); }
void run_try_wait_tests() { Baton<Atom> b; EXPECT_FALSE(b.try_wait()); b.post(); EXPECT_TRUE(b.try_wait()); }
void run_basic_timed_wait_tests() { Baton<Atom> b; b.post(); // tests if early delivery works fine EXPECT_TRUE(b.timed_wait(std::chrono::system_clock::now())); }