mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-28 10:51:24 +00:00
128 lines
3.6 KiB
C++
128 lines
3.6 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
/*
|
|
Copyright (C) 2023 The Falco Authors.
|
|
|
|
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 <falco/atomic_signal_handler.h>
|
|
#include <engine/logger.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <chrono>
|
|
#include <future>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
TEST(AtomicSignalHandler, lock_free_implementation)
|
|
{
|
|
ASSERT_TRUE(falco::atomic_signal_handler().is_lock_free());
|
|
}
|
|
|
|
TEST(AtomicSignalHandler, handle_once_wait_consistency)
|
|
{
|
|
constexpr const auto thread_num = 10;
|
|
constexpr const std::chrono::seconds thread_wait_sec{2};
|
|
constexpr const std::chrono::seconds handler_wait_sec{1};
|
|
|
|
// have a shared signal handler
|
|
falco::atomic_signal_handler handler;
|
|
|
|
// launch a bunch of threads all syncing on the same handler
|
|
struct task_result_t
|
|
{
|
|
bool handled;
|
|
std::chrono::seconds duration_secs;
|
|
};
|
|
|
|
std::vector<std::future<task_result_t>> futures;
|
|
for (int i = 0; i < thread_num; i++)
|
|
{
|
|
futures.emplace_back(std::async(std::launch::async,
|
|
[&handler, thread_wait_sec]() {
|
|
auto start = std::chrono::high_resolution_clock::now();
|
|
task_result_t res;
|
|
res.handled = false;
|
|
while (!handler.handled())
|
|
{
|
|
if (handler.triggered())
|
|
{
|
|
res.handled = handler.handle([thread_wait_sec]() {
|
|
std::this_thread::sleep_for(thread_wait_sec);
|
|
});
|
|
}
|
|
}
|
|
auto diff = std::chrono::high_resolution_clock::now() - start;
|
|
res.duration_secs = std::chrono::duration_cast<std::chrono::seconds>(diff);
|
|
return res;
|
|
}));
|
|
}
|
|
|
|
// wait a bit, then trigger the signal handler from the main thread
|
|
auto total_handled = 0;
|
|
auto start = std::chrono::high_resolution_clock::now();
|
|
std::this_thread::sleep_for(handler_wait_sec);
|
|
handler.trigger();
|
|
for (int i = 0; i < thread_num; i++)
|
|
{
|
|
// wait for all threads to finish and get the results from the futures
|
|
auto res = futures[i].get();
|
|
if (res.handled)
|
|
{
|
|
total_handled++;
|
|
}
|
|
ASSERT_GE(res.duration_secs, thread_wait_sec);
|
|
}
|
|
|
|
// check that the total time is consistent with the expectations
|
|
auto diff = std::chrono::high_resolution_clock::now() - start;
|
|
auto secs = std::chrono::duration_cast<std::chrono::seconds>(diff);
|
|
ASSERT_GE(secs, thread_wait_sec + handler_wait_sec);
|
|
|
|
// check that only one thread handled the signal
|
|
ASSERT_EQ(total_handled, 1);
|
|
}
|
|
|
|
TEST(AtomicSignalHandler, handle_and_reset)
|
|
{
|
|
auto do_nothing = []{};
|
|
falco::atomic_signal_handler handler;
|
|
|
|
ASSERT_FALSE(handler.triggered());
|
|
ASSERT_FALSE(handler.handled());
|
|
ASSERT_FALSE(handler.handle(do_nothing));
|
|
|
|
handler.trigger();
|
|
ASSERT_TRUE(handler.triggered());
|
|
ASSERT_FALSE(handler.handled());
|
|
|
|
ASSERT_TRUE(handler.handle(do_nothing));
|
|
ASSERT_TRUE(handler.triggered());
|
|
ASSERT_TRUE(handler.handled());
|
|
ASSERT_FALSE(handler.handle(do_nothing));
|
|
|
|
handler.trigger();
|
|
ASSERT_TRUE(handler.triggered());
|
|
ASSERT_FALSE(handler.handled());
|
|
ASSERT_TRUE(handler.handle(do_nothing));
|
|
ASSERT_TRUE(handler.triggered());
|
|
ASSERT_TRUE(handler.handled());
|
|
ASSERT_FALSE(handler.handle(do_nothing));
|
|
|
|
handler.reset();
|
|
ASSERT_FALSE(handler.triggered());
|
|
ASSERT_FALSE(handler.handled());
|
|
ASSERT_FALSE(handler.handle(do_nothing));
|
|
}
|