/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/io/async/ScopedEventBaseThread.h>
#include <chrono>
#include <string>
#include <folly/Optional.h>
#include <folly/futures/Promise.h>
#include <folly/io/async/EventBaseManager.h>
#include <folly/portability/GTest.h>
#include <folly/synchronization/Baton.h>
#include <folly/system/ThreadName.h>
using namespace std;
using namespace std::chrono;
using namespace folly;
class ScopedEventBaseThreadTest : public testing::Test {};
TEST_F(ScopedEventBaseThreadTest, example) {
ScopedEventBaseThread sebt;
Baton<> done;
sebt.getEventBase()->runInEventBaseThread([&] { done.post(); });
ASSERT_TRUE(done.try_wait_for(seconds(1)));
}
TEST_F(ScopedEventBaseThreadTest, named_example) {
static constexpr StringPiece kThreadName{"named_example"};
Optional<std::string> createdThreadName;
Baton<> done;
ScopedEventBaseThread sebt{kThreadName};
sebt.getEventBase()->runInEventBaseThread([&] {
createdThreadName = folly::getCurrentThreadName();
done.post();
});
ASSERT_TRUE(done.try_wait_for(seconds(1)));
if (createdThreadName) {
ASSERT_EQ(kThreadName.toString(), createdThreadName.value());
}
}
TEST_F(ScopedEventBaseThreadTest, default_manager) {
auto ebm = EventBaseManager::get();
ScopedEventBaseThread sebt;
auto sebt_eb = sebt.getEventBase();
auto ebm_eb = static_cast<EventBase*>(nullptr);
sebt_eb->runInEventBaseThreadAndWait([&] { ebm_eb = ebm->getEventBase(); });
EXPECT_EQ(uintptr_t(sebt_eb), uintptr_t(ebm_eb));
}
TEST_F(ScopedEventBaseThreadTest, custom_manager) {
EventBaseManager ebm;
ScopedEventBaseThread sebt(&ebm);
auto sebt_eb = sebt.getEventBase();
auto ebm_eb = static_cast<EventBase*>(nullptr);
sebt_eb->runInEventBaseThreadAndWait([&] { ebm_eb = ebm.getEventBase(); });
EXPECT_EQ(uintptr_t(sebt_eb), uintptr_t(ebm_eb));
}
TEST_F(ScopedEventBaseThreadTest, eb_dtor_in_io_thread) {
Optional<ScopedEventBaseThread> sebt;
sebt.emplace();
auto const io_thread_id = sebt->getThreadId();
EXPECT_NE(this_thread::get_id(), io_thread_id) << "sanity";
auto const eb = sebt->getEventBase();
thread::id eb_dtor_thread_id;
eb->runOnDestruction([&] { eb_dtor_thread_id = std::this_thread::get_id(); });
sebt.reset();
EXPECT_EQ(io_thread_id, eb_dtor_thread_id);
}
TEST_F(ScopedEventBaseThreadTest, keepalive) {
Baton<> started, done, reset;
folly::Executor::KeepAlive<> ex;
Promise<Unit> p;
std::thread t1([&] {
ScopedEventBaseThread sebt;
ex = &sebt;
started.post();
});
std::thread t2([&] {
started.wait();
p.getSemiFuture().via(ex).thenValue([&, ex](auto&&) { done.post(); });
ex.reset();
reset.post();
});
reset.wait();
p.setValue();
ASSERT_TRUE(done.try_wait_for(seconds(1)));
t1.join();
t2.join();
}