26 #include <linux/limits.h>
44 std::unique_ptr<Service> &cacheEntry =
serviceCache[make_tuple(&svcType,
id)];
45 if (cacheEntry ==
nullptr) {
48 svc = ServiceRegistry::createService(
this, svcType,
id, implName, details,
52 cacheEntry = std::unique_ptr<Service>(svc);
54 return cacheEntry.get();
60 char result[PATH_MAX];
61 ssize_t count = readlink(
"/proc/self/exe", result, PATH_MAX);
63 throw std::runtime_error(
"Could not get executable path");
64 return std::filesystem::path(std::string(result, count));
66 char buffer[MAX_PATH];
67 DWORD length = GetModuleFileNameA(NULL, buffer, MAX_PATH);
69 throw std::runtime_error(
"Could not get executable path");
70 return std::filesystem::path(std::string(buffer, length));
72 #eror "Unsupported platform"
81 return std::filesystem::path(std::string(dl_info.dli_fname));
83 HMODULE hModule = NULL;
84 if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
85 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
86 reinterpret_cast<LPCSTR
>(&
getLibPath), &hModule)) {
88 return std::filesystem::path();
91 char buffer[MAX_PATH];
92 DWORD length = GetModuleFileNameA(hModule, buffer, MAX_PATH);
94 throw std::runtime_error(
"Could not get library path");
96 return std::filesystem::path(std::string(buffer, length));
98 #eror "Unsupported platform"
106 backend[0] = toupper(backend[0]);
110 std::string backendFileName =
"lib" + backend +
"Backend.so";
112 std::string backendFileName = backend +
"Backend.dll";
114 #eror "Unsupported platform"
122 std::filesystem::path backendPath = backendFileName;
123 std::string backendPathStr;
124 if (!std::filesystem::exists(backendPath)) {
126 backendPath =
getExePath().parent_path().append(backendFileName);
127 if (!std::filesystem::exists(backendPath)) {
129 backendPath =
getLibPath().parent_path().append(backendFileName);
130 if (!std::filesystem::exists(backendPath))
132 backendPathStr = backendFileName;
136 if (backendPathStr.empty())
137 backendPathStr = backendPath.string();
146 void *handle = dlopen(backendPathStr.c_str(), RTLD_NOW | RTLD_GLOBAL);
148 throw std::runtime_error(
"While attempting to load backend plugin: " +
149 std::string(dlerror()));
153 if (backendPath != std::filesystem::path()) {
154 std::filesystem::path backendPathParent = backendPath.parent_path();
155 if (SetDllDirectoryA(backendPathParent.string().c_str()) == 0)
156 throw std::runtime_error(
"While setting DLL directory: " +
157 std::to_string(GetLastError()));
161 HMODULE handle = LoadLibraryA(backendPathStr.c_str());
163 DWORD error = GetLastError();
164 if (error == ERROR_MOD_NOT_FOUND)
165 throw std::runtime_error(
"While attempting to load backend plugin: " +
166 backendPathStr +
" not found");
167 throw std::runtime_error(
"While attempting to load backend plugin: " +
168 std::to_string(error));
171 #eror "Unsupported platform"
181 throw std::runtime_error(
"Backend already exists in registry");
186 std::unique_ptr<AcceleratorConnection>
194 throw std::runtime_error(
"Backend '" + backend +
"' not found");
196 return f->second(
ctxt, connection);
211 addListener(std::initializer_list<ReadChannelPort *> listenPorts,
224 std::future<MessageData>>>
241 std::this_thread::sleep_for(std::chrono::microseconds(100));
247 for (
auto &[channel, cbfPair] :
listeners) {
248 assert(channel &&
"Null channel in listener list");
249 std::future<MessageData> &f = cbfPair.second;
250 if (f.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
251 portUnlockWorkList.emplace_back(channel, cbfPair.first, f.get());
252 f = channel->readAsync();
258 for (
auto [channel, cb, data] : portUnlockWorkList)
259 cb(channel, std::move(data));
262 portUnlockWorkList.clear();
267 std::initializer_list<ReadChannelPort *> listenPorts,
269 std::lock_guard<std::mutex> g(listenerMutex);
270 for (
auto port : listenPorts) {
271 if (listeners.count(port))
272 throw std::runtime_error(
"Port already has a listener");
273 listeners[port] = std::make_pair(callback, port->readAsync());
280 : impl(std::make_unique<
Impl>()) {
296 std::initializer_list<ReadChannelPort *> listenPorts,
299 impl->addListener(listenPorts, callback);
assert(baseType &&"element must be base type")
void disconnect()
Disconnect from the accelerator cleanly.
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
std::map< ServiceCacheKey, std::unique_ptr< Service > > serviceCache
std::unique_ptr< AcceleratorServiceThread > serviceThread
virtual Service * createService(Service::Type service, AppIDPath idPath, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients)=0
Called by getServiceImpl exclusively.
AcceleratorConnection(Context &ctxt)
Background thread which services various requests.
void stop()
Instruct the service thread to stop running.
void addListener(std::initializer_list< ReadChannelPort * > listenPorts, std::function< void(ReadChannelPort *, MessageData)> callback)
When there's data on any of the listenPorts, call the callback.
AcceleratorServiceThread()
std::unique_ptr< Impl > impl
~AcceleratorServiceThread()
AcceleratorConnections, Accelerators, and Manifests must all share a context.
A logical chunk of data representing serialized data.
A ChannelPort which reads data from the accelerator.
Parent class of all APIs modeled as 'services'.
const std::type_info & Type
void registerBackend(std::string name, BackendCreate create)
std::function< std::unique_ptr< AcceleratorConnection >(Context &, std::string)> BackendCreate
Backends can register themselves to be connected via a connection string.
static std::map< std::string, BackendCreate > backendRegistry
std::unique_ptr< AcceleratorConnection > connect(Context &ctxt, std::string backend, std::string connection)
static std::filesystem::path getExePath()
Get the path to the currently running executable.
std::map< std::string, std::any > ServiceImplDetails
static std::filesystem::path getLibPath()
Get the path to the currently running shared library.
std::vector< HWClientDetail > HWClientDetails
static void loadBackend(std::string backend)
Load a backend plugin dynamically.
std::map< ReadChannelPort *, std::pair< std::function< void(ReadChannelPort *, MessageData)>, std::future< MessageData > > > listeners
void addListener(std::initializer_list< ReadChannelPort * > listenPorts, std::function< void(ReadChannelPort *, MessageData)> callback)
When there's data on any of the listenPorts, call the callback.