New Upstream Release - readerwriterqueue
Ready changes
Summary
Merged new upstream version: 1.0.6 (was: 1.0.5).
Resulting package
Built on 2022-05-16T13:27 (took 5m40s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases libreaderwriterqueue-dev
Lintian Result
Diff
diff --git a/README.md b/README.md
index ba87ecf..a241d00 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
# A single-producer, single-consumer lock-free queue for C++
This mini-repository has my very own implementation of a lock-free queue (that I designed from scratch) for C++.
@@ -115,7 +116,37 @@ q.wait_dequeue_timed(number, std::chrono::milliseconds(10));
```
-## CMake installation
+## CMake
+### Using targets in your project
+Using this project as a part of an existing CMake project is easy.
+
+In your CMakeLists.txt:
+```
+include(FetchContent)
+
+FetchContent_Declare(
+ readerwriterqueue
+ GIT_REPOSITORY https://github.com/cameron314/readerwriterqueue
+ GIT_TAG master
+)
+
+FetchContent_MakeAvailable(readerwriterqueue)
+
+add_library(my_target main.cpp)
+target_link_libraries(my_target PUBLIC readerwriterqueue)
+```
+
+In main.cpp:
+```cpp
+#include <readerwriterqueue.h>
+
+int main()
+{
+ moodycamel::ReaderWriterQueue<int> q(100);
+}
+```
+
+### Installing into system directories
As an alternative to including the source files in your project directly,
you can use CMake to install the library in your system's include directory:
diff --git a/atomicops.h b/atomicops.h
index c1b8ab6..b103bc6 100644
--- a/atomicops.h
+++ b/atomicops.h
@@ -43,16 +43,27 @@
// AE_UNUSED
#define AE_UNUSED(x) ((void)x)
-// AE_NO_TSAN
+// AE_NO_TSAN/AE_TSAN_ANNOTATE_*
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
+#if __cplusplus >= 201703L // inline variables require C++17
+namespace moodycamel { inline int ae_tsan_global; }
+#define AE_TSAN_ANNOTATE_RELEASE() AnnotateHappensBefore(__FILE__, __LINE__, (void *)(&::moodycamel::ae_tsan_global))
+#define AE_TSAN_ANNOTATE_ACQUIRE() AnnotateHappensAfter(__FILE__, __LINE__, (void *)(&::moodycamel::ae_tsan_global))
+extern "C" void AnnotateHappensBefore(const char*, int, void*);
+extern "C" void AnnotateHappensAfter(const char*, int, void*);
+#else // when we can't work with tsan, attempt to disable its warnings
#define AE_NO_TSAN __attribute__((no_sanitize("thread")))
-#else
-#define AE_NO_TSAN
#endif
-#else
+#endif
+#endif
+#ifndef AE_NO_TSAN
#define AE_NO_TSAN
#endif
+#ifndef AE_TSAN_ANNOTATE_RELEASE
+#define AE_TSAN_ANNOTATE_RELEASE()
+#define AE_TSAN_ANNOTATE_ACQUIRE()
+#endif
// AE_FORCEINLINE
@@ -208,10 +219,10 @@ AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
{
switch (order) {
case memory_order_relaxed: break;
- case memory_order_acquire: std::atomic_thread_fence(std::memory_order_acquire); break;
- case memory_order_release: std::atomic_thread_fence(std::memory_order_release); break;
- case memory_order_acq_rel: std::atomic_thread_fence(std::memory_order_acq_rel); break;
- case memory_order_seq_cst: std::atomic_thread_fence(std::memory_order_seq_cst); break;
+ case memory_order_acquire: AE_TSAN_ANNOTATE_ACQUIRE(); std::atomic_thread_fence(std::memory_order_acquire); break;
+ case memory_order_release: AE_TSAN_ANNOTATE_RELEASE(); std::atomic_thread_fence(std::memory_order_release); break;
+ case memory_order_acq_rel: AE_TSAN_ANNOTATE_ACQUIRE(); AE_TSAN_ANNOTATE_RELEASE(); std::atomic_thread_fence(std::memory_order_acq_rel); break;
+ case memory_order_seq_cst: AE_TSAN_ANNOTATE_ACQUIRE(); AE_TSAN_ANNOTATE_RELEASE(); std::atomic_thread_fence(std::memory_order_seq_cst); break;
default: assert(false);
}
}
@@ -352,6 +363,10 @@ extern "C" {
#include <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
+#elif defined(FREERTOS)
+#include <FreeRTOS.h>
+#include <semphr.h>
+#include <task.h>
#endif
namespace moodycamel
@@ -566,6 +581,73 @@ namespace moodycamel
}
}
};
+#elif defined(FREERTOS)
+ //---------------------------------------------------------
+ // Semaphore (FreeRTOS)
+ //---------------------------------------------------------
+ class Semaphore
+ {
+ private:
+ SemaphoreHandle_t m_sema;
+
+ Semaphore(const Semaphore& other);
+ Semaphore& operator=(const Semaphore& other);
+
+ public:
+ AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema()
+ {
+ assert(initialCount >= 0);
+ m_sema = xSemaphoreCreateCounting(static_cast<UBaseType_t>(~0ull), static_cast<UBaseType_t>(initialCount));
+ assert(m_sema);
+ }
+
+ AE_NO_TSAN ~Semaphore()
+ {
+ vSemaphoreDelete(m_sema);
+ }
+
+ bool wait() AE_NO_TSAN
+ {
+ return xSemaphoreTake(m_sema, portMAX_DELAY) == pdTRUE;
+ }
+
+ bool try_wait() AE_NO_TSAN
+ {
+ // Note: In an ISR context, if this causes a task to unblock,
+ // the caller won't know about it
+ if (xPortIsInsideInterrupt())
+ return xSemaphoreTakeFromISR(m_sema, NULL) == pdTRUE;
+ return xSemaphoreTake(m_sema, 0) == pdTRUE;
+ }
+
+ bool timed_wait(std::uint64_t usecs) AE_NO_TSAN
+ {
+ std::uint64_t msecs = usecs / 1000;
+ TickType_t ticks = static_cast<TickType_t>(msecs / portTICK_PERIOD_MS);
+ if (ticks == 0)
+ return try_wait();
+ return xSemaphoreTake(m_sema, ticks) == pdTRUE;
+ }
+
+ void signal() AE_NO_TSAN
+ {
+ // Note: In an ISR context, if this causes a task to unblock,
+ // the caller won't know about it
+ BaseType_t rc;
+ if (xPortIsInsideInterrupt())
+ rc = xSemaphoreGiveFromISR(m_sema, NULL);
+ else
+ rc = xSemaphoreGive(m_sema);
+ assert(rc == pdTRUE);
+ AE_UNUSED(rc);
+ }
+
+ void signal(int count) AE_NO_TSAN
+ {
+ while (count-- > 0)
+ signal();
+ }
+ };
#else
#error Unsupported platform! (No semaphore wrapper available)
#endif
diff --git a/debian/changelog b/debian/changelog
index 2cae7c1..0a3a0b8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+readerwriterqueue (1.0.6-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Mon, 16 May 2022 13:22:22 -0000
+
readerwriterqueue (1.0.5-1) unstable; urgency=medium
* Team Upload.
diff --git a/debian/patches/hardening.patch b/debian/patches/hardening.patch
index ce9356f..158394d 100644
--- a/debian/patches/hardening.patch
+++ b/debian/patches/hardening.patch
@@ -1,9 +1,11 @@
Description: Propagate hardening options to fix blhc
Author: Nilesh Patra <nilesh@debian.org>
Last-Update: 2021-04-21
---- a/benchmarks/makefile
-+++ b/benchmarks/makefile
-@@ -16,7 +16,7 @@
+Index: readerwriterqueue/benchmarks/makefile
+===================================================================
+--- readerwriterqueue.orig/benchmarks/makefile
++++ readerwriterqueue/benchmarks/makefile
+@@ -16,7 +16,7 @@ endif
default: benchmarks$(EXT)
benchmarks$(EXT): bench.cpp ../readerwriterqueue.h ../readerwritercircularbuffer.h ../atomicops.h ext/1024cores/spscqueue.h ext/folly/ProducerConsumerQueue.h ../tests/common/simplethread.h ../tests/common/simplethread.cpp systemtime.h systemtime.cpp makefile
@@ -12,9 +14,11 @@ Last-Update: 2021-04-21
run: benchmarks$(EXT)
./benchmarks$(EXT)
---- a/tests/stabtest/makefile
-+++ b/tests/stabtest/makefile
-@@ -18,7 +18,7 @@
+Index: readerwriterqueue/tests/stabtest/makefile
+===================================================================
+--- readerwriterqueue.orig/tests/stabtest/makefile
++++ readerwriterqueue/tests/stabtest/makefile
+@@ -18,7 +18,7 @@ endif
default: stabtest$(EXT)
stabtest$(EXT): stabtest.cpp ../../readerwriterqueue.h ../../atomicops.h ../common/simplethread.h ../common/simplethread.cpp makefile
@@ -23,9 +27,11 @@ Last-Update: 2021-04-21
run: stabtest$(EXT)
./stabtest$(EXT)
---- a/tests/unittests/makefile
-+++ b/tests/unittests/makefile
-@@ -21,7 +21,7 @@
+Index: readerwriterqueue/tests/unittests/makefile
+===================================================================
+--- readerwriterqueue.orig/tests/unittests/makefile
++++ readerwriterqueue/tests/unittests/makefile
+@@ -21,7 +21,7 @@ endif
default: unittests$(EXT)
unittests$(EXT): unittests.cpp ../../readerwriterqueue.h ../../readerwritercircularbuffer.h ../../atomicops.h ../common/simplethread.h ../common/simplethread.cpp minitest.h makefile
diff --git a/readerwritercircularbuffer.h b/readerwritercircularbuffer.h
index dbaabe8..ea25df5 100644
--- a/readerwritercircularbuffer.h
+++ b/readerwritercircularbuffer.h
@@ -33,7 +33,7 @@ public:
public:
explicit BlockingReaderWriterCircularBuffer(std::size_t capacity)
: maxcap(capacity), mask(), rawData(), data(),
- slots(new spsc_sema::LightweightSemaphore(static_cast<spsc_sema::LightweightSemaphore::ssize_t>(capacity))),
+ slots_(new spsc_sema::LightweightSemaphore(static_cast<spsc_sema::LightweightSemaphore::ssize_t>(capacity))),
items(new spsc_sema::LightweightSemaphore(0)),
nextSlot(0), nextItem(0)
{
@@ -52,7 +52,7 @@ public:
BlockingReaderWriterCircularBuffer(BlockingReaderWriterCircularBuffer&& other)
: maxcap(0), mask(0), rawData(nullptr), data(nullptr),
- slots(new spsc_sema::LightweightSemaphore(0)),
+ slots_(new spsc_sema::LightweightSemaphore(0)),
items(new spsc_sema::LightweightSemaphore(0)),
nextSlot(), nextItem()
{
@@ -86,7 +86,7 @@ public:
std::swap(mask, other.mask);
std::swap(rawData, other.rawData);
std::swap(data, other.data);
- std::swap(slots, other.slots);
+ std::swap(slots_, other.slots_);
std::swap(items, other.items);
std::swap(nextSlot, other.nextSlot);
std::swap(nextItem, other.nextItem);
@@ -98,7 +98,7 @@ public:
// No exception guarantee (state will be corrupted) if constructor of T throws.
bool try_enqueue(T const& item)
{
- if (!slots->tryWait())
+ if (!slots_->tryWait())
return false;
inner_enqueue(item);
return true;
@@ -110,7 +110,7 @@ public:
// No exception guarantee (state will be corrupted) if constructor of T throws.
bool try_enqueue(T&& item)
{
- if (!slots->tryWait())
+ if (!slots_->tryWait())
return false;
inner_enqueue(std::move(item));
return true;
@@ -122,7 +122,7 @@ public:
// No exception guarantee (state will be corrupted) if constructor of T throws.
void wait_enqueue(T const& item)
{
- while (!slots->wait());
+ while (!slots_->wait());
inner_enqueue(item);
}
@@ -132,7 +132,7 @@ public:
// No exception guarantee (state will be corrupted) if constructor of T throws.
void wait_enqueue(T&& item)
{
- while (!slots->wait());
+ while (!slots_->wait());
inner_enqueue(std::move(item));
}
@@ -143,7 +143,7 @@ public:
// No exception guarantee (state will be corrupted) if constructor of T throws.
bool wait_enqueue_timed(T const& item, std::int64_t timeout_usecs)
{
- if (!slots->wait(timeout_usecs))
+ if (!slots_->wait(timeout_usecs))
return false;
inner_enqueue(item);
return true;
@@ -156,7 +156,7 @@ public:
// No exception guarantee (state will be corrupted) if constructor of T throws.
bool wait_enqueue_timed(T&& item, std::int64_t timeout_usecs)
{
- if (!slots->wait(timeout_usecs))
+ if (!slots_->wait(timeout_usecs))
return false;
inner_enqueue(std::move(item));
return true;
@@ -262,7 +262,7 @@ private:
T& element = reinterpret_cast<T*>(data)[i & mask];
item = std::move(element);
element.~T();
- slots->signal();
+ slots_->signal();
}
template<typename U>
@@ -277,8 +277,8 @@ private:
std::size_t mask; // circular buffer capacity mask (for cheap modulo)
char* rawData; // raw circular buffer memory
char* data; // circular buffer memory aligned to element alignment
- std::unique_ptr<spsc_sema::LightweightSemaphore> slots; // number of slots currently free
- std::unique_ptr<spsc_sema::LightweightSemaphore> items; // number of elements currently enqueued
+ std::unique_ptr<spsc_sema::LightweightSemaphore> slots_; // number of slots currently free (named with underscore to accommodate Qt's 'slots' macro)
+ std::unique_ptr<spsc_sema::LightweightSemaphore> items; // number of elements currently enqueued
char cachelineFiller0[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(char*) * 2 - sizeof(std::size_t) * 2 - sizeof(std::unique_ptr<spsc_sema::LightweightSemaphore>) * 2];
std::size_t nextSlot; // index of next free slot to enqueue into
char cachelineFiller1[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(std::size_t)];