9#include <botan/filters.h>
11#if defined(BOTAN_HAS_THREAD_UTILS)
13 #include <botan/internal/barrier.h>
14 #include <botan/internal/semaphore.h>
21struct Threaded_Fork_Data {
27 Semaphore m_input_ready_semaphore;
32 Barrier m_input_complete_barrier;
39 const uint8_t* m_input =
nullptr;
44 size_t m_input_length = 0;
48 void clear_exception() {
49 const std::lock_guard
lock(m_exception_mutex);
50 m_exception =
nullptr;
53 void capture_exception() {
54 const std::lock_guard
lock(m_exception_mutex);
56 m_exception = std::current_exception();
60 std::exception_ptr exception() {
61 const std::lock_guard
lock(m_exception_mutex);
66 std::mutex m_exception_mutex;
67 std::exception_ptr m_exception;
74 Fork(nullptr, static_cast<size_t>(0)), m_thread_data(new Threaded_Fork_Data) {
75 Filter* filters[4] = {f1, f2, f3, f4};
82Threaded_Fork::Threaded_Fork(Filter* filters[],
size_t count) :
83 Fork(nullptr, static_cast<size_t>(0)), m_thread_data(new Threaded_Fork_Data) {
84 set_next(filters, count);
87Threaded_Fork::~Threaded_Fork() {
88 m_thread_data->m_input =
nullptr;
89 m_thread_data->m_input_length = 0;
91 m_thread_data->m_input_ready_semaphore.release(m_threads.size());
93 for(
auto& thread : m_threads) {
98std::string Threaded_Fork::name()
const {
99 return "Threaded Fork";
102void Threaded_Fork::set_next(Filter* f[],
size_t n) {
103 Fork::set_next(f, n);
106 if(n < m_threads.size()) {
109 m_threads.reserve(n);
110 for(
size_t i = m_threads.size(); i != n; ++i) {
111 m_threads.push_back(std::make_shared<std::thread>([
this, next = m_next[i]] { thread_entry(next); }));
116void Threaded_Fork::send(
const uint8_t input[],
size_t length) {
125 if(!m_write_queue.empty()) {
126 thread_delegate_work(m_write_queue.data(), m_write_queue.size());
128 thread_delegate_work(input, length);
130 bool nothing_attached =
true;
131 for(
size_t j = 0; j != total_ports(); ++j) {
132 if(m_next[j] !=
nullptr) {
133 nothing_attached =
false;
137 if(nothing_attached) {
138 m_write_queue += std::make_pair(input, length);
140 m_write_queue.clear();
144void Threaded_Fork::thread_delegate_work(
const uint8_t input[],
size_t length) {
146 m_thread_data->clear_exception();
147 m_thread_data->m_input = input;
148 m_thread_data->m_input_length = length;
151 m_thread_data->m_input_complete_barrier.wait(total_ports() + 1);
152 m_thread_data->m_input_ready_semaphore.release(total_ports());
155 m_thread_data->m_input_complete_barrier.sync();
157 const auto exception = m_thread_data->exception();
160 m_thread_data->m_input =
nullptr;
161 m_thread_data->m_input_length = 0;
164 std::rethrow_exception(exception);
168void Threaded_Fork::thread_entry(Filter* filter) {
170 m_thread_data->m_input_ready_semaphore.acquire();
172 if(m_thread_data->m_input ==
nullptr) {
177 if(filter !=
nullptr) {
179 filter->write(m_thread_data->m_input, m_thread_data->m_input_length);
181 m_thread_data->capture_exception();
184 m_thread_data->m_input_complete_barrier.sync();
secure_vector< T > lock(const std::vector< T > &in)