https://github.com/bringauto/async-function-execution
Asynchronous function execution by context isolation
https://github.com/bringauto/async-function-execution
Last synced: 4 months ago
JSON representation
Asynchronous function execution by context isolation
- Host: GitHub
- URL: https://github.com/bringauto/async-function-execution
- Owner: bringauto
- License: lgpl-3.0
- Created: 2025-08-27T09:21:41.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-10-30T13:10:58.000Z (8 months ago)
- Last Synced: 2025-10-30T15:08:58.999Z (8 months ago)
- Language: C++
- Size: 58.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Async Function Execution
A library providing the ability to call functions on a different binary over shared memory. The communication is divided to a producer and consumer.
### Implementation
Both sides need to have all functions defined the same way. Example implementation:
```cpp
#include
using namespace bringauto::async_function_execution;
FunctionDefinition FunctionAdd {
FunctionId { 1 }, // id can be 0-255 and has to be unique
Return { int {} }, // return type of the function
Arguments { int {}, int {}, int {} } // individual function argument types
};
AsyncFunctionExecutor executorProducer {
Config {
.isProducer = true, // decides the mode of the executor
.defaultTimeout = std::chrono::seconds(1) // polling timeout (should only be used when producer)
.functionConfigurations = structures::FunctionConfigs { {
{ 1, { std::chrono::seconds(2) }}
} }
},
FunctionList { // list of all functions
FunctionAdd
}
};
```
#### Post initialization
Before using any functions, connection needs to be established using the connect function:
```cpp
// Returns -1 on a failed connection
int rc = executorProducer.connect();
```
#### functionConfigurations
The functionConfigurations parameter accepts an unordered map representing per function configurations. Syntax:
```cpp
{
{ , { } }
}
```
Supported parameters:
- timeout: replaces the default timeout value for that function (in nanoseconds)
### Producer
Producer is the side calling functions and waiting for a response from the consumer. If timeout is provided in config, the function will throw if it doesn't execute in time. Example of function calling:
```cpp
// the function definition and same number of expected arguments need to be provided
int ret = executorProducer.callFunc(FunctionAdd, 1, 2, 3);
```
### Consumer
Consumer is consistently polling function requests, executing the requested functions and sending the required return value back to the producer. Example function calling:
```cpp
while (true) {
// poll for function requests and receive a function id and bytes holding the argument data
auto [funcId, argBytes] = executorConsumer.pollFunction();
// argument data then needs to be deserialized by providing the corresponding function definition
auto [arg1, arg2, arg3] = executorConsumer.getFunctionArgs(FunctionAdd, argBytes);
// do some work with the arguments and send a return value back to the producer
int ret = arg1 + arg2 + arg3;
executorConsumer.sendReturnMessage(FunctionAdd.id, ret);
}
```
### Non trivially copiable data types
If an argument or return type is not trivially copiable, a way of data serialization needs to be provided. This can be done simply by wraping the data type in a struct and implementing both serialize() and deserialize() functions. Example for std::string:
```cpp
struct SerializableString final {
std::string value {};
SerializableString() = default;
SerializableString(std::string str) : value(std::move(str)) {}
std::span serialize() const {
return std::span {reinterpret_cast(value.data()), value.size()};
}
void deserialize(std::span bytes) {
value = std::string {reinterpret_cast(bytes.data()), bytes.size()};
}
};
```
### Data lifetime
If a producer expects a return value where returned bytes are used directly, these bytes are valid untill the next call of the same function. If a longer lifespan is required, these bytes need to be copied, otherwise double free() errors might occur during runtime.
## Requirements
- [aeron](https://github.com/aeron-io/aeron)
- [cmlib](https://github.com/cmakelib/cmakelib)
- the CMLIB_DIR env value has to be set
## Build
```bash
mkdir -p _build && cd _build
cmake ../
make
```
## Tests
[Tests Readme](./test/README.md)