Skip to content

Commit

Permalink
Add custom queue example, more readme
Browse files Browse the repository at this point in the history
  • Loading branch information
cjappl committed Dec 23, 2024
1 parent f5cac8d commit bcc1c3e
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 2 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,34 @@ Or alternatively spin up a `rtlog::LogProcessingThread`
```c++
rtlog::LogProcessingThread thread(logger, PrintMessage, std::chrono::milliseconds(10));
```
## Customizing the queue type
If you don't want to use the SPSC moodycamel queue, you can provide your own queue type.
** IT IS UP TO YOU TO ENSURE THE QUEUE YOU PROVIDE IS LOCK-FREE AND REAL-TIME SAFE **
The queue must have the following:
```c++
template <typename T>
class MyQueue
{
public:
using value_type = T;
MyQueue(int capacity);
bool try_dequeue(T& item); // MUST return false if the queue is empty
bool try_enqueue(T&& item);
// OR
bool try_enqueue(const T& item);
};
```

Then, when creating the logger, provide the queue type as a template parameter:

```c++
using RealtimeLogger = rtlog::Logger<ExampleLogData, MAX_NUM_LOG_MESSAGES, MAX_LOG_MESSAGE_LENGTH, gSequenceNumber, MyQueue>;
```

You can see an example of wrapping a known rt-safe queue in `examples/custom_queue_example`.
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
add_subdirectory(everlog)
add_subdirectory(custom_queue_example)
29 changes: 29 additions & 0 deletions examples/custom_queue_example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
if (NOT TARGET farbot)
include(FetchContent)

FetchContent_Declare(farbot
GIT_REPOSITORY https://github.com/hogliux/farbot
GIT_TAG 0416705394720c12f0d02e55c144e4f69bb06912
)
# Note we do not "MakeAvailable" here, because farbot does not fully work via FetchContent
if(NOT farbot_POPULATED)
FetchContent_Populate(farbot)
endif()
add_library(farbot INTERFACE)
add_library(farbot::farbot ALIAS farbot)

target_include_directories(farbot INTERFACE
$<BUILD_INTERFACE:${farbot_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
endif()

add_executable(custom_queue_example
customqueuemain.cpp
)

target_link_libraries(custom_queue_example
PRIVATE
rtlog::rtlog
farbot::farbot
)
47 changes: 47 additions & 0 deletions examples/custom_queue_example/customqueuemain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <farbot/fifo.hpp>
#include <rtlog/rtlog.h>

template <typename T> class FarbotMPSCQueueWrapper {
farbot::fifo<T,
farbot::fifo_options::concurrency::single, // Consumer
farbot::fifo_options::concurrency::multiple, // Producer
farbot::fifo_options::full_empty_failure_mode::
return_false_on_full_or_empty, // consumer_failure_mode
farbot::fifo_options::full_empty_failure_mode::
overwrite_or_return_default> // producer_failure_mode

mQueue;

public:
using value_type = T;

FarbotMPSCQueueWrapper(int capacity) : mQueue(capacity) {}

bool try_enqueue(T &&item) { return mQueue.push(std::move(item)); }
bool try_dequeue(T &item) { return mQueue.pop(item); }
};

struct LogData {};

std::atomic<size_t> gSequenceNumber{0};

int main() {
rtlog::Logger<LogData, 128, 128, gSequenceNumber, FarbotMPSCQueueWrapper>
logger;
logger.Log({}, "Hello, World!");

logger.PrintAndClearLogQueue(
[](const LogData &data, size_t sequenceNumber, const char *fstring, ...) {
(void)data;
std::array<char, 128> buffer;

va_list args;
va_start(args, fstring);
vsnprintf(buffer.data(), buffer.size(), fstring, args);
va_end(args);

printf("{%zu} %s\n", sequenceNumber, buffer.data());
});

return 0;
}
6 changes: 4 additions & 2 deletions include/rtlog/rtlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ template <typename T> using rtlog_SPSC = moodycamel::ReaderWriterQueue<T, 512>;
* Requirements on QType:
* 1. Is real-time safe
* 2. Accepts one type template paramter for the type to be queued
* 3. Has a constructor that takes an integer which will be the queue's capacity
* 4. Has methods `bool try_enqueue(T &&item)` and/or `bool try_enqueue(const T &item)` and `bool try_dequeue(T &item)`
* 3. Has a constructor that takes an integer which will be the queue's
* capacity
* 4. Has methods `bool try_enqueue(T &&item)` and/or `bool
* try_enqueue(const T &item)` and `bool try_dequeue(T &item)`
*/
template <typename LogData, size_t MaxNumMessages, size_t MaxMessageLength,
std::atomic<std::size_t> &SequenceNumber,
Expand Down

0 comments on commit bcc1c3e

Please sign in to comment.