networks-1.cpp/modules/asyncio/Include/LdH/asyncio.hpp

155 lines
4.0 KiB
C++

#pragma once
//#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <concepts>
#include <type_traits>
#include <LdH/exception.hpp>
namespace LdH::Asyncio {
#if 0
template<class ret_t, template<typename> class lambda_t>
concept OverlappedFunc = std::invocable<lambda_t<ret_t>, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>
&& std::same_as<std::invoke_result_t<lambda_t<ret_t>, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>, ret_t>;
#endif
template<class lambda_t>
concept OverlappedFunc = std::invocable<lambda_t, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>
&& std::same_as<std::invoke_result_t<lambda_t, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE>, DWORD>;
class WindowsOverlappedEventloop {
private:
static thread_local struct _running_loop_variable_t {
private:
WindowsOverlappedEventloop *_value;
public:
[[nodiscard]]
WindowsOverlappedEventloop *get() {
auto cached = this->_value;
if (cached == nullptr) throw LdH::Exception{"No running loop"};
return cached;
}
[[nodiscard]]
WindowsOverlappedEventloop *getOrNull() {
return this->_value;
}
void set(WindowsOverlappedEventloop *v) {
if (this->_value != nullptr && v != nullptr) throw LdH::Exception{"Recursive loops not allowed"};
this->_value = v;
}
} _running_loop;
struct FiberMetadata {
public:
OVERLAPPED overlapped;
void *fiber_id;
FiberMetadata *next_existing;
FiberMetadata *prev_existing;
FiberMetadata *next_active;
FiberMetadata *prev_active;
DWORD err_code;
DWORD read_count;
};
HANDLE const notifier;
bool const need_rollback_to_thread;
void *const master_fiber;
bool interrupted;
FiberMetadata *next_existing;
FiberMetadata *next_active;
DWORD const fls_fiber_metadata;
void *fiber_to_destroy;
public:
WindowsOverlappedEventloop();
~WindowsOverlappedEventloop();
private:
[[nodiscard]]
HANDLE createEvent() const;
[[nodiscard]]
HANDLE prepareFibers() const;
[[nodiscard]]
DWORD allocFls() const;
public:
void runUntilHasTasksAndNotInterrupted();
private:
void _addTask(void (*routine)(void *), void *arg);
static void _overlapped_completion_routine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, FiberMetadata *lpOverlapped);
public:
template<class T>
static void addTaskToRuningLoop(void (*routine)(T *), T *arg) {
WindowsOverlappedEventloop::_running_loop.get()->_addTask(
reinterpret_cast<void (*)(void *)>(routine),
reinterpret_cast<void *>(arg)
);
}
template<class T>
void addTask(void (*routine)(T *), T *arg) {
this->_addTask(
reinterpret_cast<void (*)(void *)>(routine),
reinterpret_cast<void *>(arg)
);
}
static DWORD overlappedCall(OverlappedFunc auto func) {
auto loop = WindowsOverlappedEventloop::_running_loop.get();
auto metadata = reinterpret_cast<FiberMetadata *>(FlsGetValue(loop->fls_fiber_metadata));
if (metadata == nullptr) LdH::Exception::throwFromLastWindowsErr();
DWORD read_count = func(reinterpret_cast<LPOVERLAPPED>(metadata), reinterpret_cast<LPOVERLAPPED_COMPLETION_ROUTINE>(&WindowsOverlappedEventloop::_overlapped_completion_routine));
if (read_count != 0) return read_count;
if (loop->next_active == metadata)
loop->next_active = metadata->next_active;
if (metadata->next_active != nullptr)
metadata->next_active->prev_active = metadata->prev_active;
if (metadata->prev_active != nullptr)
metadata->prev_active->next_active = metadata->next_active;
metadata->next_active = nullptr;
metadata->prev_active = nullptr;
SwitchToFiber(loop->master_fiber);
if (metadata->err_code != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(metadata->err_code);
return metadata->read_count;
}
static void interruptEventLoop() {
WindowsOverlappedEventloop::_running_loop.get()->interrupted = true;
}
private:
struct FiberInitializer {
WindowsOverlappedEventloop *loop;
void (*routine)(void *);
void *routine_arg;
void *caller_fiber;
};
static void fiber_kernel(FiberInitializer *init);
};
}