Repository: nasa/fprime (language: python)

Issue:
Refactor Os::Queue into CMake Selection
| | |
|:---|:---|
|**_F´ Version_**| |
|**_Affected Component_**|  |
---
## Feature Description

- [ ] Refactor Os::Queue into the Interface, Os::Queue, and Implementation classes (following pattern of Os::File)
- [ ] Implement Posix implementation
- [ ] Implement Stub implementation
- [ ] Clean up multiple queue implementations that already exist
- [ ] Implement Test stub implementation
- [ ] Build common rules-based tests
- [ ] Build specific posix tests
- [ ] Build stub interface tests
- [ ] Setup default posix implementation for Posix platforms
- [ ] Document



Discussion / hints:

Fix patch:
diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
index ccdb4d282e..bbfd7efaa7 100644
--- a/.github/actions/spelling/expect.txt
+++ b/.github/actions/spelling/expect.txt
@@ -794,6 +794,7 @@ prepeneding
 pri
 printables
 prioritization
+PRIORITYQUEUE
 prm
 PRMDB
 PRMDBIMPL
@@ -997,6 +998,7 @@ STDC
 stddef
 stdint
 stest
+Stl
 STREQ
 STREQUAL
 strerror
@@ -1216,4 +1218,4 @@ xsltproc
 xxxx
 yacgen
 zimri
-zmq
\ No newline at end of file
+zmq
diff --git a/Fw/Comp/ActiveComponentBase.cpp b/Fw/Comp/ActiveComponentBase.cpp
index d33086b5c0..879cd75342 100644
--- a/Fw/Comp/ActiveComponentBase.cpp
+++ b/Fw/Comp/ActiveComponentBase.cpp
@@ -75,7 +75,7 @@ namespace Fw {
         ActiveComponentExitSerializableBuffer exitBuff;
         SerializeStatus stat = exitBuff.serialize(static_cast<I32>(ACTIVE_COMPONENT_EXIT));
         FW_ASSERT(FW_SERIALIZE_OK == stat,static_cast<NATIVE_INT_TYPE>(stat));
-        (void)this->m_queue.send(exitBuff,0,Os::Queue::QUEUE_NONBLOCKING);
+        (void)this->m_queue.send(exitBuff,0,Os::Queue::BlockingType::NONBLOCKING);
         DEBUG_PRINT("exit %s\n", this->getObjName());
     }
 
@@ -137,7 +137,7 @@ namespace Fw {
 
     ActiveComponentBase::MsgDispatchStatus ActiveComponentBase::dispatch() {
         // Cooperative tasks should return rather than block when no messages are available
-        if (this->m_task.isCooperative() and m_queue.getNumMsgs() == 0) {
+        if (this->m_task.isCooperative() and m_queue.getMessagesAvailable() == 0) {
             return MsgDispatchStatus::MSG_DISPATCH_EMPTY;
         }
        return this->doDispatch();
diff --git a/Fw/Comp/QueuedComponentBase.cpp b/Fw/Comp/QueuedComponentBase.cpp
index 06546f342e..0c91d9ae63 100644
--- a/Fw/Comp/QueuedComponentBase.cpp
+++ b/Fw/Comp/QueuedComponentBase.cpp
@@ -30,7 +30,7 @@ namespace Fw {
     }
 #endif
 
-    Os::Queue::QueueStatus QueuedComponentBase::createQueue(NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize) {
+    Os::Queue::Queue::Status QueuedComponentBase::createQueue(FwSizeType depth, FwSizeType msgSize) {
 
         Os::QueueString queueName;
 #if FW_OBJECT_NAMES == 1
diff --git a/Fw/Comp/QueuedComponentBase.hpp b/Fw/Comp/QueuedComponentBase.hpp
index cb1c773f19..79833e1284 100644
--- a/Fw/Comp/QueuedComponentBase.hpp
+++ b/Fw/Comp/QueuedComponentBase.hpp
@@ -34,7 +34,7 @@ namespace Fw {
             virtual ~QueuedComponentBase(); //!< Destructor
             void init(NATIVE_INT_TYPE instance); //!< initialization function
             Os::Queue m_queue; //!< queue object for active component
-            Os::Queue::QueueStatus createQueue(NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize);
+            Os::Queue::Status createQueue(FwSizeType depth, FwSizeType msgSize);
             virtual MsgDispatchStatus doDispatch()=0; //!< method to dispatch a single message in the queue.
 #if FW_OBJECT_TO_STRING == 1
             virtual void toString(char* str, NATIVE_INT_TYPE size); //!< dump string representation of component
diff --git a/Os/Baremetal/Queue.cpp b/Os/Baremetal/Queue.cpp
index bfec97ae1f..d65020b737 100644
--- a/Os/Baremetal/Queue.cpp
+++ b/Os/Baremetal/Queue.cpp
@@ -208,7 +208,7 @@ Queue::QueueStatus Queue::receive(U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_I
     return bareReceiveBlock(handle, buffer, capacity, actualSize, priority);
 }
 
-NATIVE_INT_TYPE Queue::getNumMsgs() const {
+NATIVE_INT_TYPE Queue::getMessagesAvailable() const {
     //Check if the handle is null or check the underlying queue is null
     if ((nullptr == reinterpret_cast<BareQueueHandle*>(this->m_handle)) ||
         (!reinterpret_cast<BareQueueHandle*>(this->m_handle)->m_init)) {
diff --git a/Os/CMakeLists.txt b/Os/CMakeLists.txt
index 66c2a01820..a095e66b82 100644
--- a/Os/CMakeLists.txt
+++ b/Os/CMakeLists.txt
@@ -8,6 +8,7 @@
 add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Models")
 add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Stub")
 add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Posix")
+add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Generic")
 
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/test/ut/file/SyntheticFileSystem.cpp"
@@ -26,10 +27,6 @@ set(MOD_DEPS
 # Basic source files used in every OSAL layer.  Contains common code and helpers.
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/IntervalTimerCommon.cpp"
-#    "${CMAKE_CURRENT_LIST_DIR}/TaskCommon.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/QueueCommon.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/IPCQueueCommon.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/SimpleQueueRegistry.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/MemCommon.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/ValidateFileCommon.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/ValidatedFile.cpp"
@@ -41,6 +38,8 @@ set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Mutex.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/FileSystem.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/Directory.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Condition.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/Queue.cpp"
 )
 # Check for default logger
 if (NOT FPRIME_DISABLE_DEFAULT_LOGGER)
@@ -52,10 +51,6 @@ endif()
 if (FPRIME_USE_POSIX)
     list(APPEND SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/Console.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Pthreads/Queue.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Pthreads/BufferQueueCommon.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Pthreads/PriorityBufferQueue.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/Pthreads/MaxHeap/MaxHeap.cpp"
         "${CMAKE_CURRENT_LIST_DIR}/Linux/InterruptLock.cpp"
         "${CMAKE_CURRENT_LIST_DIR}/Linux/WatchdogTimer.cpp"
         "${CMAKE_CURRENT_LIST_DIR}/Posix/IntervalTimer.cpp"
@@ -64,14 +59,12 @@ endif()
 # Darwin IPC queue implementation
 if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
   list(APPEND SOURCE_FILES
-    "${CMAKE_CURRENT_LIST_DIR}/MacOs/IPCQueueStub.cpp"
+#    "${CMAKE_CURRENT_LIST_DIR}/MacOs/IPCQueueStub.cpp"
     "${CMAKE_CURRENT_LIST_DIR}/MacOs/SystemResources.cpp"
   )
 # Linux IPC queues implementation
 elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
   list(APPEND SOURCE_FILES
-    "${CMAKE_CURRENT_LIST_DIR}/Posix/IPCQueue.cpp"
-    "${CMAKE_CURRENT_LIST_DIR}/Posix/LocklessQueue.cpp"
 	"${CMAKE_CURRENT_LIST_DIR}/Linux/SystemResources.cpp"
   )
   # Shared libraries need an -rt dependency for mq libs
@@ -103,11 +96,11 @@ require_fprime_implementation(Os/Directory)
 require_fprime_implementation(Os/Mutex)
 # require_fprime_implementation(Os/Task) # should be added in
 # require_fprime_implementation(Os/Console) # should be added in
+require_fprime_implementation(Os/Queue)
 
 
 ### UTS ### Note: 3 separate UTs registered here.
 set(UT_SOURCE_FILES
-  "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsQueueTest.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsTestMain.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/IntervalTimerTest.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/test/ut/OsValidateFileTest.cpp"
@@ -127,14 +120,3 @@ if (BUILD_TESTING)
         endif()
     endforeach()
 endif()
-# Second UT Pthreads
-set(UT_SOURCE_FILES
-  "${CMAKE_CURRENT_LIST_DIR}/Pthreads/test/ut/BufferQueueTest.cpp"
-)
-register_fprime_ut("Os_pthreads")
-
-# Third  UT Pthreads MAX Heap
-set(UT_SOURCE_FILES
-  "${CMAKE_CURRENT_LIST_DIR}/Pthreads/MaxHeap/test/ut/MaxHeapTest.cpp"
-)
-register_fprime_ut("Os_pthreads_max_heap")
diff --git a/Os/Condition.cpp b/Os/Condition.cpp
new file mode 100644
index 0000000000..dbd4dbd275
--- /dev/null
+++ b/Os/Condition.cpp
@@ -0,0 +1,34 @@
+#include "Os/Condition.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+ConditionVariable::ConditionVariable() : m_delegate(*ConditionVariableInterface::getDelegate(m_handle_storage)) {}
+
+ConditionVariable::~ConditionVariable() {
+    m_delegate.~ConditionVariableInterface();
+}
+
+void ConditionVariable::wait(Os::Mutex& mutex) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<ConditionVariableInterface*>(&this->m_handle_storage[0]));
+    FW_ASSERT(this->m_lock == nullptr || this->m_lock == &mutex); // Confirm the same mutex used across waits
+    this->m_lock = &mutex;
+    // Attempt to lock the mutex and ensure that this was successful or the lock was already held
+    Mutex::Status lock_status = this->m_lock->take();
+    FW_ASSERT(lock_status == Mutex::Status::OP_OK || lock_status == Mutex::Status::ERROR_DEADLOCK);
+    this->m_delegate.wait(mutex);
+}
+void ConditionVariable::notify() {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<ConditionVariableInterface*>(&this->m_handle_storage[0]));
+    this->m_delegate.notify();
+}
+void ConditionVariable::notifyAll() {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<ConditionVariableInterface*>(&this->m_handle_storage[0]));
+    this->m_delegate.notifyAll();
+}
+
+ConditionVariableHandle* ConditionVariable::getHandle(){
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<const ConditionVariableInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate.getHandle();
+}
+
+}
diff --git a/Os/Condition.hpp b/Os/Condition.hpp
new file mode 100644
index 0000000000..b1bc7c9b8e
--- /dev/null
+++ b/Os/Condition.hpp
@@ -0,0 +1,125 @@
+// ======================================================================
+// \title Os/Condition.hpp
+// \brief common function definitions for Os::ConditionVariables
+// ======================================================================
+#include "Os/Mutex.hpp"
+#include "Os/Os.hpp"
+
+#ifndef OS_CONDITION_HPP_
+#define OS_CONDITION_HPP_
+
+namespace Os {
+
+//! \brief Condition variable handle parent
+class ConditionVariableHandle {};
+
+//! \brief interface for condition variables
+//!
+//! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically
+//! reacquiring the mutex once the condition has been notified.
+class ConditionVariableInterface {
+  public:
+    //! Default constructor
+    ConditionVariableInterface() = default;
+    //! Default destructor
+    virtual ~ConditionVariableInterface() = default;
+
+    //! \brief copy constructor is forbidden
+    ConditionVariableInterface(const ConditionVariableInterface& other) = delete;
+
+    //! \brief assignment operator is forbidden
+    virtual ConditionVariableInterface& operator=(const ConditionVariableInterface& other) = delete;
+
+    //! \brief wait on a condition variable
+    //!
+    //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition
+    //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another
+    //! thread of execution.
+    //!
+    //! \param mutex: mutex to unlock as part of this operation
+    virtual void wait(Os::Mutex& mutex) = 0;
+
+    //! \brief notify a single waiter on this condition variable
+    //!
+    //! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters
+    //! and it is advantageous not to hold the lock to prevent immediate re-blocking.
+    virtual void notify() = 0;
+
+    //! \brief notify all waiters on this condition variable
+    //!
+    //! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters
+    //! and it is advantageous not to hold the lock to prevent immediate re-blocking.
+    virtual void notifyAll() = 0;
+
+    //! \brief return the underlying condition variable handle (implementation specific).
+    //! \return internal task handle representation
+    virtual ConditionVariableHandle* getHandle() = 0;
+
+    //! \brief provide a pointer to a Mutex delegate object
+    static ConditionVariableInterface* getDelegate(ConditionVariableHandleStorage& aligned_new_memory);
+};
+
+//! \brief condition variable implementation
+//!
+//! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically
+//! reacquiring the mutex once the condition has been notified.
+class ConditionVariable final : public ConditionVariableInterface {
+  public:
+    //! \brief default constructor
+    ConditionVariable();
+
+    //! \brief default virtual destructor
+    ~ConditionVariable() final;
+
+    //! \brief copy constructor is forbidden
+    ConditionVariable(const ConditionVariableInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    ConditionVariable(const ConditionVariableInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
+
+    //! \brief wait on a condition variable
+    //!
+    //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition
+    //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another
+    //! thread of execution. This function delegates to the underlying implementation.
+    //!
+    //! \warning it is invalid to supply a mutex different from those supplied by others
+    //! \warning conditions *must* be rechecked after the condition variable unlocks
+    //! \note unlocked mutexes will be locked before waiting and will be relocked before this function returns
+    //!
+    //! \param mutex: mutex to unlock as part of this operation
+    void wait(Os::Mutex& mutex) override;
+
+    //! \brief notify a single waiter on this condition variable
+    //!
+    //! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters
+    //! and it is advantageous not to hold the lock to prevent immediate re-blocking. This function delegates to the
+    //! underlying implementation.
+    void notify() override;
+
+    //! \brief notify all waiters on this condition variable
+    //!
+    //! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters
+    //! and it is advantageous not to hold the lock to prevent immediate re-blocking. This function delegates to the
+    //! underlying implementation.
+    void notifyAll() override;
+
+    //! \brief return the underlying condition variable handle (implementation specific). Delegates to implementation.
+    //! \return internal task handle representation
+    ConditionVariableHandle* getHandle() override;
+
+  private:
+    //! Pointer to mutex object previously used
+    Os::Mutex* m_lock = nullptr;
+
+    // This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is
+    // opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in
+    // the byte-array here and set `handle` to that address for storage.
+    alignas(FW_HANDLE_ALIGNMENT) ConditionVariableHandleStorage m_handle_storage; //!< Storage for aligned FileHandle data
+    ConditionVariableInterface& m_delegate;                                       //!< Delegate for the real implementation
+};
+}
+#endif //OS_CONDITION_HPP_
diff --git a/Os/Console.cpp b/Os/Console.cpp
index 56113d42b0..30b6502692 100644
--- a/Os/Console.cpp
+++ b/Os/Console.cpp
@@ -6,8 +6,6 @@
 #include <Fw/Types/Assert.hpp>
 
 namespace Os {
-    Console* Console::s_singleton;
-
     Console::Console() : ConsoleInterface(), Fw::Logger(), m_handle_storage(), m_delegate(*ConsoleInterface::getDelegate(m_handle_storage)) {}
 
     Console::~Console() {
diff --git a/Os/Console.hpp b/Os/Console.hpp
index 9ff47ab3f8..dbcc5e6634 100644
--- a/Os/Console.hpp
+++ b/Os/Console.hpp
@@ -128,7 +128,6 @@ namespace Os {
         static Console& getSingleton();
 
       private:
-        static Console* s_singleton;
         // This section is used to store the implementation-defined console handle. To Os::Console and fprime, this type
         // is opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle
         // in the byte-array here and set `handle` to that address for storage.
diff --git a/Os/Delegate.hpp b/Os/Delegate.hpp
index 0c977f6153..be80ec9044 100644
--- a/Os/Delegate.hpp
+++ b/Os/Delegate.hpp
@@ -42,11 +42,11 @@ namespace Delegate {
 //! \tparam Implementation: implementation class of the delegate (e.g. PosixTask)
 //! \param aligned_new_memory: memory to be filled via placement new call
 //! \return pointer to implementation result of placement new
-template <class Interface, class Implementation>
-inline Interface* makeDelegate(HandleStorage& aligned_new_memory) {
+template <class Interface, class Implementation, class StorageType=HandleStorage>
+inline Interface* makeDelegate(StorageType& aligned_new_memory) {
     // Ensure prerequisites before performing placement new
     static_assert(std::is_base_of<Interface, Implementation>::value, "Implementation must derive from Interface");
-    static_assert(sizeof(Implementation) <= FW_HANDLE_MAX_SIZE, "Handle size not large enough");
+    static_assert(sizeof(Implementation) <= sizeof(StorageType), "Handle size not large enough");
     static_assert((FW_HANDLE_ALIGNMENT % alignof(Implementation)) == 0, "Handle alignment invalid");
     // Placement new the object and ensure non-null result
     Implementation* interface = new (aligned_new_memory) Implementation;
diff --git a/Os/Directory.hpp b/Os/Directory.hpp
index c5a1b6f308..4e9b614f23 100644
--- a/Os/Directory.hpp
+++ b/Os/Directory.hpp
@@ -54,7 +54,7 @@ class DirectoryInterface {
     virtual DirectoryHandle* getHandle() = 0;
 
     //! \brief provide a pointer to a Directory delegate object
-    static DirectoryInterface* getDelegate(HandleStorage& aligned_new_memory);
+    static DirectoryInterface* getDelegate(DirectoryHandleStorage& aligned_new_memory);
 
 
     // -----------------------------------------------------------------
diff --git a/Os/FileSystem.cpp b/Os/FileSystem.cpp
index c2b7a2abfe..8febd12f1d 100644
--- a/Os/FileSystem.cpp
+++ b/Os/FileSystem.cpp
@@ -6,8 +6,6 @@
 #include <Os/FileSystem.hpp>
 
 namespace Os {
-FileSystem* FileSystem::s_singleton;
-
 
 FileSystem::FileSystem() : m_handle_storage(), m_delegate(*FileSystemInterface::getDelegate(m_handle_storage)) {
     FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
diff --git a/Os/FileSystem.hpp b/Os/FileSystem.hpp
index a738e552ef..f5bfa485ff 100644
--- a/Os/FileSystem.hpp
+++ b/Os/FileSystem.hpp
@@ -64,7 +64,7 @@ class FileSystemInterface {
     virtual FileSystemHandle* getHandle() = 0;
 
     //! \brief provide a pointer to a FileSystem delegate object
-    static FileSystemInterface* getDelegate(HandleStorage& aligned_new_memory);
+    static FileSystemInterface* getDelegate(FileSystemHandleStorage& aligned_new_memory);
 
 
     // ------------------------------------------------------------------
@@ -380,8 +380,6 @@ class FileSystem final : public FileSystemInterface {
 
     alignas(FW_HANDLE_ALIGNMENT) FileSystemHandleStorage m_handle_storage;  //!< FileSystem handle storage
     FileSystemInterface& m_delegate;          
-
-    static FileSystem* s_singleton;
 };
 
 
diff --git a/Os/Generic/CMakeLists.txt b/Os/Generic/CMakeLists.txt
new file mode 100644
index 0000000000..de21d99d98
--- /dev/null
+++ b/Os/Generic/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Types")
+add_custom_target("${FPRIME_CURRENT_MODULE}")
+
+#### Os/File/Posix Section ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/PriorityQueue.cpp"
+)
+set(MOD_DEPS
+    Os_Generic_Types
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/PriorityQueue.hpp"
+)
+register_fprime_module(Os_Generic_PriorityQueue)
+register_fprime_implementation(Os/Queue Os_Generic_PriorityQueue "${CMAKE_CURRENT_LIST_DIR}/DefaultPriorityQueue.cpp")
+
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/PriorityQueueTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/queue/CommonTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/queue/QueueRules.cpp"
+)
+set(UT_MOD_DEPS
+        Fw_Time
+        Os
+        Os_Models
+        STest
+)
+choose_fprime_implementation(Os/Queue Os_Generic_PriorityQueue)
+register_fprime_ut(PriorityQueueTest)
+if (TARGET PriorityQueueTest)
+    target_include_directories(PriorityQueueTest PRIVATE "${CMAKE_CURRENT_LIST_DIR}/test/ut")
+endif()
\ No newline at end of file
diff --git a/Os/Generic/DefaultPriorityQueue.cpp b/Os/Generic/DefaultPriorityQueue.cpp
new file mode 100644
index 0000000000..4092bd83e7
--- /dev/null
+++ b/Os/Generic/DefaultPriorityQueue.cpp
@@ -0,0 +1,14 @@
+// ======================================================================
+// \title Os/Posix/DefaultFile.cpp
+// \brief sets default Os::Queue to generic priority queue implementation via linker
+// ======================================================================
+#include "Os/Delegate.hpp"
+#include "Os/Generic/PriorityQueue.hpp"
+#include "Os/Queue.hpp"
+
+namespace Os {
+QueueInterface* QueueInterface::getDelegate(QueueHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<QueueInterface, Os::Generic::PriorityQueue, QueueHandleStorage>(
+        aligned_new_memory);
+}
+}  // namespace Os
diff --git a/Os/Generic/PriorityQueue.cpp b/Os/Generic/PriorityQueue.cpp
new file mode 100644
index 0000000000..0d65beecea
--- /dev/null
+++ b/Os/Generic/PriorityQueue.cpp
@@ -0,0 +1,169 @@
+// ======================================================================
+// \title Os/Generic/PriorityQueue.cpp
+// \brief priority queue implementation for Os::Queue
+// ======================================================================
+
+#include "PriorityQueue.hpp"
+#include <Fw/Types/Assert.hpp>
+#include <cstring>
+#include <new>
+
+namespace Os {
+namespace Generic {
+
+FwSizeType PriorityQueueHandle ::find_index() {
+    FwSizeType index = this->m_indices[this->m_startIndex % this->m_depth];
+    this->m_startIndex = (this->m_startIndex + 1) % this->m_depth;
+    return index;
+}
+
+void PriorityQueueHandle ::return_index(FwSizeType index) {
+    this->m_indices[this->m_stopIndex % this->m_depth] = index;
+    this->m_stopIndex = (this->m_stopIndex + 1) % this->m_depth;
+}
+
+void PriorityQueueHandle ::store_data(FwSizeType index, const U8* data, FwSizeType size) {
+    FW_ASSERT(size <= this->m_maxSize);
+    FW_ASSERT(index < this->m_depth);
+
+    FwSizeType offset = this->m_maxSize * index;
+    ::memcpy(this->m_data + offset, data, size);
+    this->m_sizes[index] = size;
+}
+
+void PriorityQueueHandle ::load_data(FwSizeType index, U8* destination, FwSizeType size) {
+    FW_ASSERT(size <= this->m_maxSize);
+    FW_ASSERT(index < this->m_depth);
+    FwSizeType offset = this->m_maxSize * index;
+    ::memcpy(destination, this->m_data + offset, size);
+}
+
+PriorityQueue::~PriorityQueue() {
+    delete[] this->m_handle.m_data;
+    delete[] this->m_handle.m_indices;
+    delete[] this->m_handle.m_sizes;
+}
+
+QueueInterface::Status PriorityQueue::create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) {
+    // Ensure we are created exactly once
+    FW_ASSERT(this->m_handle.m_indices == nullptr);
+    FW_ASSERT(this->m_handle.m_sizes == nullptr);
+    FW_ASSERT(this->m_handle.m_data == nullptr);
+
+    // Allocate indices list
+    FwSizeType* indices = new (std::nothrow) FwSizeType[depth];
+    if (indices == nullptr) {
+        return QueueInterface::Status::UNKNOWN_ERROR;
+    }
+    // Allocate sizes list or clean-up
+    FwSizeType* sizes = new (std::nothrow) FwSizeType[depth];
+    if (sizes == nullptr) {
+        delete[] indices;
+        return QueueInterface::Status::UNKNOWN_ERROR;
+    }
+    // Allocate sizes list or clean-up
+    U8* data = new (std::nothrow) U8[depth * messageSize];
+    if (data == nullptr) {
+        delete[] indices;
+        delete[] sizes;
+        return QueueInterface::Status::UNKNOWN_ERROR;
+    }
+    // Allocate max heap or clean-up
+    bool created = this->m_handle.m_heap.create(depth);
+    if (not created) {
+        delete[] indices;
+        delete[] sizes;
+        delete[] data;
+        return QueueInterface::Status::UNKNOWN_ERROR;
+    }
+    // Assign initial indices and sizes
+    for (FwSizeType i = 0; i < depth; i++) {
+        indices[i] = i;
+        sizes[i] = 0;
+    }
+    // Set local tracking variables
+    this->m_handle.m_maxSize = messageSize;
+    this->m_handle.m_indices = indices;
+    this->m_handle.m_data = data;
+    this->m_handle.m_sizes = sizes;
+    this->m_handle.m_startIndex = 0;
+    this->m_handle.m_stopIndex = 0;
+    this->m_handle.m_depth = depth;
+    this->m_handle.m_highMark = 0;
+
+    return QueueInterface::Status::OP_OK;
+}
+
+QueueInterface::Status PriorityQueue::send(const U8* buffer,
+                                           FwSizeType size,
+                                           FwQueuePriorityType priority,
+                                           QueueInterface::BlockingType blockType) {
+    // Check for sizing problem before locking
+    if (size > this->m_handle.m_maxSize) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    }
+    // Artificial block scope for scope lock ensuring an unlock in all cases and ensuring an unlock before notify
+    {
+        Os::ScopeLock lock(this->m_handle.m_data_lock);
+        if (this->m_handle.m_heap.isFull() and blockType == BlockingType::NONBLOCKING) {
+            return QueueInterface::Status::FULL;
+        }
+        // Will loop and block until full is false
+        while (this->m_handle.m_heap.isFull()) {
+            this->m_handle.m_full.wait(this->m_handle.m_data_lock);
+        }
+        FwSizeType index = this->m_handle.find_index();
+
+        // Space must exist, push must work
+        FW_ASSERT(this->m_handle.m_heap.push(priority, index));
+        this->m_handle.store_data(index, buffer, size);
+        this->m_handle.m_sizes[index] = size;
+        this->m_handle.m_highMark = FW_MAX(this->m_handle.m_highMark, this->getMessagesAvailable());
+    }
+    this->m_handle.m_empty.notify();
+    return QueueInterface::Status::OP_OK;
+}
+
+QueueInterface::Status PriorityQueue::receive(U8* destination,
+                                              FwSizeType capacity,
+                                              QueueInterface::BlockingType blockType,
+                                              FwSizeType& actualSize,
+                                              FwQueuePriorityType& priority) {
+    {
+        Os::ScopeLock lock(this->m_handle.m_data_lock);
+        if (this->m_handle.m_heap.isEmpty() and blockType == BlockingType::NONBLOCKING) {
+            return QueueInterface::Status::EMPTY;
+        }
+        // Loop and lock while empty
+        while (this->m_handle.m_heap.isEmpty()) {
+            this->m_handle.m_empty.wait(this->m_handle.m_data_lock);
+        }
+
+        FwSizeType index;
+        // Message must exist, so pop must pass and size must be valid
+        FW_ASSERT(this->m_handle.m_heap.pop(priority, index));
+        actualSize = this->m_handle.m_sizes[index];
+        FW_ASSERT(actualSize <= capacity);
+        this->m_handle.load_data(index, destination, actualSize);
+        this->m_handle.return_index(index);
+    }
+    this->m_handle.m_full.notify();
+    return QueueInterface::Status::OP_OK;
+}
+
+FwSizeType PriorityQueue::getMessagesAvailable() const {
+    return this->m_handle.m_heap.getSize();
+}
+
+FwSizeType PriorityQueue::getMessageHighWaterMark() const {
+    // Safe to cast away const in this context because scope lock will restore unlocked state on return
+    Os::ScopeLock lock(const_cast<Mutex&>(this->m_handle.m_data_lock));
+    return this->m_handle.m_highMark;
+}
+
+QueueHandle* PriorityQueue::getHandle() {
+    return &this->m_handle;
+}
+
+}  // namespace Generic
+}  // namespace Os
diff --git a/Os/Generic/PriorityQueue.hpp b/Os/Generic/PriorityQueue.hpp
new file mode 100644
index 0000000000..e0e0f03052
--- /dev/null
+++ b/Os/Generic/PriorityQueue.hpp
@@ -0,0 +1,139 @@
+// ======================================================================
+// \title Os/Generic/PriorityQueue.hpp
+// \brief priority queue implementation definitions for Os::Queue
+// ======================================================================
+#include "Os/Condition.hpp"
+#include "Os/Generic/Types/MaxHeap.hpp"
+#include "Os/Mutex.hpp"
+#include "Os/Queue.hpp"
+#ifndef OS_GENERIC_PRIORITYQUEUE_HPP
+#define OS_GENERIC_PRIORITYQUEUE_HPP
+
+namespace Os {
+namespace Generic {
+
+//! \brief critical data stored for priority queue
+//!
+//! The priority queue has two essential data structures: a block of unordered memory storing message data and size. The
+//! queue also stores a circular list of indices into that memory tracking which slots are free and which are taken.
+//! These indices are ordered by a max heap data structure projecting priority on to the otherwise unordered data. Both
+//! the data region and index list have queue depth number of entries.
+struct PriorityQueueHandle : public QueueHandle {
+    Types::MaxHeap m_heap;            //!< MaxHeap data store for tracking priority
+    U8* m_data = nullptr;             //!< Pointer to data allocation
+    FwSizeType* m_indices = nullptr;  //!< List of indices into data
+    FwSizeType* m_sizes = nullptr;    //!< Size store for each method
+    FwSizeType m_depth = 0;           //!< Depth of the queue
+    FwSizeType m_startIndex = 0;      //!< Start index of the circular data structure
+    FwSizeType m_stopIndex = 0;       //!< End index of the circular data structure
+    FwSizeType m_maxSize = 0;         //!< Maximum size allowed of a message
+    FwSizeType m_highMark = 0;        //!< Message count high water mark
+    Os::Mutex m_data_lock;            //!< Lock against data manipulation
+    Os::ConditionVariable m_full;     //!< Queue full condition variable to support blocking
+    Os::ConditionVariable m_empty;    //!< Queue empty condition variable to support blocking
+
+    //!\brief find an available index to store data from the list
+    FwSizeType find_index();
+
+    //!\brief return index to the circular data structure
+    //!\param index: index to return to the list
+    void return_index(FwSizeType index);
+
+    //!\brief store data into a set index in the data store
+    void store_data(FwSizeType index, const U8* source, FwSizeType size);
+
+    //!\brief load data from a set index in the data store
+    void load_data(FwSizeType index, U8* destination, FwSizeType capacity);
+};
+//! \brief generic priority queue implementation
+//!
+//! A generic implementation of a priority queue to support the Os::QueueInterface. This queue uses OSAL mutexes,
+//! and condition variables to provide for a task-safe blocking queue implementation. Data is stored in heap memory.
+//!
+//! \warning allocates memory on the heap
+class PriorityQueue : public Os::QueueInterface {
+  public:
+    //! \brief default queue interface constructor
+    PriorityQueue() = default;
+
+    //! \brief default queue destructor
+    virtual ~PriorityQueue();
+
+    //! \brief copy constructor is forbidden
+    PriorityQueue(const QueueInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    PriorityQueue(const QueueInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    PriorityQueue& operator=(const QueueInterface& other) override = delete;
+
+    //! \brief create queue storage
+    //!
+    //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each.
+    //!
+    //! \warning allocates memory on the heap
+    //!
+    //! \param name: name of queue
+    //! \param depth: depth of queue in number of messages
+    //! \param messageSize: size of an individual message
+    //! \return: status of the creation
+    Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override;
+
+    //! \brief send a message into the queue
+    //!
+    //! Send a message into the queue, providing the message data, size, priority, and blocking type. When
+    //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error
+    //! status on queue full.
+    //!
+    //! \warning It is invalid to send a null buffer
+    //! \warning This method will block if the queue is full and blockType is set to BLOCKING
+    //!
+    //! \param buffer: message data
+    //! \param size: size of message data
+    //! \param priority: priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return: status of the send
+    Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) override;
+
+    //! \brief receive a message from the queue
+    //!
+    //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type.
+    //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an
+    //! error status on queue empty. Actual size received and priority of message is set on success status.
+    //!
+    //! \warning It is invalid to send a null buffer
+    //! \warning This method will block if the queue is full and blockType is set to BLOCKING
+    //!
+    //! \param destination: destination for message data
+    //! \param capacity: maximum size of message data
+    //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty
+    //! \param actualSize: (output) actual size of message read
+    //! \param priority: (output) priority of message read
+    //! \return: status of the send
+    Status receive(U8* destination,
+                   FwSizeType capacity,
+                   BlockingType blockType,
+                   FwSizeType& actualSize,
+                   FwQueuePriorityType& priority) override;
+
+    //! \brief get number of messages available
+    //!
+    //! \return number of messages available
+    FwSizeType getMessagesAvailable() const override;
+
+    //! \brief get maximum messages stored at any given time
+    //!
+    //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for this
+    //! queue.
+    //! \return queue message high-water mark
+    FwSizeType getMessageHighWaterMark() const override;
+
+    QueueHandle* getHandle() override;
+
+    PriorityQueueHandle m_handle;
+};
+}  // namespace Generic
+}  // namespace Os
+
+#endif  // OS_GENERIC_PRIORITYQUEUE_HPP
diff --git a/Os/Generic/Types/CMakeLists.txt b/Os/Generic/Types/CMakeLists.txt
new file mode 100644
index 0000000000..b4b7632025
--- /dev/null
+++ b/Os/Generic/Types/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/MaxHeap.cpp"
+)
+set(MOD_DEPS
+        "Fw/Types"
+)
+register_fprime_module()
+
+# Rules based unit testing
+set(UT_MOD_DEPS
+        STest
+        Fw/Types
+)
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/MaxHeap/MaxHeapTest.cpp"
+)
+register_fprime_ut("Types_Max_Heap_test")
\ No newline at end of file
diff --git a/Os/Generic/Types/MaxHeap.cpp b/Os/Generic/Types/MaxHeap.cpp
new file mode 100644
index 0000000000..895bf6c171
--- /dev/null
+++ b/Os/Generic/Types/MaxHeap.cpp
@@ -0,0 +1,252 @@
+// ======================================================================
+// \title  MaxHeap.cpp
+// \author dinkel
+// \brief  An implementation of a stable max heap data structure. Items
+//         popped off the heap are guaranteed to be in order of decreasing
+//         "value" (max removed first). Items of equal "value" will be
+//         popped off in FIFO order. The performance of both push and pop
+//         is O(log(n)).
+//
+// \copyright
+// Copyright 2009-2015, by the California Institute of Technology.
+// ALL RIGHTS RESERVED.  United States Government Sponsorship
+// acknowledged.
+//
+// ======================================================================
+
+#include "Os/Generic/Types/MaxHeap.hpp"
+#include <FpConfig.hpp>
+#include <Fw/Logger/Logger.hpp>
+#include "Fw/Types/Assert.hpp"
+
+#include <cstdio>
+#include <new>
+
+// Macros for traversing the heap:
+#define LCHILD(x) (2 * x + 1)
+#define RCHILD(x) (2 * x + 2)
+#define PARENT(x) ((x - 1) / 2)
+
+namespace Types {
+
+MaxHeap::MaxHeap() {
+    // Initialize the heap:
+    this->m_capacity = 0;
+    this->m_heap = nullptr;
+    this->m_size = 0;
+    this->m_order = 0;
+}
+
+MaxHeap::~MaxHeap() {
+    delete[] this->m_heap;
+    this->m_heap = nullptr;
+}
+
+bool MaxHeap::create(FwSizeType capacity) {
+    FW_ASSERT(this->m_heap == nullptr);
+    // Loop bounds will overflow if capacity set to the max allowable value
+    FW_ASSERT(capacity < std::numeric_limits<FwSizeType>::max());
+    this->m_heap = new (std::nothrow) Node[capacity];
+    if (nullptr == this->m_heap) {
+        return false;
+    }
+    this->m_capacity = capacity;
+    return true;
+}
+
+bool MaxHeap::push(FwQueuePriorityType value, FwSizeType id) {
+    // If the queue is full, return false:
+    if (this->isFull()) {
+        return false;
+    }
+
+    // Heap indexes:
+    FwSizeType parent;
+    FwSizeType index = this->m_size;
+
+    // Max loop bounds for bit flip protection:
+    const FwSizeType maxIter = this->m_size + 1;
+    FW_ASSERT(maxIter != 0);
+    // Start at the bottom of the heap and work our ways
+    // upwards until we find a parent that has a value
+    // greater than ours.
+    FwSizeType i = 0;
+    for (i = 0; (i < maxIter) && (index != 0); i++) {
+        // Get the parent index:
+        parent = PARENT(index);
+        // The parent index should ALWAYS be less than the
+        // current index. Let's verify that.
+        FW_ASSERT(parent < index, static_cast<FwAssertArgType>(parent), static_cast<FwAssertArgType>(index));
+        // If the current value is less than the parent,
+        // then the current index is in the correct place,
+        // so break out of the loop:
+        if (value <= this->m_heap[parent].value) {
+            break;
+        }
+        // Swap the parent and child:
+        this->m_heap[index] = this->m_heap[parent];
+        index = parent;
+    }
+
+    // Check for programming errors or bit flips:
+    FW_ASSERT(i < maxIter, static_cast<FwAssertArgType>(i), static_cast<FwAssertArgType>(maxIter));
+    FW_ASSERT(index <= this->m_size, static_cast<FwAssertArgType>(index));
+
+    // Set the values of the new element:
+    this->m_heap[index].value = value;
+    this->m_heap[index].order = m_order;
+    this->m_heap[index].id = id;
+
+    ++this->m_size;
+    ++this->m_order;
+    return true;
+}
+
+bool MaxHeap::pop(FwQueuePriorityType& value, FwSizeType& id) {
+    // If there is nothing in the heap then
+    // return false:
+    if (this->isEmpty()) {
+        return false;
+    }
+
+    // Set the return values to the top (max) of
+    // the heap:
+    value = this->m_heap[0].value;
+    id = this->m_heap[0].id;
+
+    // Now place the last element on the heap in
+    // the root position, and resize the heap.
+    // This will put the smallest value in the
+    // heap on the top, violating the heap property.
+    FwSizeType index = this->m_size - 1;
+    // Fw::Logger::log("Putting on top: i: %u v: %d\n", index, this->m_heap[index].value);
+    this->m_heap[0] = this->m_heap[index];
+    --this->m_size;
+
+    // Now that the heap property is violated, we
+    // need to reorganize the heap to restore it's
+    // heapy-ness.
+    this->heapify();
+    return true;
+}
+
+// Is the heap full:
+bool MaxHeap::isFull() {
+    return (this->m_size == this->m_capacity);
+}
+
+// Is the heap empty:
+bool MaxHeap::isEmpty() {
+    return (this->m_size == 0);
+}
+
+// Get the current size of the heap:
+FwSizeType MaxHeap::getSize() const {
+    return this->m_size;
+}
+
+// A non-recursive heapify method.
+// Note: This method had an additional property, such that
+// items pushed of the same priority will be popped in FIFO
+// order.
+void MaxHeap::heapify() {
+    FwSizeType index = 0;
+    FwSizeType left;
+    FwSizeType right;
+    FwSizeType largest;
+
+    // Max loop bounds for bit flip protection:
+    const FwSizeType maxIter = this->m_size + 1;
+    FwSizeType i = 0;
+
+    for (i = 0; (i < maxIter) && (index <= this->m_size); i++) {
+        // Get the children indexes for this node:
+        left = LCHILD(index);
+        right = RCHILD(index);
+        FW_ASSERT(left > index, static_cast<FwAssertArgType>(left), static_cast<FwAssertArgType>(index));
+        FW_ASSERT(right > left, static_cast<FwAssertArgType>(right), static_cast<FwAssertArgType>(left));
+
+        // If the left node is bigger than the heap
+        // size, we have reached the end of the heap
+        // so we can stop:
+        if (left >= this->m_size) {
+            break;
+        }
+
+        // Initialize the largest node to the current
+        // node:
+        largest = index;
+
+        // Which one is larger, the current node or
+        // the left node?:
+        largest = this->max(left, largest);
+
+        // Make sure the right node exists before checking it:
+        if (right < this->m_size) {
+            // Which one is larger, the current largest
+            // node or the right node?
+            largest = this->max(right, largest);
+        }
+
+        // If the largest node is the current node
+        // then we are done heapifying:
+        if (largest == index) {
+            break;
+        }
+
+        // Swap the largest node with the current node:
+        this->swap(index, largest);
+
+        // Set the new index to whichever child was larger:
+        index = largest;
+    }
+
+    // Check for programming errors or bit flips:
+    FW_ASSERT(i < maxIter, static_cast<FwAssertArgType>(i), static_cast<FwAssertArgType>(maxIter));
+    FW_ASSERT(index <= this->m_size, static_cast<FwAssertArgType>(index));
+}
+
+// Return the maximum priority index between two nodes. If their
+// priorities are equal, return the oldest to keep the heap stable
+FwSizeType MaxHeap::max(FwSizeType a, FwSizeType b) {
+    static_assert(not std::numeric_limits<FwSizeType>::is_signed, "FwSizeType must be unsigned");
+    FW_ASSERT(a < this->m_size, static_cast<FwAssertArgType>(a), static_cast<FwAssertArgType>(this->m_size));
+    FW_ASSERT(b < this->m_size, static_cast<FwAssertArgType>(b), static_cast<FwAssertArgType>(this->m_size));
+
+    // Extract the priorities:
+    FwQueuePriorityType aValue = this->m_heap[a].value;
+    FwQueuePriorityType bValue = this->m_heap[b].value;
+
+    // If the priorities are equal, the "larger" one will be
+    // the "older" one as determined by order pushed on to the
+    // heap. Using this secondary ordering technique makes the
+    // heap stable (ie. FIFO for equal priority elements).
+    // Note: We check this first, because it is the most common
+    // case. Let's save as many ticks as we can...
+    if (aValue == bValue) {
+        FwSizeType aAge = this->m_order - this->m_heap[a].order;
+        FwSizeType bAge = this->m_order - this->m_heap[b].order;
+        if (aAge > bAge) {
+            return a;
+        }
+        return b;
+    }
+
+    // Which priority is larger?:
+    if (aValue > bValue) {
+        return a;
+    }
+    // B is larger:
+    return b;
+}
+
+// Swap two nodes in the heap:
+void MaxHeap::swap(FwSizeType a, FwSizeType b) {
+    FW_ASSERT(a < this->m_size, static_cast<FwAssertArgType>(a), static_cast<FwAssertArgType>(this->m_size));
+    FW_ASSERT(b < this->m_size, static_cast<FwAssertArgType>(b), static_cast<FwAssertArgType>(this->m_size));
+    Node temp = this->m_heap[a];
+    this->m_heap[a] = this->m_heap[b];
+    this->m_heap[b] = temp;
+}
+
+}  // namespace Types
diff --git a/Os/Pthreads/MaxHeap/MaxHeap.hpp b/Os/Generic/Types/MaxHeap.hpp
similarity index 64%
rename from Os/Pthreads/MaxHeap/MaxHeap.hpp
rename to Os/Generic/Types/MaxHeap.hpp
index 4456d6b31b..06d3d5d22e 100644
--- a/Os/Pthreads/MaxHeap/MaxHeap.hpp
+++ b/Os/Generic/Types/MaxHeap.hpp
@@ -10,23 +10,23 @@
 //
 // ======================================================================
 
-#ifndef OS_PTHREADS_MAX_HEAP_HPP
-#define OS_PTHREADS_MAX_HEAP_HPP
+#ifndef UTILS_TYPES_MAX_HEAP_HPP
+#define UTILS_TYPES_MAX_HEAP_HPP
 
 #include <FpConfig.hpp>
 
-namespace Os {
+namespace Types {
 
-  //! \class MaxHeap
-  //! \brief A stable max heap data structure
-  //!
-  //! This is a max heap data structure. Items of the highest value will
-  //! be popped off the heap first. Items of equal value will be popped
-  //! off in FIFO order. Insertion and deletion from the heap are both
-  //! O(log(n)) time.
-  class MaxHeap {
-
-    public:
+//! \class MaxHeap
+//! \brief A stable max heap data structure
+//!
+//! This is a max heap data structure. Items of the highest value will
+//! be popped off the heap first. Items of equal value will be popped
+//! off in FIFO order. Insertion and deletion from the heap are both
+//! O(log(n)) time.
+//! \warning allocates memory on the heap
+class MaxHeap {
+  public:
     //! \brief MaxHeap constructor
     //!
     //! Create a max heap object
@@ -40,10 +40,11 @@ namespace Os {
     //! \brief MaxHeap creation
     //!
     //! Create the max heap with a given maximum size
+    //! \warning allocates memory on the heap
     //!
     //! \param capacity the maximum number of elements to store in the heap
     //!
-    bool create(NATIVE_UINT_TYPE capacity);
+    bool create(FwSizeType capacity);
     //! \brief Push an item onto the heap.
     //!
     //! The item will be put into the heap according to its value. The
@@ -53,7 +54,7 @@ namespace Os {
     //! \param value the value of the element to push onto the heap
     //! \param id the identifier of the element to push onto the heap
     //!
-    bool push(NATIVE_INT_TYPE value, NATIVE_UINT_TYPE id);
+    bool push(FwQueuePriorityType value, FwSizeType id);
     //! \brief Pop an item from the heap.
     //!
     //! The item with the maximum value in the heap will be returned.
@@ -63,7 +64,7 @@ namespace Os {
     //! \param value the value of the element to popped from the heap
     //! \param id the identifier of the element popped from the heap
     //!
-    bool pop(NATIVE_INT_TYPE& value, NATIVE_UINT_TYPE& id);
+    bool pop(FwQueuePriorityType& value, FwSizeType& id);
     //! \brief Is the heap full?
     //!
     //! Has the heap reached max size. No new items can be put on the
@@ -81,36 +82,31 @@ namespace Os {
     //! This function returns the current number of items on the
     //! heap.
     //!
-    NATIVE_UINT_TYPE getSize();
-    //! \brief Print the contents of the heap to stdout.
-    //!
-    //! This function here is for debugging purposes.
-    //!
-    void print();
+    FwSizeType getSize() const;
 
-    private:
+  private:
     // Private functions:
     // Ensure the heap meets the heap property:
     void heapify();
     // Swap two elements on the heap:
-    void swap(NATIVE_UINT_TYPE a, NATIVE_UINT_TYPE b);
+    void swap(FwSizeType a, FwSizeType b);
     // Return the max between two elements on the heap:
-    NATIVE_UINT_TYPE max(NATIVE_UINT_TYPE a, NATIVE_UINT_TYPE b);
+    FwSizeType max(FwSizeType a, FwSizeType b);
 
     // The data structure for a node on the heap:
     struct Node {
-      NATIVE_INT_TYPE value; // the priority of the node
-      NATIVE_UINT_TYPE order; // order in which node was pushed
-      NATIVE_UINT_TYPE id; // unique id for this node
+        FwQueuePriorityType value;  // the priority of the node
+        FwSizeType order;           // order in which node was pushed
+        FwSizeType id;              // unique id for this node
     };
 
     // Private members:
-    Node* m_heap; // the heap itself
-    NATIVE_UINT_TYPE m_size; // the current size of the heap
-    NATIVE_UINT_TYPE m_order; // the current count of heap pushes
-    NATIVE_UINT_TYPE m_capacity; // the maximum capacity of the heap
-  };
+    Node* m_heap;           // the heap itself
+    FwSizeType m_size;      // the current size of the heap
+    FwSizeType m_order;     // the current count of heap pushes
+    FwSizeType m_capacity;  // the maximum capacity of the heap
+};
 
-}
+}  // namespace Types
 
-#endif // OS_PTHREADS_MAX_HEAP_HPP
+#endif  // UTILS_TYPES_MAX_HEAP_HPP
diff --git a/Os/IPCQueue.hpp b/Os/IPCQueue.hpp
deleted file mode 100644
index ca19acca79..0000000000
--- a/Os/IPCQueue.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _IPCQueue_hpp_
-#define _IPCQueue_hpp_
-
-#include <Os/Queue.hpp>
-
-namespace Os {
-    class IPCQueue : public Os::Queue {
-        public:
-            IPCQueue();
-            ~IPCQueue();
-            QueueStatus create(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize); //!<  create a message queue
-
-            // Base class has overloads - NOTE(mereweth) - this didn't work
-            //using Queue::send;
-            //using Queue::receive;
-
-            // Send serialized buffers
-            QueueStatus send(const Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE priority, QueueBlocking block); //!<  send a message
-            QueueStatus receive(Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE &priority, QueueBlocking block); //!<  receive a message
-
-            // Send raw buffers
-            QueueStatus send(const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority, QueueBlocking block); //!<  send a message
-            QueueStatus receive(U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority, QueueBlocking block); //!<  receive a message
-
-            NATIVE_INT_TYPE getNumMsgs() const; //!< get the number of messages in the queue
-            NATIVE_INT_TYPE getMaxMsgs() const; //!< get the maximum number of messages (high watermark)
-            NATIVE_INT_TYPE getQueueSize() const; //!< get the queue depth (maximum number of messages queue can hold)
-            NATIVE_INT_TYPE getMsgSize() const; //!< get the message size (maximum message size queue can hold)
-    };
-}
-
-#endif
diff --git a/Os/IPCQueueCommon.cpp b/Os/IPCQueueCommon.cpp
deleted file mode 100644
index b8790a8682..0000000000
--- a/Os/IPCQueueCommon.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <Os/IPCQueue.hpp>
-#include <cstring>
-
-namespace Os {
-
-    Queue::QueueStatus IPCQueue::send(const Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE priority, QueueBlocking block) {
-
-        const U8* msgBuff = buffer.getBuffAddr();
-        NATIVE_INT_TYPE buffLength = static_cast<NATIVE_INT_TYPE>(buffer.getBuffLength());
-
-        return this->send(msgBuff,buffLength,priority, block);
-
-    }
-
-    Queue::QueueStatus IPCQueue::receive(Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE &priority, QueueBlocking block) {
-
-        U8* msgBuff = buffer.getBuffAddr();
-        NATIVE_INT_TYPE buffCapacity = static_cast<NATIVE_INT_TYPE>(buffer.getBuffCapacity());
-        NATIVE_INT_TYPE recvSize = 0;
-
-        Queue::QueueStatus recvStat = this->receive(msgBuff, buffCapacity, recvSize, priority, block);
-
-        if (QUEUE_OK == recvStat) {
-            if (buffer.setBuffLen(static_cast<NATIVE_UINT_TYPE>(recvSize)) == Fw::FW_SERIALIZE_OK) {
-                return QUEUE_OK;
-            } else {
-                return QUEUE_SIZE_MISMATCH;
-            }
-        } else {
-            return recvStat;
-        }
-    }
-
-}
diff --git a/Os/LocklessQueue.hpp b/Os/LocklessQueue.hpp
deleted file mode 100644
index 2eb8f6044b..0000000000
--- a/Os/LocklessQueue.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _LOCKLESS_QUEUE_H_
-#define _LOCKLESS_QUEUE_H_
-
-#include <FpConfig.hpp>
-#include <Os/Queue.hpp>
-#ifndef BUILD_DARWIN // Allow compiling
-#include <mqueue.h>
-#endif
-
-namespace Os {
-
-  class LocklessQueue {
-
-    typedef struct QueueNode_s {
-      U8                 * data;
-      NATIVE_INT_TYPE      size;
-      struct QueueNode_s * next;
-    } QueueNode;
-    
-  public:
-    
-    LocklessQueue (NATIVE_INT_TYPE maxmsg, NATIVE_INT_TYPE msgsize);
-    ~LocklessQueue();
-
-#ifndef BUILD_DARWIN // Allow compiling
-    void GetAttr (mq_attr & attr);
-#endif
-
-    Os::Queue::QueueStatus Send (const U8 * buffer, NATIVE_INT_TYPE size);
-    Os::Queue::QueueStatus Receive (U8 * buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE & size);
-
-  private:
-    bool PopFree (QueueNode ** free_node);
-    void PushFree (QueueNode * my_node);
-
-    QueueNode *  m_first;   
-    QueueNode *  m_last;    
-
-    QueueNode *  m_free_head;
-
-    QueueNode *  m_index;
-    U8        *  m_data;
-#ifndef BUILD_DARWIN
-    mq_attr      m_attr;
-#endif
-  };
-
-}
-
-#endif
diff --git a/Os/MacOs/IPCQueueStub.cpp b/Os/MacOs/IPCQueueStub.cpp
index 83a947829f..c915775c9b 100644
--- a/Os/MacOs/IPCQueueStub.cpp
+++ b/Os/MacOs/IPCQueueStub.cpp
@@ -340,7 +340,7 @@ namespace Os {
       return receiveBlockIPCStub(queueHandle, buffer, capacity, actualSize, priority);
   }
 
-  NATIVE_INT_TYPE IPCQueue::getNumMsgs() const {
+  NATIVE_INT_TYPE IPCQueue::getMessagesAvailable() const {
       QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
       if (nullptr == queueHandle) {
           return 0;
diff --git a/Os/Mutex.cpp b/Os/Mutex.cpp
index de3e58a7ec..5aaab43288 100644
--- a/Os/Mutex.cpp
+++ b/Os/Mutex.cpp
@@ -42,4 +42,13 @@ void Mutex::unLock() {
     Mutex::Status status = this->release();
     FW_ASSERT(status == Mutex::Status::OP_OK, status);
 }
+
+ScopeLock::ScopeLock(Mutex& mutex) : m_mutex(mutex) {
+    this->m_mutex.lock();
+}
+
+ScopeLock::~ScopeLock() {
+    this->m_mutex.release();
+}
+
 }  // namespace Os
diff --git a/Os/Mutex.hpp b/Os/Mutex.hpp
index 1a12c58906..437721397a 100644
--- a/Os/Mutex.hpp
+++ b/Os/Mutex.hpp
@@ -30,6 +30,9 @@ class MutexInterface {
     //! \brief copy constructor is forbidden
     MutexInterface(const MutexInterface& other) = delete;
 
+    //! \brief copy constructor is forbidden
+    MutexInterface(const MutexInterface* other) = delete;
+
     //! \brief assignment operator is forbidden
     MutexInterface& operator=(const MutexInterface& other) = delete;
 
@@ -67,6 +70,35 @@ class Mutex final : public MutexInterface {
     alignas(FW_HANDLE_ALIGNMENT) HandleStorage m_handle_storage;  //!< Mutex handle storage
     MutexInterface& m_delegate;                                   //!< Delegate for the real implementation
 };
+//! \brief locks a mutex within the current scope
+//!
+//! The scope lock will lock the associated mutex immediately and will ensure the mutex is unlock when the scope lock
+//! is destroyed.
+//!
+//! \warning it is unadvisable to dynamically allocate ScopeLock as this violates the implied usage.
+class ScopeLock {
+  public:
+    //! \brief construct the scope lock
+    //!
+    //! Will lock the supplied mutex and will unlock the mutex when this object goes out of scope.
+    //! \param mutex
+    explicit ScopeLock(Mutex& mutex);
+
+    //!\brief unlock the scoped mutex
+    ~ScopeLock();
+
+    //! \brief copy constructor is forbidden
+    ScopeLock(const ScopeLock& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    ScopeLock(const ScopeLock* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    ScopeLock& operator=(const ScopeLock& other) = delete;
+
+  private:
+    Mutex& m_mutex; //!< Stores the mutex reference
+};
 }  // namespace Os
 
 #endif
diff --git a/Os/Os.hpp b/Os/Os.hpp
index 1a68c13165..feee9aaf7f 100644
--- a/Os/Os.hpp
+++ b/Os/Os.hpp
@@ -7,10 +7,11 @@
 #include "FpConfig.h"
 
 //! Storage type for OSAL handles
+typedef U8 QueueHandleStorage[FW_QUEUE_HANDLE_MAX_SIZE];
 typedef U8 HandleStorage[FW_HANDLE_MAX_SIZE];
-
 typedef U8 DirectoryHandleStorage[FW_DIRECTORY_HANDLE_MAX_SIZE];
 typedef U8 FileSystemHandleStorage[FW_FILESYSTEM_HANDLE_MAX_SIZE];
+typedef U8 ConditionVariableHandleStorage[FW_CONDITION_VARIABLE_HANDLE_MAX_SIZE];
 
 namespace Os {
 
@@ -18,5 +19,4 @@ namespace Os {
 void init();
 
 }  // namespace Os
-
 #endif
diff --git a/Os/Posix/CMakeLists.txt b/Os/Posix/CMakeLists.txt
index 7070077c91..30396e8ba2 100644
--- a/Os/Posix/CMakeLists.txt
+++ b/Os/Posix/CMakeLists.txt
@@ -104,6 +104,7 @@ register_fprime_ut(PosixTaskTest)
 # -----------------------------------------
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Mutex.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/ConditionVariable.cpp"
 )
 set(HEADER_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Mutex.hpp"
@@ -125,7 +126,6 @@ set(UT_MOD_DEPS
 choose_fprime_implementation(Os/Mutex Os_Mutex_Posix)
 register_fprime_ut(PosixMutexTest)
 
-
 # -----------------------------------------
 ### Os/FileSystem/Posix Section
 # -----------------------------------------
@@ -178,3 +178,13 @@ set(UT_MOD_DEPS
 choose_fprime_implementation(Os/Directory Os_Directory_Posix)
 register_fprime_ut(PosixDirectoryTest)
 
+# -----------------------------------------
+### Os/ConditionVariable/Posix Section
+# -----------------------------------------
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/condition/CommonTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/condition/ConditionRules.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/PosixConditionTests.cpp"
+)
+choose_fprime_implementation(Os/Mutex Os_Mutex_Posix)
+register_fprime_ut(PosixConditionTests)
diff --git a/Os/Posix/ConditionVariable.cpp b/Os/Posix/ConditionVariable.cpp
new file mode 100644
index 0000000000..8158c1a730
--- /dev/null
+++ b/Os/Posix/ConditionVariable.cpp
@@ -0,0 +1,38 @@
+// ======================================================================
+// \title Os/Posix/ConditionVariable.cpp
+// \brief Posix implementations for Os::ConditionVariable
+// ======================================================================
+#include "Os/Posix/ConditionVariable.hpp"
+#include "Os/Posix/Mutex.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+namespace Posix {
+namespace Mutex {
+
+PosixConditionVariable::PosixConditionVariable() {
+    PlatformIntType status = pthread_cond_init(&this->m_handle.m_condition, nullptr);
+    FW_ASSERT(status == 0, status);  // If this fails, something horrible happened.
+}
+PosixConditionVariable::~PosixConditionVariable() {
+    (void)pthread_cond_destroy(&this->m_handle.m_condition);
+}
+
+void PosixConditionVariable::wait(Os::Mutex& mutex) {
+    PosixMutexHandle* mutex_handle = reinterpret_cast<PosixMutexHandle*>(mutex.getHandle());
+    FW_ASSERT(pthread_cond_wait(&this->m_handle.m_condition, &mutex_handle->m_mutex_descriptor) == 0);
+}
+void PosixConditionVariable::notify() {
+    FW_ASSERT(pthread_cond_signal(&this->m_handle.m_condition) == 0);
+}
+void PosixConditionVariable::notifyAll() {
+    FW_ASSERT(pthread_cond_broadcast(&this->m_handle.m_condition) == 0);
+}
+
+ConditionVariableHandle* PosixConditionVariable::getHandle() {
+    return &m_handle;
+}
+
+}
+}
+}
diff --git a/Os/Posix/ConditionVariable.hpp b/Os/Posix/ConditionVariable.hpp
new file mode 100644
index 0000000000..6a6dcbabb9
--- /dev/null
+++ b/Os/Posix/ConditionVariable.hpp
@@ -0,0 +1,54 @@
+// ======================================================================
+// \title Os/Posix/ConditionVariable.hpp
+// \brief Posix definitions for Os::ConditionVariable
+// ======================================================================
+#ifndef OS_POSIX_CONDITION_VARIABLE_HPP
+#define OS_POSIX_CONDITION_VARIABLE_HPP
+#include <pthread.h>
+#include <Os/Condition.hpp>
+
+namespace Os {
+namespace Posix {
+namespace Mutex {
+
+struct PosixConditionVariableHandle : public ConditionVariableHandle {
+    pthread_cond_t m_condition; //! The condition variable
+};
+
+//! \brief Posix implementation of Os::ConditionVariable
+//!
+//! Posix implementation of `ConditionVariable` for use as a delegate class handling error-only file operations.
+//!
+class PosixConditionVariable : public ConditionVariableInterface {
+  public:
+    //! \brief constructor
+    //!
+    PosixConditionVariable();
+
+    //! \brief destructor
+    //!
+    ~PosixConditionVariable() override;
+
+    ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
+
+    //! \brief wait releasing mutex
+    void wait(Os::Mutex& mutex) override;
+
+    //! \brief notify a single waiter
+    void notify() override;
+
+    //! \brief notify all current waiters
+    void notifyAll() override;
+
+    //! \brief get handle
+    ConditionVariableHandle* getHandle() override;
+
+  private:
+    //! Handle for PosixMutex
+    PosixConditionVariableHandle m_handle;
+};
+
+}  // namespace Mutex
+}  // namespace Posix
+}  // namespace Os
+#endif  // OS_POSIX_CONDITION_VARIABLE_HPP
diff --git a/Os/Posix/DefaultDirectory.cpp b/Os/Posix/DefaultDirectory.cpp
index abde91735e..5bb1ebdf70 100644
--- a/Os/Posix/DefaultDirectory.cpp
+++ b/Os/Posix/DefaultDirectory.cpp
@@ -7,7 +7,7 @@
 #include "Os/Delegate.hpp"
 
 namespace Os {
-DirectoryInterface* DirectoryInterface::getDelegate(HandleStorage& aligned_new_memory) {
+DirectoryInterface* DirectoryInterface::getDelegate(DirectoryHandleStorage& aligned_new_memory) {
     return Os::Delegate::makeDelegate<DirectoryInterface, Os::Posix::Directory::PosixDirectory>(aligned_new_memory);
 }
 }
diff --git a/Os/Posix/DefaultFileSystem.cpp b/Os/Posix/DefaultFileSystem.cpp
index 6f88c21595..84616cc5e0 100644
--- a/Os/Posix/DefaultFileSystem.cpp
+++ b/Os/Posix/DefaultFileSystem.cpp
@@ -7,7 +7,7 @@
 #include "Os/Delegate.hpp"
 
 namespace Os {
-FileSystemInterface* FileSystemInterface::getDelegate(HandleStorage& aligned_new_memory) {
+FileSystemInterface* FileSystemInterface::getDelegate(FileSystemHandleStorage& aligned_new_memory) {
     return Os::Delegate::makeDelegate<FileSystemInterface, Os::Posix::FileSystem::PosixFileSystem>(aligned_new_memory);
 }
 }
diff --git a/Os/Posix/DefaultMutex.cpp b/Os/Posix/DefaultMutex.cpp
index 0659d9ada5..2bec454540 100644
--- a/Os/Posix/DefaultMutex.cpp
+++ b/Os/Posix/DefaultMutex.cpp
@@ -3,6 +3,7 @@
 // \brief sets default Os::Mutex Posix implementation via linker
 // ======================================================================
 #include "Os/Posix/Mutex.hpp"
+#include "Os/Posix/ConditionVariable.hpp"
 #include "Os/Delegate.hpp"
 namespace Os {
 
@@ -14,4 +15,13 @@ MutexInterface *MutexInterface::getDelegate(HandleStorage& aligned_new_memory) {
             aligned_new_memory
     );
 }
+
+//! \brief get a delegate for MutexInterface that intercepts calls for Posix
+//! \param aligned_new_memory: aligned memory to fill
+//! \return: pointer to delegate
+ConditionVariableInterface *ConditionVariableInterface::getDelegate(ConditionVariableHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<ConditionVariableInterface, Os::Posix::Mutex::PosixConditionVariable, ConditionVariableHandleStorage>(
+        aligned_new_memory
+    );
+}
 }
diff --git a/Os/Posix/IPCQueue.cpp b/Os/Posix/IPCQueue.cpp
deleted file mode 100644
index b5f043e6ed..0000000000
--- a/Os/Posix/IPCQueue.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-#include <Fw/Types/Assert.hpp>
-#include <Os/Queue.hpp>
-#include <Os/IPCQueue.hpp>
-
-#ifdef TGT_OS_TYPE_VXWORKS
-    #include <vxWorks.h>
-#endif
-
-#ifdef TGT_OS_TYPE_LINUX
-    #include <sys/types.h>
-    #include <unistd.h>
-#endif
-
-#include <mqueue.h>
-#include <fcntl.h>
-#include <cerrno>
-#include <cstring>
-#include <cstdio>
-#include <ctime>
-#include <sys/time.h>
-#include <pthread.h>
-#include <new>
-
-#define IPC_QUEUE_TIMEOUT_SEC (1)
-
-namespace Os {
-
-    class QueueHandle {
-        public:
-        QueueHandle(mqd_t m_handle) {
-            this->handle = m_handle;
-        }
-        ~QueueHandle() {
-            // Destroy the handle:
-            if (-1 != this->handle) {
-                (void) mq_close(this->handle);
-            }
-        }
-        mqd_t handle;
-    };
-
-    IPCQueue::IPCQueue() : Queue() {
-    }
-
-    Queue::QueueStatus IPCQueue::create(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize) {
-
-        this->m_name = "/QP_";
-        this->m_name += name;
-#ifndef TGT_OS_TYPE_VXWORKS
-        char pid[40];
-        (void)snprintf(pid,sizeof(pid),".%d",getpid());
-        pid[sizeof(pid)-1] = 0;
-        this->m_name += pid;
-#endif
-        mq_attr att;
-        mqd_t handle;
-
-        memset(&att,0,sizeof(att));
-        att.mq_maxmsg = depth;
-        att.mq_msgsize = msgSize;
-        att.mq_flags = 0;
-        att.mq_curmsgs = 0;
-
-        /* NOTE(mereweth) - O_BLOCK is the default; we use timedsend and
-         * timedreceive below if QUEUE_NONBLOCKING is specified
-         *
-         */
-        handle = mq_open(this->m_name.toChar(), O_RDWR | O_CREAT | O_EXCL, 0666, &att);
-
-        // If queue already exists, then unlink it and try again.
-        if (-1 ==  handle) {
-            switch (errno) {
-                case EEXIST:
-                    (void)mq_unlink(this->m_name.toChar());
-                    break;
-                default:
-                    return QUEUE_UNINITIALIZED;
-            }
-
-            handle = mq_open(this->m_name.toChar(), O_RDWR | O_CREAT | O_EXCL, 0666, &att);
-
-            if (-1 == handle) {
-                return QUEUE_UNINITIALIZED;
-            }
-        }
-
-        // Set up queue handle:
-        QueueHandle* queueHandle = new(std::nothrow) QueueHandle(handle);
-        if (nullptr == queueHandle) {
-          return QUEUE_UNINITIALIZED;
-        }
-        this->m_handle = reinterpret_cast<POINTER_CAST>(queueHandle);
-
-        Queue::s_numQueues++;
-
-        return QUEUE_OK;
-    }
-
-    IPCQueue::~IPCQueue() {
-        // Clean up the queue handle:
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        if (nullptr != queueHandle) {
-          delete queueHandle;
-        }
-        this->m_handle = reinterpret_cast<POINTER_CAST>(nullptr); // important so base Queue class doesn't free it
-        (void) mq_unlink(this->m_name.toChar());
-    }
-
-    Queue::QueueStatus IPCQueue::send(const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority, QueueBlocking block) {
-
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        if (-1 == handle) {
-            return QUEUE_UNINITIALIZED;
-        }
-
-        if (nullptr == buffer) {
-            return QUEUE_EMPTY_BUFFER;
-        }
-
-        bool keepTrying = true;
-        while (keepTrying) {
-            struct timeval now;
-            gettimeofday(&now,nullptr);
-            struct timespec wait;
-            wait.tv_sec = now.tv_sec;
-            wait.tv_nsec = now.tv_usec * 1000;
-
-            if (block == QUEUE_BLOCKING) {
-                wait.tv_sec += IPC_QUEUE_TIMEOUT_SEC;
-            }
-
-            NATIVE_INT_TYPE stat = mq_timedsend(
-                handle,
-                reinterpret_cast<const char*>(buffer),
-                static_cast<size_t>(size),
-                static_cast<unsigned int>(priority),
-                &wait);
-
-            if (-1 == stat) {
-                switch (errno) {
-                    case EINTR:
-                        continue;
-                    case EMSGSIZE:
-                        return QUEUE_SIZE_MISMATCH;
-                    case EINVAL:
-                        return QUEUE_INVALID_PRIORITY;
-                    case ETIMEDOUT:
-                        if (block == QUEUE_NONBLOCKING) {
-                            // no more messages. If we are
-                            // non-blocking, return
-                            return QUEUE_FULL;
-                        } else {
-                            // TODO(mereweth) - multiprocess signalling necessary?
-                            // Go to sleep until we receive a signal that something was taken off the queue
-                            continue;
-                        }
-                    default:
-                        return QUEUE_UNKNOWN_ERROR;
-                }
-            } else {
-                keepTrying=false;
-                // TODO(mereweth) - multiprocess signalling necessary?
-                // Wake up a thread that might be waiting on the other end of the queue:
-            }
-        }
-
-        return QUEUE_OK;
-    }
-
-    Queue::QueueStatus IPCQueue::receive(U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority, QueueBlocking block) {
-
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        if (-1 == handle) {
-            return QUEUE_UNINITIALIZED;
-        }
-
-        ssize_t size;
-        bool notFinished = true;
-        while (notFinished) {
-            struct timeval now;
-            gettimeofday(&now,nullptr);
-            struct timespec wait;
-            wait.tv_sec = now.tv_sec;
-            wait.tv_nsec = now.tv_usec * 1000;
-
-            if (block == QUEUE_BLOCKING) {
-                wait.tv_sec += IPC_QUEUE_TIMEOUT_SEC;
-            }
-            size = mq_timedreceive(handle, reinterpret_cast<char*>(buffer), static_cast<size_t>(capacity),
-#ifdef TGT_OS_TYPE_VXWORKS
-                        reinterpret_cast<int*>(&priority), &wait);
-#else
-                        reinterpret_cast<unsigned int*>(&priority), &wait);
-#endif
-
-            if (-1 == size) { // error
-                switch (errno) {
-                    case EINTR:
-                        continue;
-                    case EMSGSIZE:
-                        return QUEUE_SIZE_MISMATCH;
-                    case ETIMEDOUT:
-                        if (block == QUEUE_NONBLOCKING) {
-                            // no more messages. If we are
-                            // non-blocking, return
-                            return QUEUE_NO_MORE_MSGS;
-                        } else {
-                            // TODO(mereweth) - multiprocess signalling necessary?
-                            // Go to sleep until we receive a signal that something was put on the queue:
-                            continue;
-                        }
-                        break;
-                    default:
-                        return QUEUE_UNKNOWN_ERROR;
-                }
-            }
-            else {
-                notFinished = false;
-                // TODO(mereweth) - multiprocess signalling necessary?
-                // Wake up a thread that might be waiting on the other end of the queue
-            }
-        }
-
-        actualSize = static_cast<NATIVE_INT_TYPE>(size);
-        return QUEUE_OK;
-    }
-
-    NATIVE_INT_TYPE IPCQueue::getNumMsgs() const {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        struct mq_attr attr;
-        int status = mq_getattr(handle, &attr);
-        FW_ASSERT(status == 0);
-        return static_cast<NATIVE_INT_TYPE>(attr.mq_curmsgs);
-    }
-
-    NATIVE_INT_TYPE IPCQueue::getMaxMsgs() const {
-        //FW_ASSERT(0);
-        return 0;
-    }
-
-    NATIVE_INT_TYPE IPCQueue::getQueueSize() const {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        struct mq_attr attr;
-        int status = mq_getattr(handle, &attr);
-        FW_ASSERT(status == 0);
-        return static_cast<NATIVE_INT_TYPE>(attr.mq_maxmsg);
-    }
-
-    NATIVE_INT_TYPE IPCQueue::getMsgSize() const {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        struct mq_attr attr;
-        int status = mq_getattr(handle, &attr);
-        FW_ASSERT(status == 0);
-        return static_cast<NATIVE_INT_TYPE>(attr.mq_msgsize);
-    }
-
-}
diff --git a/Os/Posix/LocklessQueue.cpp b/Os/Posix/LocklessQueue.cpp
deleted file mode 100644
index bb93d90f73..0000000000
--- a/Os/Posix/LocklessQueue.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <Os/LocklessQueue.hpp>
-#include <Fw/Types/Assert.hpp>
-
-#include <fcntl.h>
-#include <cstring>
-#include <new>
-
-#define CAS(a_ptr, a_oldVal, a_newVal) __sync_bool_compare_and_swap(a_ptr, a_oldVal, a_newVal)
-
-namespace Os {
-
-    LocklessQueue::LocklessQueue(const NATIVE_INT_TYPE maxmsg,
-            const NATIVE_INT_TYPE msgsize) {
-#ifndef BUILD_DARWIN
-        m_attr.mq_flags = O_NONBLOCK;
-        m_attr.mq_maxmsg = maxmsg;
-        m_attr.mq_msgsize = msgsize;
-        m_attr.mq_curmsgs = 0;
-#endif
-        // Must have at least 2 messages in the queue
-        FW_ASSERT(maxmsg >= 2, maxmsg);
-
-        m_index = new(std::nothrow) QueueNode[maxmsg]; // Allocate an index entry for each msg
-        m_data = new(std::nothrow) U8[maxmsg * msgsize];  // Allocate data for each msg
-        FW_ASSERT(m_index != nullptr);
-        FW_ASSERT(m_data != nullptr);
-
-        for (int i = 0, j = 1; i < maxmsg; i++, j++) {
-            m_index[i].data = &m_data[i * msgsize]; // Assign the data pointer of index to top that msg's buffer
-
-            if (j < maxmsg) {           // If we aren't processing the last item
-                m_index[i].next = &m_index[j]; // Chain this item to the next one
-            } else {
-                m_index[i].next = nullptr;         // Initialize to NULL otherwise
-            }
-        }
-
-        // Assign each of the pointers to the first index element
-        // This one is held in a "dummy" position for now
-        // It will be cleaned up by the producer
-        m_first = &m_index[0];
-        m_last = &m_index[0];
-        m_last->next = nullptr;
-
-        // Assign the head of the free list to the second element
-        m_free_head = &m_index[1];
-    }
-
-    LocklessQueue::~LocklessQueue() {
-        delete[] m_index;
-        delete[] m_data;
-    }
-
-#ifndef BUILD_DARWIN
-    void LocklessQueue::GetAttr(mq_attr & attr) {
-        memcpy(&attr, &m_attr, sizeof(mq_attr));
-    }
-#endif
-
-    void LocklessQueue::PushFree(QueueNode * my_node) {
-        QueueNode * old_free_head;
-
-        FW_ASSERT(my_node != nullptr);
-
-        // CAS the node into the free list
-        do {
-            old_free_head = m_free_head;
-            my_node->next = old_free_head;
-        } while (!CAS(&m_free_head, old_free_head, my_node));
-    }
-
-    bool LocklessQueue::PopFree(QueueNode ** free_node) {
-        QueueNode * my_node;
-
-        // CAS a buffer from the free list
-        do {
-            my_node = m_free_head;
-
-            if (nullptr == my_node) {
-                return false;
-            }
-
-        } while (!CAS(&m_free_head, my_node, my_node->next));
-
-        (*free_node) = my_node;
-
-        return true;
-    }
-
-    Queue::QueueStatus LocklessQueue::Send(const U8 * buffer,
-            NATIVE_INT_TYPE size) {
-
-        QueueNode * my_node;
-        QueueNode * old_last;
-
-#ifndef BUILD_DARWIN
-        // Check that the new message will fit in our buffers
-        if (size > m_attr.mq_msgsize) {
-            return Queue::QUEUE_SIZE_MISMATCH;
-        }
-#endif
-
-        if (!PopFree(&my_node)) {
-            return Queue::QUEUE_FULL;
-        }
-
-        // Copy the data into the buffer
-        memcpy(my_node->data, buffer, static_cast<size_t>(size));
-        my_node->size = size;
-        my_node->next = nullptr;
-
-        // Publish the node
-        // The m_last pointer is moved before the item is published
-        // All concurrent writers will argue over their order using CAS
-        do {
-            old_last = m_last;
-        } while (!CAS(&m_last, old_last, my_node));
-
-        old_last->next = my_node;
-
-        return Queue::QUEUE_OK;
-    }
-
-    // ONLY ONE RECEIVER AT A TIME!!!!
-    Queue::QueueStatus LocklessQueue::Receive(U8 * buffer,
-            NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE & size) {
-
-        QueueNode * my_node;
-        QueueNode * old_node;
-
-#ifndef BUILD_DARWIN
-        if (capacity < m_attr.mq_msgsize) {
-            return Queue::QUEUE_SIZE_MISMATCH;
-        }
-#endif
-
-        if (m_first == m_last) {
-            return Queue::QUEUE_NO_MORE_MSGS;
-        }
-
-        old_node = m_first;
-        my_node = m_first->next;
-
-        if (my_node == nullptr) {
-            // We may not be fully linked yet, even though "last" has moved
-            return Queue::QUEUE_NO_MORE_MSGS;
-        }
-
-        m_first = m_first->next;
-        PushFree(old_node);
-
-        // Copy the data from the buffer
-        memcpy(buffer, my_node->data, static_cast<size_t>(my_node->size));
-        size = my_node->size;
-
-        return Queue::QUEUE_OK;
-    }
-
-}
diff --git a/Os/Posix/Mutex.cpp b/Os/Posix/Mutex.cpp
index 369d80f042..be77145868 100644
--- a/Os/Posix/Mutex.cpp
+++ b/Os/Posix/Mutex.cpp
@@ -17,7 +17,7 @@ PosixMutex::PosixMutex() : Os::MutexInterface(), m_handle() {
     FW_ASSERT(status == 0, status);
 
     // set to normal mutex type
-    status = pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_NORMAL);
+    status = pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_ERRORCHECK);
     FW_ASSERT(status == 0, status);
 
     // set to check for priority inheritance
diff --git a/Os/Posix/Queue.cpp b/Os/Posix/Queue.cpp
deleted file mode 100644
index 641ce77052..0000000000
--- a/Os/Posix/Queue.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-#include <Fw/Types/Assert.hpp>
-#include <Os/Queue.hpp>
-
-#ifdef TGT_OS_TYPE_VXWORKS
-    #include <vxWorks.h>
-#endif
-
-#ifdef TGT_OS_TYPE_LINUX
-    #include <sys/types.h>
-    #include <unistd.h>
-#endif
-
-#include <mqueue.h>
-#include <fcntl.h>
-#include <cerrno>
-#include <cstring>
-#include <cstdio>
-#include <ctime>
-#include <pthread.h>
-#include <new>
-
-namespace Os {
-
-    class QueueHandle {
-        public:
-        QueueHandle(mqd_t m_handle) {
-            // Initialize the handle:
-            int ret;
-            ret = pthread_cond_init(&this->queueNotEmpty, nullptr);
-            FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-            ret = pthread_cond_init(&this->queueNotFull, nullptr);
-            FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-            ret = pthread_mutex_init(&this->mp, nullptr);
-            FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-            this->handle = m_handle;
-        }
-        ~QueueHandle() {
-            // Destroy the handle:
-            if (-1 != this->handle) {
-                (void) mq_close(this->handle);
-            }
-            (void) pthread_cond_destroy(&this->queueNotEmpty);
-            (void) pthread_mutex_destroy(&this->mp);
-        }
-        mqd_t handle;
-        pthread_cond_t queueNotEmpty;
-        pthread_cond_t queueNotFull;
-        pthread_mutex_t mp;
-    };
-
-    Queue::Queue() :
-        m_handle(-1) {
-    }
-
-    Queue::QueueStatus Queue::createInternal(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize) {
-
-        this->m_name = "/QP_";
-        this->m_name += name;
-#ifndef TGT_OS_TYPE_VXWORKS
-        char pid[40];
-        (void)snprintf(pid,sizeof(pid),".%d",getpid());
-        pid[sizeof(pid)-1] = 0;
-        this->m_name += pid;
-#endif
-        mq_attr att;
-        mqd_t handle;
-
-        memset(&att,0,sizeof(att));
-        att.mq_maxmsg = depth;
-        att.mq_msgsize = msgSize;
-        att.mq_flags = 0;
-        att.mq_curmsgs = 0;
-
-        handle = mq_open(this->m_name.toChar(), O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0666, &att);
-
-        // If queue already exists, then unlink it and try again.
-        if (-1 == handle) {
-        	switch (errno) {
-        	case EEXIST:
-        		(void)mq_unlink(this->m_name.toChar());
-        		break;
-        	default:
-            	return QUEUE_UNINITIALIZED;
-        	}
-
-        	handle = mq_open(this->m_name.toChar(), O_RDWR | O_CREAT | O_EXCL, 0666, &att);
-
-            if (-1 == handle) {
-                return QUEUE_UNINITIALIZED;
-            }
-        }
-
-        // Set up queue handle:
-        QueueHandle* queueHandle = new(std::nothrow) QueueHandle(handle);
-        if (nullptr == queueHandle) {
-          return QUEUE_UNINITIALIZED;
-        }
-        this->m_handle = reinterpret_cast<POINTER_CAST>(queueHandle);
-
-        Queue::s_numQueues++;
-
-        return QUEUE_OK;
-    }
-
-    Queue::~Queue() {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        delete queueHandle;
-        (void) mq_unlink(this->m_name.toChar());
-    }
-
-    Queue::QueueStatus Queue::send(const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority, QueueBlocking block) {
-
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-        pthread_cond_t* queueNotEmpty = &queueHandle->queueNotEmpty;
-        pthread_cond_t* queueNotFull = &queueHandle->queueNotFull;
-        pthread_mutex_t* mp = &queueHandle->mp;
-
-        if (-1 == handle) {
-            return QUEUE_UNINITIALIZED;
-        }
-
-        if (nullptr == buffer) {
-            return QUEUE_EMPTY_BUFFER;
-        }
-
-        bool keepTrying = true;
-        int ret;
-        while (keepTrying) {
-            NATIVE_INT_TYPE stat = mq_send(handle, reinterpret_cast<const char*>(buffer), size, priority);
-            if (-1 == stat) {
-                switch (errno) {
-                    case EINTR:
-                        continue;
-                    case EMSGSIZE:
-                        return QUEUE_SIZE_MISMATCH;
-                    case EINVAL:
-                        return QUEUE_INVALID_PRIORITY;
-                    case EAGAIN:
-                        if (block == QUEUE_NONBLOCKING) {
-                            // no more messages. If we are
-                            // non-blocking, return
-                            return QUEUE_FULL;
-                        } else {
-                            // Go to sleep until we receive a signal that something was taken off the queue:
-                            // Note: pthread_cont_wait must be called "with mutex locked by the calling
-                            // thread or undefined behavior results." - from the docs
-                            ret = pthread_mutex_lock(mp);
-                            FW_ASSERT(ret == 0, errno);
-                            ret = pthread_cond_wait(queueNotFull, mp);
-                            FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-                            ret = pthread_mutex_unlock(mp);
-                            FW_ASSERT(ret == 0, errno);
-                            continue;
-                        }
-                    default:
-                        return QUEUE_UNKNOWN_ERROR;
-                }
-            } else {
-                keepTrying=false;
-                // Wake up a thread that might be waiting on the other end of the queue:
-                ret = pthread_cond_signal(queueNotEmpty);
-                FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-            }
-        }
-
-        return QUEUE_OK;
-    }
-
-    Queue::QueueStatus Queue::receive(U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority, QueueBlocking block) {
-
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-        pthread_cond_t* queueNotEmpty = &queueHandle->queueNotEmpty;
-        pthread_cond_t* queueNotFull = &queueHandle->queueNotFull;
-        pthread_mutex_t* mp = &queueHandle->mp;
-
-        if (-1 == handle) {
-            return QUEUE_UNINITIALIZED;
-        }
-
-        ssize_t size;
-        int ret;
-        bool notFinished = true;
-        while (notFinished) {
-            size = mq_receive(handle, static_cast<char*>(buffer), static_cast<size_t>(capacity),
-#ifdef TGT_OS_TYPE_VXWORKS
-                        reinterpret_cast<int*>(&priority));
-#else
-                        reinterpret_cast<unsigned int*>(&priority));
-#endif
-
-            if (-1 == size) { // error
-                switch (errno) {
-                    case EINTR:
-                        continue;
-                    case EMSGSIZE:
-                        return QUEUE_SIZE_MISMATCH;
-                    case EAGAIN:
-                        if (block == QUEUE_NONBLOCKING) {
-                            // no more messages. If we are
-                            // non-blocking, return
-                            return QUEUE_NO_MORE_MSGS;
-                        } else {
-                            // Go to sleep until we receive a signal that something was put on the queue:
-                            // Note: pthread_cont_wait must be called "with mutex locked by the calling
-                            // thread or undefined behavior results." - from the docs
-                            ret = pthread_mutex_lock(mp);
-                            FW_ASSERT(ret == 0, errno);
-                            ret = pthread_cond_wait(queueNotEmpty, mp);
-                            FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-                            ret = pthread_mutex_unlock(mp);
-                            FW_ASSERT(ret == 0, errno);
-                            continue;
-                        }
-                        break;
-                    default:
-                        return QUEUE_UNKNOWN_ERROR;
-                }
-            }
-            else {
-                notFinished = false;
-                // Wake up a thread that might be waiting on the other end of the queue:
-                ret = pthread_cond_signal(queueNotFull);
-                FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-            }
-        }
-
-        actualSize = static_cast<NATIVE_INT_TYPE>(size);
-        return QUEUE_OK;
-    }
-
-    NATIVE_INT_TYPE Queue::getNumMsgs() const {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        struct mq_attr attr;
-        int status = mq_getattr(handle, &attr);
-        FW_ASSERT(status == 0);
-        return static_cast<U32>(attr.mq_curmsgs);
-    }
-
-    NATIVE_INT_TYPE Queue::getMaxMsgs() const {
-        //FW_ASSERT(0);
-        return 0;
-    }
-
-    NATIVE_INT_TYPE Queue::getQueueSize() const {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        struct mq_attr attr;
-        int status = mq_getattr(handle, &attr);
-        FW_ASSERT(status == 0);
-        return static_cast<U32>(attr.mq_maxmsg);
-    }
-
-    NATIVE_INT_TYPE Queue::getMsgSize() const {
-        QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-        mqd_t handle = queueHandle->handle;
-
-        struct mq_attr attr;
-        int status = mq_getattr(handle, &attr);
-        FW_ASSERT(status == 0);
-        return static_cast<U32>(attr.mq_msgsize);
-    }
-
-}
-
diff --git a/Os/Pthreads/BufferQueue.hpp b/Os/Pthreads/BufferQueue.hpp
deleted file mode 100644
index e27b8fe941..0000000000
--- a/Os/Pthreads/BufferQueue.hpp
+++ /dev/null
@@ -1,132 +0,0 @@
-// ======================================================================
-// \title  BufferQueue.hpp
-// \author dinkel
-// \brief  A generic buffer queue data structure.
-//
-// \copyright
-// Copyright 2009-2015, by the California Institute of Technology.
-// ALL RIGHTS RESERVED.  United States Government Sponsorship
-// acknowledged.
-//
-// ======================================================================
-
-#ifndef OS_PTHREADS_BUFFER_QUEUE_HPP
-#define OS_PTHREADS_BUFFER_QUEUE_HPP
-
-#include <FpConfig.hpp>
-
-// This is a generic buffer queue interface. 
-namespace Os {
-
-  //! \class BufferQueue
-  //! \brief A generic buffer queue data structure
-  //!
-  //! This is a generic queue interface that can be implemented using a variety
-  //! of different data structures
-  class BufferQueue {
-    // Public interface:
-    public:
-    //! \brief BufferQueue constructor
-    //!
-    //! Create a BufferQueue object.
-    //!
-    BufferQueue();
-    //! \brief BufferQueue deconstructor
-    //!
-    //! Deallocate the queue.
-    //!
-    ~BufferQueue();
-    //! \brief BufferQueue creation
-    //!
-    //! Create a queue with buffer allocated at initialization. Messages 
-    //! will have a maximum size "msgSize" and the buffer with be "depth"
-    //! elements deep.
-    //!
-    //! \param depth the maximum number of buffers to store on queue
-    //! \param msgSize the maximum size of a buffer that can be stored on
-    //! the queue
-    //!
-    bool create(NATIVE_UINT_TYPE depth, NATIVE_UINT_TYPE msgSize);
-    //! \brief push an item onto the queue
-    //!
-    //! Push an item onto the queue with the specified size and priority
-    //!
-    //! \param buffer the buffer to push onto the queue
-    //! \param size the size of buffer
-    //! \param priority the priority of the buffer on the queue (higher 
-    //! priority means that the buffer will be popped off sooner.
-    //!
-    bool push(const U8* buffer, NATIVE_UINT_TYPE size, NATIVE_INT_TYPE priority);
-    //! \brief pop an item off the queue
-    //!
-    //! Pull an item off of the queue and put it in "buffer" which is of size
-    //! "size". Returns the size of the pulled item in "size" and the priority
-    //! of the pulled item in "priority" on a success.
-    //!
-    //! \param buffer the buffer to fill from the queue
-    //! \param size the size of buffer. The size of the popped buffer
-    //! will also be returned in this variable. It is used as both input
-    //! and output
-    //! \param priority the priority of the buffer popped off the queue
-    //!
-    bool pop(U8* buffer, NATIVE_UINT_TYPE& size, NATIVE_INT_TYPE &priority);
-    //! \brief check if the queue is full
-    //!
-    //! Is the queue full?
-    //!
-    bool isFull();
-    //! \brief check if the queue is empty
-    //!
-    //! Is the queue empty?
-    //!
-    bool isEmpty();
-    //! \brief Get the current number of items on the queue
-    //!
-    //! Get the number of items on the queue.
-    //!
-    NATIVE_UINT_TYPE getCount();
-    //! \brief Get the maximum number of items seen on the queue
-    //!
-    //! Get the maximum number of items that have been on the queue since the
-    //! instantiation of the queue. This is a "high water mark" count.
-    //!
-    NATIVE_UINT_TYPE getMaxCount();
-    //! \brief Get the maximum message size
-    //!
-    //! Get the maximum message size allowed on the queue
-    //!
-    NATIVE_UINT_TYPE getMsgSize();
-    //! \brief Get the queue depths
-    //!
-    //! Get the maximum number of messages allowed on the queue
-    //!
-    NATIVE_UINT_TYPE getDepth();
-
-    // Internal member functions:
-    private:
-    // Initialize data structures necessary for the queue:
-    bool initialize(NATIVE_UINT_TYPE depth, NATIVE_UINT_TYPE msgSize);
-    // Destroy queue data structures:
-    void finalize();
-    // Enqueue a message into the data structure:
-    bool enqueue(const U8* buffer, NATIVE_UINT_TYPE size, NATIVE_INT_TYPE priority);
-    // Dequeue a message from the data structure:
-    bool dequeue(U8* buffer, NATIVE_UINT_TYPE& size, NATIVE_INT_TYPE &priority);
-    // Low level enqueue which does the copying onto the queue:
-    void enqueueBuffer(const U8* buffer, NATIVE_UINT_TYPE size, U8* data, NATIVE_UINT_TYPE index);
-    // Low level dequeue which does the copying from the queue:
-    bool dequeueBuffer(U8* buffer, NATIVE_UINT_TYPE& size, U8* data, NATIVE_UINT_TYPE index);
-    // Helper function to get the buffer index into the queue for particular
-    // queue index.
-    NATIVE_UINT_TYPE getBufferIndex(NATIVE_INT_TYPE index);
-
-    // Member variables:
-    void* m_queue; // The queue can be implemented in various ways
-    NATIVE_UINT_TYPE m_msgSize; // Max size of message on the queue
-    NATIVE_UINT_TYPE m_depth; // Max number of messages on the queue
-    NATIVE_UINT_TYPE m_count; // Current number of messages on the queue
-    NATIVE_UINT_TYPE m_maxCount; // Maximum number of messages ever seen on the queue
-  };
-}
-
-#endif // OS_PTHREADS_BUFFER_QUEUE_HPP
diff --git a/Os/Pthreads/BufferQueueCommon.cpp b/Os/Pthreads/BufferQueueCommon.cpp
deleted file mode 100644
index 74fad09fc5..0000000000
--- a/Os/Pthreads/BufferQueueCommon.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-// ======================================================================
-// \title  BufferQueueCommon.hpp
-// \author dinkel
-// \brief  This file implements some of the methods for the generic
-//         buffer queue data structure declared in BufferQueue.hpp that
-//         are common amongst different queue implementations.
-//
-// \copyright
-// Copyright 2009-2015, by the California Institute of Technology.
-// ALL RIGHTS RESERVED.  United States Government Sponsorship
-// acknowledged.
-//
-// ======================================================================
-
-#include "Os/Pthreads/BufferQueue.hpp"
-#include <Fw/Types/Assert.hpp>
-#include <cstring>
-
-namespace Os {
-
-  /////////////////////////////////////////////////////
-  // Class functions:
-  /////////////////////////////////////////////////////
-
-  BufferQueue::BufferQueue() {
-    // Set member variables:
-    this->m_queue = nullptr;
-    this->m_msgSize = 0;
-    this->m_depth = 0;
-    this->m_count = 0;
-    this->m_maxCount = 0;
-  }
-
-  BufferQueue::~BufferQueue() {
-    this->finalize();
-  }
-
-  bool BufferQueue::create(NATIVE_UINT_TYPE depth, NATIVE_UINT_TYPE msgSize) {
-    // Queue is already set up. destroy it and try again:
-    if (nullptr != this->m_queue) {
-      this->finalize();
-    }
-    FW_ASSERT(nullptr == this->m_queue, static_cast<FwAssertArgType>(reinterpret_cast<POINTER_CAST>(this->m_queue)));
-
-    // Set member variables:
-    this->m_msgSize = msgSize;
-    this->m_depth = depth;
-    return this->initialize(depth, msgSize);
-  }
-
-  bool BufferQueue::push(const U8* buffer, NATIVE_UINT_TYPE size, NATIVE_INT_TYPE priority) {
-
-    FW_ASSERT(size <= this->m_msgSize);
-    if( this->isFull() ) {
-      return false;
-    }
-
-    // Enqueue the data:
-    bool ret = enqueue(buffer, size, priority);
-    if( !ret ) {
-      return false;
-    }
-
-    // Increment count:
-    ++this->m_count;
-    if( this->m_count > this->m_maxCount ) {
-      this->m_maxCount = this->m_count;
-    }
-    return true;
-  }
-
-  bool BufferQueue::pop(U8* buffer, NATIVE_UINT_TYPE& size, NATIVE_INT_TYPE &priority) {
-
-    if( this->isEmpty() ) {
-      size = 0;
-      return false;
-    }
-
-    // Dequeue the data:
-    bool ret = dequeue(buffer, size, priority);
-    if( !ret ) {
-      return false;
-    }
-
-    // Decrement count:
-    --this->m_count;
-
-    return true;
-  }
-
-  bool BufferQueue::isFull() {
-    return (this->m_count == this->m_depth);
-  }
-
-  bool BufferQueue::isEmpty() {
-    return (this->m_count == 0);
-  }
-
-  NATIVE_UINT_TYPE BufferQueue::getCount() {
-    return this->m_count;
-  }
-
-  NATIVE_UINT_TYPE BufferQueue::getMaxCount() {
-    return this->m_maxCount;
-  }
-
-
-  NATIVE_UINT_TYPE BufferQueue::getMsgSize() {
-    return this->m_msgSize;
-  }
-
-  NATIVE_UINT_TYPE BufferQueue::getDepth() {
-    return this->m_depth;
-  }
-
-  NATIVE_UINT_TYPE BufferQueue::getBufferIndex(NATIVE_INT_TYPE index) {
-    return static_cast<NATIVE_UINT_TYPE>((static_cast<NATIVE_UINT_TYPE>(index) % this->m_depth) * (sizeof(NATIVE_INT_TYPE) + this->m_msgSize));
-  }
-
-  void BufferQueue::enqueueBuffer(const U8* buffer, NATIVE_UINT_TYPE size, U8* data, NATIVE_UINT_TYPE index) {
-    // Copy size of buffer onto queue:
-    void* dest = &data[index];
-    void* ptr = memcpy(dest, &size, sizeof(size));
-    FW_ASSERT(ptr == dest);
-
-    // Copy buffer onto queue:
-    index += static_cast<NATIVE_UINT_TYPE>(sizeof(size));
-    dest = &data[index];
-    ptr = memcpy(dest, buffer, size);
-    FW_ASSERT(ptr == dest);
-  }
-
-  bool BufferQueue::dequeueBuffer(U8* buffer, NATIVE_UINT_TYPE& size, U8* data, NATIVE_UINT_TYPE index) {
-    // Copy size of buffer from queue:
-    NATIVE_UINT_TYPE storedSize;
-    void* source = &data[index];
-    void* ptr = memcpy(&storedSize, source, sizeof(size));
-    FW_ASSERT(ptr == &storedSize);
-
-    // If the buffer passed in is not big
-    // enough, return false, and pass out
-    // the size of the message:
-    if(storedSize > size){
-      size = storedSize;
-      return false;
-    }
-    size = storedSize;
-
-    // Copy buffer from queue:
-    index += static_cast<NATIVE_UINT_TYPE>(sizeof(size));
-    source = &data[index];
-    ptr = memcpy(buffer, source, storedSize);
-    FW_ASSERT(ptr == buffer);
-    return true;
-  }
-}
diff --git a/Os/Pthreads/FIFOBufferQueue.cpp b/Os/Pthreads/FIFOBufferQueue.cpp
deleted file mode 100644
index d18dc05fe4..0000000000
--- a/Os/Pthreads/FIFOBufferQueue.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-// ======================================================================
-// \title  FIFOBufferQueue.hpp
-// \author dinkel
-// \brief  An implementation of BufferQueue which uses a FIFO data
-//         structure for the queue. Priority is ignored.
-//
-// \copyright
-// Copyright 2009-2015, by the California Institute of Technology.
-// ALL RIGHTS RESERVED.  United States Government Sponsorship
-// acknowledged.
-//
-// ======================================================================
-
-#include "Os/Pthreads/BufferQueue.hpp"
-#include <Fw/Types/Assert.hpp>
-
-#include <cstring>
-#include <new>
-
-// This is a simple FIFO queue implementation which ignores priority
-namespace Os {
-
-  /////////////////////////////////////////////////////
-  // Queue handler:
-  /////////////////////////////////////////////////////
-
-  struct FIFOQueue {
-    U8* data;
-    NATIVE_UINT_TYPE head;
-    NATIVE_UINT_TYPE tail;
-  };
-
-  /////////////////////////////////////////////////////
-  // Class functions:
-  /////////////////////////////////////////////////////
-
-  bool BufferQueue::initialize(NATIVE_UINT_TYPE depth, NATIVE_UINT_TYPE msgSize) {
-    U8* data = new(std::nothrow) U8[depth*(sizeof(msgSize) + msgSize)];
-    if (nullptr == data) {
-      return false;
-    }
-    FIFOQueue* fifoQueue = new(std::nothrow) FIFOQueue;
-    if (nullptr == fifoQueue) {
-      return false;
-    }
-    fifoQueue->data = data;
-    fifoQueue->head = 0;
-    fifoQueue->tail = 0;
-    this->m_queue = fifoQueue;
-    return true;
-  }
-
-  void BufferQueue::finalize() {
-    FIFOQueue* fQueue = static_cast<FIFOQueue*>(this->m_queue);
-    if (nullptr != fQueue)
-    {
-      U8* data = fQueue->data;
-      if (nullptr != data) {
-        delete [] data;
-      }
-      delete fQueue;
-    }
-    this->m_queue = nullptr;
-  }
-
-  bool BufferQueue::enqueue(const U8* buffer, NATIVE_UINT_TYPE size, NATIVE_INT_TYPE priority) {
-    (void) priority;
-
-    FIFOQueue* fQueue = static_cast<FIFOQueue*>(this->m_queue);
-    U8* data = fQueue->data;
-
-    // Store the buffer to the queue:
-    NATIVE_UINT_TYPE index = getBufferIndex(fQueue->tail);
-    this->enqueueBuffer(buffer, size, data, index);
-
-    // Increment tail of fifo:
-    ++fQueue->tail;
-    return true;
-  }
-
-  bool BufferQueue::dequeue(U8* buffer, NATIVE_UINT_TYPE& size, NATIVE_INT_TYPE &priority) {
-    (void) priority;
-
-    FIFOQueue* fQueue = static_cast<FIFOQueue*>(this->m_queue);
-    U8* data = fQueue->data;
-
-    // Get the buffer from the queue:
-    NATIVE_UINT_TYPE index = getBufferIndex(fQueue->head);
-    bool ret = this->dequeueBuffer(buffer, size, data, index);
-    if(!ret) {
-      return false;
-    }
-
-    // Increment head of fifo:
-    ++fQueue->head;
-    return true;
-  }
-}
diff --git a/Os/Pthreads/MaxHeap/MaxHeap.cpp b/Os/Pthreads/MaxHeap/MaxHeap.cpp
deleted file mode 100644
index 42e1c0c502..0000000000
--- a/Os/Pthreads/MaxHeap/MaxHeap.cpp
+++ /dev/null
@@ -1,290 +0,0 @@
-// ======================================================================
-// \title  MaxHeap.cpp
-// \author dinkel
-// \brief  An implementation of a stable max heap data structure. Items
-//         popped off the heap are guaranteed to be in order of decreasing
-//         "value" (max removed first). Items of equal "value" will be
-//         popped off in FIFO order. The performance of both push and pop
-//         is O(log(n)).
-//
-// \copyright
-// Copyright 2009-2015, by the California Institute of Technology.
-// ALL RIGHTS RESERVED.  United States Government Sponsorship
-// acknowledged.
-//
-// ======================================================================
-
-#include "Os/Pthreads/MaxHeap/MaxHeap.hpp"
-#include <FpConfig.hpp>
-#include "Fw/Types/Assert.hpp"
-#include <Fw/Logger/Logger.hpp>
-
-#include <new>
-#include <cstdio>
-
-// Macros for traversing the heap:
-#define LCHILD(x) (2 * x + 1)
-#define RCHILD(x) (2 * x + 2)
-#define PARENT(x) ((x - 1) / 2)
-
-namespace Os {
-
-    MaxHeap::MaxHeap() {
-      // Initialize the heap:
-      this->m_capacity = 0;
-      this->m_heap = nullptr;
-      this->m_size = 0;
-      this->m_order = 0;
-    }
-
-    MaxHeap::~MaxHeap() {
-      delete [] this->m_heap;
-      this->m_heap = nullptr;
-    }
-
-    bool MaxHeap::create(NATIVE_UINT_TYPE capacity)
-    {
-      // The heap has already been created.. so delete
-      // it and try again.
-      if( nullptr != this->m_heap ) {
-        delete [] this->m_heap;
-        this->m_heap = nullptr;
-      }
-
-      this->m_heap = new(std::nothrow) Node[capacity];
-      if( nullptr == this->m_heap ) {
-        return false;
-      }
-      this->m_capacity = capacity;
-      return true;
-    }
-
-    bool MaxHeap::push(NATIVE_INT_TYPE value, NATIVE_UINT_TYPE id) {
-      // If the queue is full, return false:
-      if(this->isFull()) {
-        return false;
-      }
-
-      // Heap indexes:
-      NATIVE_UINT_TYPE parent;
-      NATIVE_UINT_TYPE index = this->m_size;
-
-      // Max loop bounds for bit flip protection:
-      NATIVE_UINT_TYPE maxIter = this->m_size+1;
-      NATIVE_UINT_TYPE maxCount = 0;
-
-      // Start at the bottom of the heap and work our ways
-      // upwards until we find a parent that has a value
-      // greater than ours.
-      while(index && maxCount < maxIter) {
-        // Get the parent index:
-        parent = PARENT(index);
-        // The parent index should ALWAYS be less than the
-        // current index. Let's verify that.
-        FW_ASSERT(parent < index, static_cast<FwAssertArgType>(parent), static_cast<FwAssertArgType>(index));
-        // If the current value is less than the parent,
-        // then the current index is in the correct place,
-        // so break out of the loop:
-        if(value <= this->m_heap[parent].value) {
-          break;
-        }
-        // Swap the parent and child:
-        this->m_heap[index] = this->m_heap[parent];
-        index = parent;
-        ++maxCount;
-      }
-
-      // Check for programming errors or bit flips:
-      FW_ASSERT(maxCount < maxIter, static_cast<FwAssertArgType>(maxCount), static_cast<FwAssertArgType>(maxIter));
-      FW_ASSERT(index <= this->m_size, static_cast<FwAssertArgType>(index));
-
-      // Set the values of the new element:
-      this->m_heap[index].value = value;
-      this->m_heap[index].order = m_order;
-      this->m_heap[index].id = id;
-
-      ++this->m_size;
-      ++this->m_order;
-      return true;
-    }
-
-    bool MaxHeap::pop(NATIVE_INT_TYPE& value, NATIVE_UINT_TYPE& id) {
-      // If there is nothing in the heap then
-      // return false:
-      if(this->isEmpty()) {
-        return false;
-      }
-
-      // Set the return values to the top (max) of
-      // the heap:
-      value = this->m_heap[0].value;
-      id = this->m_heap[0].id;
-
-      // Now place the last element on the heap in
-      // the root position, and resize the heap.
-      // This will put the smallest value in the
-      // heap on the top, violating the heap property.
-      NATIVE_UINT_TYPE index = this->m_size-1;
-      // Fw::Logger::log("Putting on top: i: %u v: %d\n", index, this->m_heap[index].value);
-      this->m_heap[0]= this->m_heap[index];
-      --this->m_size;
-
-      // Now that the heap property is violated, we
-      // need to reorganize the heap to restore it's
-      // heapy-ness.
-      this->heapify();
-      return true;
-    }
-
-    // Is the heap full:
-    bool MaxHeap::isFull() {
-      return (this->m_size == this->m_capacity);
-    }
-
-    // Is the heap empty:
-    bool MaxHeap::isEmpty() {
-      return (this->m_size == 0);
-    }
-
-    // Get the current size of the heap:
-    NATIVE_UINT_TYPE MaxHeap::getSize() {
-      return this->m_size;
-    }
-
-    // A non-recursive heapify method.
-    // Note: This method had an additional property, such that
-    // items pushed of the same priority will be popped in FIFO
-    // order.
-    void MaxHeap::heapify() {
-      NATIVE_UINT_TYPE index = 0;
-      NATIVE_UINT_TYPE left;
-      NATIVE_UINT_TYPE right;
-      NATIVE_UINT_TYPE largest;
-
-      // Max loop bounds for bit flip protection:
-      NATIVE_UINT_TYPE maxIter = this->m_size+1;
-      NATIVE_UINT_TYPE maxCount = 0;
-
-      while(index <= this->m_size && maxCount < maxIter) {
-        // Get the children indexes for this node:
-        left = LCHILD(index);
-        right = RCHILD(index);
-        FW_ASSERT(left > index, static_cast<FwAssertArgType>(left), static_cast<FwAssertArgType>(index));
-        FW_ASSERT(right > left, static_cast<FwAssertArgType>(right), static_cast<FwAssertArgType>(left));
-
-        // If the left node is bigger than the heap
-        // size, we have reached the end of the heap
-        // so we can stop:
-        if (left >= this->m_size) {
-          break;
-        }
-
-        // Initialize the largest node to the current
-        // node:
-        largest = index;
-
-        // Which one is larger, the current node or
-        // the left node?:
-        largest = this->max(left, largest);
-
-        // Make sure the right node exists before checking it:
-        if (right < this->m_size) {
-          // Which one is larger, the current largest
-          // node or the right node?
-          largest = this->max(right, largest);
-        }
-
-        // If the largest node is the current node
-        // then we are done heapifying:
-        if (largest == index)
-        {
-          break;
-        }
-
-        // Swap the largest node with the current node:
-        // Fw::Logger::log("Swapping: i: %u v: %d with i: %u v: %d\n",
-        //   index, this->m_heap[index].value,
-        //   largest, this->m_heap[largest].value);
-        this->swap(index, largest);
-
-        // Set the new index to whichever child was larger:
-        index = largest;
-      }
-
-      // Check for programming errors or bit flips:
-      FW_ASSERT(maxCount < maxIter, static_cast<FwAssertArgType>(maxCount), static_cast<FwAssertArgType>(maxIter));
-      FW_ASSERT(index <= this->m_size, static_cast<FwAssertArgType>(index));
-    }
-
-    // Return the maximum priority index between two nodes. If their
-    // priorities are equal, return the oldest to keep the heap stable
-    NATIVE_UINT_TYPE MaxHeap::max(NATIVE_UINT_TYPE a, NATIVE_UINT_TYPE b) {
-      FW_ASSERT(a < this->m_size, static_cast<FwAssertArgType>(a), static_cast<FwAssertArgType>(this->m_size));
-      FW_ASSERT(b < this->m_size, static_cast<FwAssertArgType>(b), static_cast<FwAssertArgType>(this->m_size));
-
-      // Extract the priorities:
-      NATIVE_INT_TYPE aValue = this->m_heap[a].value;
-      NATIVE_INT_TYPE bValue = this->m_heap[b].value;
-
-      // If the priorities are equal, the "larger" one will be
-      // the "older" one as determined by order pushed on to the
-      // heap. Using this secondary ordering technique makes the
-      // heap stable (ie. FIFO for equal priority elements).
-      // Note: We check this first, because it is the most common
-      // case. Let's save as many ticks as we can...
-      if(aValue == bValue) {
-        NATIVE_UINT_TYPE aAge = this->m_order - this->m_heap[a].order;
-        NATIVE_UINT_TYPE bAge = this->m_order - this->m_heap[b].order;
-        if(aAge > bAge) {
-          return a;
-        }
-        return b;
-      }
-
-      // Which priority is larger?:
-      if( aValue > bValue ) {
-        return a;
-      }
-      // B is larger:
-      return b;
-    }
-
-    // Swap two nodes in the heap:
-    void MaxHeap::swap(NATIVE_UINT_TYPE a, NATIVE_UINT_TYPE b) {
-      FW_ASSERT(a < this->m_size, static_cast<FwAssertArgType>(a), static_cast<FwAssertArgType>(this->m_size));
-      FW_ASSERT(b < this->m_size, static_cast<FwAssertArgType>(b), static_cast<FwAssertArgType>(this->m_size));
-      Node temp = this->m_heap[a];
-      this->m_heap[a] = this->m_heap[b];
-      this->m_heap[b] = temp;
-    }
-
-    // Print heap, for debugging purposes only:
-    void MaxHeap::print() {
-      NATIVE_UINT_TYPE index = 0;
-      NATIVE_UINT_TYPE left;
-      NATIVE_UINT_TYPE right;
-      Fw::Logger::log("Printing Heap of Size: %d\n", this->m_size);
-      while(index < this->m_size) {
-        left = LCHILD(index);
-        right = RCHILD(index);
-
-        if( left >= m_size && index == 0) {
-          Fw::Logger::log("i: %u v: %d d: %u -> (NULL, NULL)\n",
-            index, this->m_heap[index].value, this->m_heap[index].id);
-        }
-        else if( right >= m_size && left < m_size ) {
-          Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, NULL)\n",
-            index, this->m_heap[index].value, this->m_heap[index].id,
-            left, this->m_heap[left].value, this->m_heap[left].id);
-        }
-        else if( right < m_size && left < m_size ) {
-          Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, i: %u v: %d d: %u)\n",
-            index, this->m_heap[index].value, this->m_heap[index].id,
-            left, this->m_heap[left].value,this->m_heap[left].id,
-            right, this->m_heap[right].value, this->m_heap[right].id);
-        }
-
-        ++index;
-      }
-    }
-}
diff --git a/Os/Pthreads/PriorityBufferQueue.cpp b/Os/Pthreads/PriorityBufferQueue.cpp
deleted file mode 100644
index 2eb70ba8ee..0000000000
--- a/Os/Pthreads/PriorityBufferQueue.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-// ======================================================================
-// \title  PriorityBufferQueue.hpp
-// \author dinkel
-// \brief  An implementation of BufferQueue which uses a stable max heap
-//         data structure for the queue. Items of highest priority will
-//         be popped off of the queue first. Items of equal priority will
-//         be popped off the queue in FIFO order.
-//
-// \copyright
-// Copyright 2009-2015, by the California Institute of Technology.
-// ALL RIGHTS RESERVED.  United States Government Sponsorship
-// acknowledged.
-//
-// ======================================================================
-
-#include "Os/Pthreads/BufferQueue.hpp"
-#include "Os/Pthreads/MaxHeap/MaxHeap.hpp"
-#include <Fw/Types/Assert.hpp>
-#include <cstring>
-#include <cstdio>
-#include <new>
-
-// This is a priority queue implementation implemented using a stable max heap.
-// Elements pushed onto the queue will be popped off in priority order.
-// Elements of the same priority will be popped off in FIFO order.
-namespace Os {
-
-  /////////////////////////////////////////////////////
-  // Queue handler:
-  /////////////////////////////////////////////////////
-
-  struct PriorityQueue {
-    MaxHeap* heap;
-    U8* data;
-    NATIVE_UINT_TYPE* indexes;
-    NATIVE_UINT_TYPE startIndex;
-    NATIVE_UINT_TYPE stopIndex;
-  };
-
-  /////////////////////////////////////////////////////
-  // Helper functions:
-  /////////////////////////////////////////////////////
-
-  NATIVE_UINT_TYPE checkoutIndex(PriorityQueue* pQueue, NATIVE_UINT_TYPE depth) {
-    NATIVE_UINT_TYPE* indexes = pQueue->indexes;
-
-    // Get an available index from the index pool:
-    NATIVE_UINT_TYPE index = indexes[pQueue->startIndex % depth];
-    ++pQueue->startIndex;
-    NATIVE_UINT_TYPE diff = pQueue->stopIndex - pQueue->startIndex;
-    FW_ASSERT(
-      diff <= depth,
-      static_cast<FwAssertArgType>(diff),
-      static_cast<FwAssertArgType>(depth),
-      static_cast<FwAssertArgType>(pQueue->stopIndex),
-      static_cast<FwAssertArgType>(pQueue->startIndex));
-    return index;
-  }
-
-  void returnIndex(PriorityQueue* pQueue, NATIVE_UINT_TYPE depth, NATIVE_UINT_TYPE index) {
-    NATIVE_UINT_TYPE* indexes = pQueue->indexes;
-
-    // Return the index back to the index pool:
-    indexes[pQueue->stopIndex % depth] = index;
-    ++pQueue->stopIndex;
-    NATIVE_UINT_TYPE diff = pQueue->stopIndex - pQueue->startIndex;
-    FW_ASSERT(
-      diff <= depth,
-      static_cast<FwAssertArgType>(diff),
-      static_cast<FwAssertArgType>(depth),
-      static_cast<FwAssertArgType>(pQueue->stopIndex),
-      static_cast<FwAssertArgType>(pQueue->startIndex));
-  }
-
-  /////////////////////////////////////////////////////
-  // Class functions:
-  /////////////////////////////////////////////////////
-
-  bool BufferQueue::initialize(NATIVE_UINT_TYPE depth, NATIVE_UINT_TYPE msgSize) {
-    // Create the priority queue data structure on the heap:
-    MaxHeap* heap = new(std::nothrow) MaxHeap;
-    if (nullptr == heap) {
-      return false;
-    }
-    if( !heap->create(depth) ) {
-      delete heap;
-      return false;
-    }
-    U8* data = new(std::nothrow) U8[depth*(sizeof(msgSize) + msgSize)];
-    if (nullptr == data) {
-      delete heap;
-      return false;
-    }
-    NATIVE_UINT_TYPE* indexes = new(std::nothrow) NATIVE_UINT_TYPE[depth];
-    if (nullptr == indexes) {
-      delete heap;
-      delete[] data;
-      return false;
-    }
-    for(NATIVE_UINT_TYPE ii = 0; ii < depth; ++ii) {
-        indexes[ii] = getBufferIndex(static_cast<NATIVE_INT_TYPE>(ii));
-    }
-    PriorityQueue* priorityQueue = new(std::nothrow) PriorityQueue;
-    if (nullptr == priorityQueue) {
-      delete heap;
-      delete[] data;
-      delete[] indexes;
-      return false;
-    }
-    priorityQueue->heap = heap;
-    priorityQueue->data = data;
-    priorityQueue->indexes = indexes;
-    priorityQueue->startIndex = 0;
-    priorityQueue->stopIndex = depth;
-    this->m_queue = priorityQueue;
-    return true;
-  }
-
-  void BufferQueue::finalize() {
-    PriorityQueue* pQueue = static_cast<PriorityQueue*>(this->m_queue);
-    if (nullptr != pQueue)
-    {
-      MaxHeap* heap = pQueue->heap;
-      if (nullptr != heap) {
-        delete heap;
-      }
-      U8* data = pQueue->data;
-      if (nullptr != data) {
-        delete [] data;
-      }
-      NATIVE_UINT_TYPE* indexes = pQueue->indexes;
-      if (nullptr != indexes)
-      {
-        delete [] indexes;
-      }
-      delete pQueue;
-    }
-    this->m_queue = nullptr;
-  }
-
-  bool BufferQueue::enqueue(const U8* buffer, NATIVE_UINT_TYPE size, NATIVE_INT_TYPE priority) {
-
-    // Extract queue handle variables:
-    PriorityQueue* pQueue = static_cast<PriorityQueue*>(this->m_queue);
-    MaxHeap* heap = pQueue->heap;
-    U8* data = pQueue->data;
-
-    // Get an available data index:
-    NATIVE_UINT_TYPE index = checkoutIndex(pQueue, this->m_depth);
-
-    // Insert the data into the heap:
-    bool ret = heap->push(priority, index);
-    FW_ASSERT(ret, ret);
-
-    // Store the buffer to the queue:
-    this->enqueueBuffer(buffer, size, data, index);
-
-    return true;
-  }
-
-  bool BufferQueue::dequeue(U8* buffer, NATIVE_UINT_TYPE& size, NATIVE_INT_TYPE &priority) {
-
-    // Extract queue handle variables:
-    PriorityQueue* pQueue = static_cast<PriorityQueue*>(this->m_queue);
-    MaxHeap* heap = pQueue->heap;
-    U8* data = pQueue->data;
-
-    // Get the highest priority data from the heap:
-    NATIVE_UINT_TYPE index = 0;
-    bool ret = heap->pop(priority, index);
-    FW_ASSERT(ret, ret);
-
-    ret = this->dequeueBuffer(buffer, size, data, index);
-    if(!ret) {
-      // The dequeue failed, so push the popped
-      // value back on the heap.
-      ret = heap->push(priority, index);
-      FW_ASSERT(ret, ret);
-      return false;
-    }
-
-    // Return the index to the available indexes:
-    returnIndex(pQueue, this->m_depth, index);
-
-    return true;
-  }
-}
diff --git a/Os/Pthreads/Queue.cpp b/Os/Pthreads/Queue.cpp
deleted file mode 100644
index 0a46fda2d9..0000000000
--- a/Os/Pthreads/Queue.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-// ======================================================================
-// \title  Queue.cpp
-// \author dinkel
-// \brief  Queue implementation using the pthread library. This is NOT
-//         an IPC queue. It is meant to be used between threads within
-//         the same address space.
-//
-// \copyright
-// Copyright 2009-2015, by the California Institute of Technology.
-// ALL RIGHTS RESERVED.  United States Government Sponsorship
-// acknowledged.
-//
-// ======================================================================
-
-#include <Os/Pthreads/BufferQueue.hpp>
-#include <Fw/Types/Assert.hpp>
-#include <Os/Queue.hpp>
-
-#include <cerrno>
-#include <pthread.h>
-#include <cstdio>
-#include <new>
-
-namespace Os {
-
-  // A helper class which stores variables for the queue handle.
-  // The queue itself, a pthread condition variable, and pthread
-  // mutex are contained within this container class.
-  class QueueHandle {
-    public:
-    QueueHandle() {
-      int ret;
-      ret = pthread_cond_init(&this->queueNotEmpty, nullptr);
-      FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-      ret = pthread_cond_init(&this->queueNotFull, nullptr);
-      FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-      ret = pthread_mutex_init(&this->queueLock, nullptr);
-      FW_ASSERT(ret == 0, ret); // If this fails, something horrible happened.
-    }
-    ~QueueHandle() {
-      (void) pthread_cond_destroy(&this->queueNotEmpty);
-      (void) pthread_cond_destroy(&this->queueNotFull);
-      (void) pthread_mutex_destroy(&this->queueLock);
-    }
-    bool create(NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize) {
-      return queue.create(static_cast<NATIVE_UINT_TYPE>(depth), static_cast<NATIVE_UINT_TYPE>(msgSize));
-    }
-    BufferQueue queue;
-    pthread_cond_t queueNotEmpty;
-    pthread_cond_t queueNotFull;
-    pthread_mutex_t queueLock;
-  };
-
-  Queue::Queue() :
-    m_handle(reinterpret_cast<POINTER_CAST>(nullptr)) {
-  }
-
-  Queue::QueueStatus Queue::createInternal(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize) {
-    QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-
-    // Queue has already been created... remove it and try again:
-    if (nullptr != queueHandle) {
-        delete queueHandle;
-        queueHandle = nullptr;
-    }
-
-    // Create queue handle:
-    queueHandle = new(std::nothrow) QueueHandle;
-    if (nullptr == queueHandle) {
-      return QUEUE_UNINITIALIZED;
-    }
-    if( !queueHandle->create(depth, msgSize) ) {
-      return QUEUE_UNINITIALIZED;
-    }
-    this->m_handle = reinterpret_cast<POINTER_CAST>(queueHandle);
-
-#if FW_QUEUE_REGISTRATION
-    if (this->s_queueRegistry) {
-        this->s_queueRegistry->regQueue(this);
-    }
-#endif
-
-    return QUEUE_OK;
-  }
-
-  Queue::~Queue() {
-    // Clean up the queue handle:
-    QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-    if (nullptr != queueHandle) {
-      delete queueHandle;
-    }
-    this->m_handle = reinterpret_cast<POINTER_CAST>(nullptr);
-  }
-
-  Queue::QueueStatus sendNonBlock(QueueHandle* queueHandle, const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority) {
-
-    BufferQueue* queue = &queueHandle->queue;
-    pthread_cond_t* queueNotEmpty = &queueHandle->queueNotEmpty;
-    pthread_mutex_t* queueLock = &queueHandle->queueLock;
-    NATIVE_INT_TYPE ret;
-    Queue::QueueStatus status = Queue::QUEUE_OK;
-
-    ////////////////////////////////
-    // Locked Section
-    ///////////////////////////////
-    ret = pthread_mutex_lock(queueLock);
-    FW_ASSERT(ret == 0, errno);
-    ///////////////////////////////
-
-    // Push item onto queue:
-    bool pushSucceeded = queue->push(buffer, static_cast<NATIVE_UINT_TYPE>(size), priority);
-
-    if(pushSucceeded) {
-      // Push worked - wake up a thread that might be waiting on
-      // the other end of the queue:
-      ret = pthread_cond_signal(queueNotEmpty);
-      FW_ASSERT(ret == 0, errno); // If this fails, something horrible happened.
-    }
-    else {
-      // Push failed - the queue is full:
-      status = Queue::QUEUE_FULL;
-    }
-
-    ///////////////////////////////
-    ret = pthread_mutex_unlock(queueLock);
-    FW_ASSERT(ret == 0, errno);
-    ////////////////////////////////
-    ///////////////////////////////
-
-    return status;
-  }
-
-  Queue::QueueStatus sendBlock(QueueHandle* queueHandle, const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority) {
-
-    BufferQueue* queue = &queueHandle->queue;
-    pthread_cond_t* queueNotEmpty = &queueHandle->queueNotEmpty;
-    pthread_cond_t* queueNotFull = &queueHandle->queueNotFull;
-    pthread_mutex_t* queueLock = &queueHandle->queueLock;
-    NATIVE_INT_TYPE ret;
-
-    ////////////////////////////////
-    // Locked Section
-    ///////////////////////////////
-    ret = pthread_mutex_lock(queueLock);
-    FW_ASSERT(ret == 0, errno);
-    ///////////////////////////////
-
-    // If the queue is full, wait until a message is taken off the queue:
-    while( queue->isFull() ) {
-      ret = pthread_cond_wait(queueNotFull, queueLock);
-      FW_ASSERT(ret == 0, errno);
-    }
-
-    // Push item onto queue:
-    bool pushSucceeded = queue->push(buffer, static_cast<NATIVE_UINT_TYPE>(size), priority);
-
-    // The only reason push would not succeed is if the queue
-    // was full. Since we waited for the queue to NOT be full
-    // before sending on the queue, the push must have succeeded
-    // unless there was a programming error or a bit flip.
-    FW_ASSERT(pushSucceeded, pushSucceeded);
-
-    // Push worked - wake up a thread that might be waiting on
-    // the other end of the queue:
-    ret = pthread_cond_signal(queueNotEmpty);
-    FW_ASSERT(ret == 0, errno); // If this fails, something horrible happened.
-
-    ///////////////////////////////
-    ret = pthread_mutex_unlock(queueLock);
-    FW_ASSERT(ret == 0, errno);
-    ////////////////////////////////
-    ///////////////////////////////
-
-    return Queue::QUEUE_OK;
-  }
-
-
-  Queue::QueueStatus Queue::send(const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority, QueueBlocking block) {
-    (void) block; // Always non-blocking for now
-    QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-    BufferQueue* queue = &queueHandle->queue;
-
-    if (nullptr == queueHandle) {
-        return QUEUE_UNINITIALIZED;
-    }
-
-    if (nullptr == buffer) {
-        return QUEUE_EMPTY_BUFFER;
-    }
-
-    if (size < 0 || static_cast<NATIVE_UINT_TYPE>(size) > queue->getMsgSize()) {
-        return QUEUE_SIZE_MISMATCH;
-    }
-
-    if( QUEUE_NONBLOCKING == block ) {
-      return sendNonBlock(queueHandle, buffer, size, priority);
-    }
-
-    return sendBlock(queueHandle, buffer, size, priority);
-  }
-
-  Queue::QueueStatus receiveNonBlock(QueueHandle* queueHandle, U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority) {
-
-      BufferQueue* queue = &queueHandle->queue;
-      pthread_mutex_t* queueLock = &queueHandle->queueLock;
-      pthread_cond_t* queueNotFull = &queueHandle->queueNotFull;
-      NATIVE_INT_TYPE ret;
-
-      NATIVE_UINT_TYPE size = static_cast<NATIVE_UINT_TYPE>(capacity);
-      NATIVE_INT_TYPE pri = 0;
-      Queue::QueueStatus status = Queue::QUEUE_OK;
-
-      ////////////////////////////////
-      // Locked Section
-      ///////////////////////////////
-      ret = pthread_mutex_lock(queueLock);
-      FW_ASSERT(ret == 0, errno);
-      ///////////////////////////////
-
-      // Get an item off of the queue:
-      bool popSucceeded = queue->pop(buffer, size, pri);
-
-      if(popSucceeded) {
-        // Pop worked - set the return size and priority:
-        actualSize = static_cast<NATIVE_INT_TYPE>(size);
-        priority = pri;
-
-        // Pop worked - wake up a thread that might be waiting on
-        // the send end of the queue:
-        ret = pthread_cond_signal(queueNotFull);
-        FW_ASSERT(ret == 0, errno); // If this fails, something horrible happened.
-      }
-      else {
-        actualSize = 0;
-        if( size > static_cast<NATIVE_UINT_TYPE>(capacity) ) {
-          // The buffer capacity was too small!
-          status = Queue::QUEUE_SIZE_MISMATCH;
-        }
-        else if( size == 0 ) {
-          // The queue is empty:
-          status = Queue::QUEUE_NO_MORE_MSGS;
-        }
-        else {
-          // If this happens, a programming error or bit flip occurred:
-          FW_ASSERT(0);
-        }
-      }
-
-      ///////////////////////////////
-      ret = pthread_mutex_unlock(queueLock);
-      FW_ASSERT(ret == 0, errno);
-      ////////////////////////////////
-      ///////////////////////////////
-
-      return status;
-  }
-
-  Queue::QueueStatus receiveBlock(QueueHandle* queueHandle, U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority) {
-
-      BufferQueue* queue = &queueHandle->queue;
-      pthread_cond_t* queueNotEmpty = &queueHandle->queueNotEmpty;
-      pthread_cond_t* queueNotFull = &queueHandle->queueNotFull;
-      pthread_mutex_t* queueLock = &queueHandle->queueLock;
-      NATIVE_INT_TYPE ret;
-
-      NATIVE_UINT_TYPE size = static_cast<NATIVE_UINT_TYPE>(capacity);
-      NATIVE_INT_TYPE pri = 0;
-      Queue::QueueStatus status = Queue::QUEUE_OK;
-
-      ////////////////////////////////
-      // Locked Section
-      ///////////////////////////////
-      ret = pthread_mutex_lock(queueLock);
-      FW_ASSERT(ret == 0, errno);
-      ///////////////////////////////
-
-      // If the queue is empty, wait until a message is put on the queue:
-      while( queue->isEmpty() ) {
-        ret = pthread_cond_wait(queueNotEmpty, queueLock);
-        FW_ASSERT(ret == 0, errno);
-      }
-
-      // Get an item off of the queue:
-      bool popSucceeded = queue->pop(buffer, size, pri);
-
-      if(popSucceeded) {
-        // Pop worked - set the return size and priority:
-        actualSize = static_cast<NATIVE_INT_TYPE>(size);
-        priority = pri;
-
-        // Pop worked - wake up a thread that might be waiting on
-        // the send end of the queue:
-        ret = pthread_cond_signal(queueNotFull);
-        FW_ASSERT(ret == 0, errno); // If this fails, something horrible happened.
-      }
-      else {
-        actualSize = 0;
-        if( size > static_cast<NATIVE_UINT_TYPE>(capacity) ) {
-          // The buffer capacity was too small!
-          status = Queue::QUEUE_SIZE_MISMATCH;
-        }
-        else {
-          // If this happens, a programming error or bit flip occurred:
-          // The only reason a pop should fail is if the user's buffer
-          // was too small.
-          FW_ASSERT(0);
-        }
-      }
-
-      ///////////////////////////////
-      ret = pthread_mutex_unlock(queueLock);
-      FW_ASSERT(ret == 0, errno);
-      ////////////////////////////////
-      ///////////////////////////////
-
-      return status;
-  }
-
-  Queue::QueueStatus Queue::receive(U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority, QueueBlocking block) {
-
-      if( reinterpret_cast<POINTER_CAST>(nullptr) == this->m_handle ) {
-        return QUEUE_UNINITIALIZED;
-      }
-
-      QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-
-      if (nullptr == queueHandle) {
-        return QUEUE_UNINITIALIZED;
-      }
-
-      // Do not need to check the upper bound of capacity, We don't care
-      // how big the user's buffer is.. as long as it's big enough.
-      if (capacity < 0) {
-          return QUEUE_SIZE_MISMATCH;
-      }
-
-      if( QUEUE_NONBLOCKING == block ) {
-        return receiveNonBlock(queueHandle, buffer, capacity, actualSize, priority);
-      }
-
-      return receiveBlock(queueHandle, buffer, capacity, actualSize, priority);
-  }
-
-  NATIVE_INT_TYPE Queue::getNumMsgs() const {
-      QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-      if (nullptr == queueHandle) {
-          return 0;
-      }
-      BufferQueue* queue = &queueHandle->queue;
-      return static_cast<NATIVE_INT_TYPE>(queue->getCount());
-  }
-
-  NATIVE_INT_TYPE Queue::getMaxMsgs() const {
-      QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-      if (nullptr == queueHandle) {
-          return 0;
-      }
-      BufferQueue* queue = &queueHandle->queue;
-      return static_cast<NATIVE_INT_TYPE>(queue->getMaxCount());
-  }
-
-  NATIVE_INT_TYPE Queue::getQueueSize() const {
-      QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-      if (nullptr == queueHandle) {
-          return 0;
-      }
-      BufferQueue* queue = &queueHandle->queue;
-      return static_cast<NATIVE_INT_TYPE>(queue->getDepth());
-  }
-
-  NATIVE_INT_TYPE Queue::getMsgSize() const {
-      QueueHandle* queueHandle = reinterpret_cast<QueueHandle*>(this->m_handle);
-      if (nullptr == queueHandle) {
-          return 0;
-      }
-      BufferQueue* queue = &queueHandle->queue;
-      return static_cast<NATIVE_INT_TYPE>(queue->getMsgSize());
-  }
-
-}
-
diff --git a/Os/Pthreads/docs/sdd.md b/Os/Pthreads/docs/sdd.md
deleted file mode 100644
index 2321cb3dc4..0000000000
--- a/Os/Pthreads/docs/sdd.md
+++ /dev/null
@@ -1,216 +0,0 @@
-\page OsQueue Os::Queue (Pthreads implementation)
-# Os::Queue (Pthreads implementation)
-
-## 1 Introduction
-
-The ISF `Os::Queue` provides a message queue interface for asynchronous ISF ports. Many operating systems provide
-their own inter-process communication (IPC) queues (ie. [POSIX](http://man7.org/linux/man-pages/man7/mq_overview.7.html), VxWorks, [SysV](http://man7.org/linux/man-pages/man7/svipc.7.html)), which have traditionally been used as
-the underlying implementation for `Os::Queue`. In contrast, this Pthreads implementation is hand coded C++ code
-tailored to the ISF `Os::Queue` interface. Its only dependency on non-standard libraries is [`<pthread.h>`](http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread.h.html), which is 
-used for access and control flow of the internal queue data structure (ie. [`pthread_mutex_lock`](http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_mutex_lock.html), [`pthread_cond_wait`](http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_cond_wait.html), 
-etc.). The Pthread implementation provides the following advantages over the operating system provided IPC queues:
-
-- The Pthreads implementation is NOT an IPC queue. It is designed for message passing between threads in the same
-memory address space. This means that it never touches the filesystem and has no persistent state after the
-`Os::Queue` deconstructor has been called. ISF currently does not spread different threads of execution in different memory 
-spaces on Darwin and Linux, so this is an acceptable solution.
-
-- Memory for Pthreads queues are allocated on the heap at initialization. After initialization, the memory usage of the
-queue remains static. The queue sizes are only limited by the amount of memory on your system. The queue size is NOT 
-governed by arbitrary limits defined in kernel configurations, as is the case for POSIX and SysV queues.
-
-- Since the Pthreads implementation is handwritten, ISF developers can change the interface and add new features
-to support mission needs. In particular, queue usage statistics can be built in, such as high water marking, message
-counts, etc.
-
-The Pthread queues can be configured in one of two ways depending on mission needs: first-in-first-out (FIFO) or priority. 
-The FIFO queue is implemented using a circular buffer with *O(log(1))* enqueue and dequeue time. The priority queue is
-implemented using a stable maximum binary heap with *O(log(n))* enqueue and dequeue time. Note: A *stable* maximum binary heap 
-has the property that items pulled off the queue are in order of decreasing priority. Items of equal priority are pulled off 
-in FIFO order.
-
-NOTE: POSIX queues use a dynamically sized [red-black tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) for the message queue data structure. This data structure also has an *O(log(n))* enqueue and dequeue time.
-
-## 2 Requirements
-
-Requirement | Description | Rationale | Verification Method
----- | ---- | ---- | ----
-ISF-Q-001 | The Pthreads queue shall conform to the ISF `Os::Queue` interface. | Ensures the queue can be used for ISF components | Inspection
-ISF-Q-002 | The Pthreads queue shall not use dynamic memory, except at initialization. | Conform to flight software guidelines. | Inspection
-ISF-Q-003 | The Pthreads queue shall not use operating system parameters for size limits. | Ensure that the queue sizes can be changed by the user without changing kernel parameters. | Inspection
-
-## 3 Design
-
-### 3.1 Constants
-
-The Pthreads queue uses the following constants, specified at instantiation:
-
-1. <a name="msgSize">*Message Size*</a>: The maximum size of a message that can be stored in the queue.
-
-2. <a name="depth">*Depth*</a>: The maximum number of messages that can stored in the queue.
-
-3. <a name="block">*Block*</a>: Flag which specifies whether the queue should block when reading from an empty queue.
-
-### 3.2 State
-
-The queue maintains the following state:
-
-1. <a name="num_queue">*Number of Queues*</a>: The current number of queues allocated in the system (static variable which starts at 0).
-
-2. <a name="count">*Count*</a>: The current number of messages in the queue (starts at 0).
-
-3. <a name="maxCount">*Maximum Count*</a>: The maximum number of messages ever seen in the queue since instantiation. This is the "high water mark" of the queue.
-
-4. <a name="queue">*Queue*</a>: The queue data structure itself. The queue memory is allocated in a `U8*` buffer of size: ([Message Size](#msgSize) + `sizeof(NATIVE_UINT_TYPE)`) * [Depth](#depth)
-
-5. <a name="heap">*Heap*</a> (for priority queue only): The stable maximum binary heap data structure which orders stored messages with respect to priority. The size of the heap in memory is: `sizeof(NATIVE_UINT_TYPE)` * 3 * [Depth](#depth).
-
-### 3.3 Stable Maximum Binary Heap
-
-A maximum [binary heap data structure](https://en.wikipedia.org/wiki/Binary_heap) is a binary tree with the following constraints:
-
-1. It is complete, that is, all levels of the tree, except possibly the last one (deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right.
-
-2. It satisfies the maximum heap property, that is, all nodes are either greater than or equal to each of its children.
-
-The Pthreads heap implementation is also *stable*, which means it satisfies the following additional constraint:
-
-3. If a node has children nodes of equal value, the parent node must be "older" (inserted before) each equal-valued child node. 
-
-This ensures that messages of equal priority are dequeued in FIFO order.
-
-##4 Implementation
-
-This section provides a summary of the code included in the C++ implementation files.
-
-- **`Queue.cpp`:** This is the implementation of the ISF `Os::Queue` class. This file provides synchronization between threads reading and writing to the queue, and passes data to and from the underlying data structure.
-
-- **`BufferQueue.hpp`:** This file outlines an interface to a generic queue data structure.
-
-- **`FIFOBufferQueue.cpp`:** This file implements a first-in-first-out queue data structure, conforming to `BufferQueue.hpp`.
-
-- **`PriorityBufferQueue.cpp`:** This file implements a priority queue data structure, conforming to `BufferQueue.hpp`. It uses files in MaxHeap/ to perform priority queueing.
-
-- **`BufferQueueCommon.cpp`:** This file implements various common methods for `BufferQueue.hpp`.
-
-- **`MaxHeap/MaxHeap.hpp`:** This file outlines an interface to a generic maximum heap data structure, where `NATIVE_INT_TYPE` is used for priority and a `NATIVE_UINT_TYPE` is stored as data.
-
-- **`MaxHeap/MaxHeap.cpp`:** This file implements a stable maximum heap conforming to `MaxHeap/MaxHeap.hpp`.
-
-Note: To use the FIFO queue implementation, a user must include `Queue.cpp`, `FIFOBufferQueue.cpp`, and `BufferQueueCommon.cpp` in the compilation. To use the priority queue implementation, the user must include `Queue.cpp`, `PriorityBufferQueue.cpp`, `BufferQueueCommon.cpp`, and `MaxHeap/MaxHeap.cpp`.
-
-## 5 Unit Testing
-
-There are 3 unit tests used to validate the Pthreads queue implementation at different levels of abstraction.
-
-### 5.1 Maximum Heap Unit Test
-
-The maximum heap unit tests are located in `Os/Pthread/MaxHeap/test/ut`. These tests validate the functionality of the maximum heap data structure. Test names and descriptions are listed below:
-
-1. **Empty Heap**: Make sure that removing an item from an empty heap returns an error.
-
-2. **Full Heap**: Make sure that adding an item to a full heap returns an error.
-
-3. **Pop**: Test removing an item from a filled heap.
-
-4. **Random Push/Pop**: Test adding and removing items of varied priority and ensure that they are returned off the heap in the correct order.
-
-5. **Equal Priority**: Test that items added to the queue with equal priority are popped off in FIFO order.
-
-6. **Mixed Priority**: Test that items added to the queue with both varied and equal priority are popped off in priority order and FIFO order when priorities are equal.
-
-### 5.2 Buffer Queue Unit Test
-
-The buffer queue unit tests are located in `Os/Pthread/test/ut`. These tests validate the functionality of the underlying queue data structure. Note: These tests do NOT test any blocking behavior of the queue. Test names and descriptions are listed below:
-
-1. **Empty Queue**: Make sure that removing an item from an empty queue returns an error.
-
-2. **Full Queue**: Make sure that adding an item to a full queue returns an error.
-
-3. **Size Mismatch**: Make sure that trying to receive a large message into a too-small buffer returns an error.
-
-4. **Pop**: Test removing an item from a filled queue.
-
-5. **Priorities**: Ensure that the queue returns messages in priority order, and in FIFO order for equal priorities.
-
-### 5.3 Queue Unit Test
-
-The queue unit tests are located in `Os/test/ut`. These tests validate the functionality of the queue as well as the blocking behavior at the component interface level. Test names and descriptions are listed below:
-
-#### 5.3.1 Blocking Queue Unit Test
-
-1. **Send and Receive**: Test successful send and receive from a blocking queue.
-
-2. **Blocking Receive on Empty**: Test blocking behavior for receiving on an empty queue.
-
-3. **Non-blocking Send on Full**: Test non-blocking behavior for sending to a full queue.
-
-4. **Send and Receive with Priorities**: Test that sending and receiving of messages occurs in the correct order with respect to priority.
-
-#### 5.3.2 Non-blocking Queue Unit Test
-
-1. **Send and Receive**: Test successful send and receive from a non-blocking queue.
-
-2. **Non-blocking Receive on Empty**: Test non-blocking behavior for receiving on an empty queue.
-
-3. **Non-blocking Send on Full**: Test non-blocking behavior for sending to a full queue.
-
-4. **Send and Receive with Priorities**: Test that sending and receiving of messages occurs in the correct order with respect to priority.
-
-#### 5.3.3 Queue Performance Unit Test
-
-1. **Shallow Queue Test**: 3 messages are sent on the queue, and then 3 messages are read on the queue. This test is repeated 1000000 times in a single thread and the execution time is printed.
-
-2. **Deep Queue Test**: The queue is first pre-filled to its maximum capacity (default 10). Next, test 1 is run 1000000 times and the execution time is printed.
-
-3. **Concurrent Queue Test**: Test 2 is run simultaneously using 4 threads, 50000 times for each thread, and the execution time is printed.
-
-## 6 Performance
-
-The performance results for tests 5.3.3 for the Pthreads queue and the Posix queue were run on a Virtual Box VM (hosted on a Mac) and given 4 execution cores (April 2016). The test results can be seen below:
-
-**Pthreads queue results:**
-```
----------------------
-- performance test --
----------------------
-Testing shallow queue...
-Time: 1.362s (1.362us per)
-Testing deep queue...
-Time: 1.769s (1.769us per)
-Test complete.
----------------------
----------------------
----------------------
--- concurrent test --
----------------------
-Testing deep queue...
-Time: 0.882s (17.633us per)
-Test complete.
----------------------
----------------------
-```
-
-**Posix queue results:**
-```
----------------------
-- performance test --
----------------------
-Testing shallow queue...
-Time: 3.993s (3.993us per)
-Testing deep queue...
-Time: 3.942s (3.942us per)
-Test complete.
----------------------
----------------------
----------------------
--- concurrent test --
----------------------
-Testing deep queue...
-Time: 0.701s (14.017us per)
-Test complete.
----------------------
----------------------
-```
-
-The Pthreads queues are significantly faster than posix queues on a single core. The Pthreads queue is marginally slower in a multi-threaded environment, but its performance is still very similar to the Posix queue implementation. Based on these results the Pthreads queue is performant enough for single core flight systems. It also looks to have reasonable performance when multi-threaded. If we wanted better multi-core performance, we could look into implementing a [lock-free concurrent max heap data structure](http://www.non-blocking.com/download/SunT03_PQueue_TR.pdf).
diff --git a/Os/Queue.cpp b/Os/Queue.cpp
new file mode 100644
index 0000000000..10e7062067
--- /dev/null
+++ b/Os/Queue.cpp
@@ -0,0 +1,137 @@
+// ======================================================================
+// \title Os/Queue.cpp
+// \brief common function implementation for Os::Queue
+// ======================================================================
+#include "Os/Queue.hpp"
+#include "Fw/Types/Assert.hpp"
+#include "Fw/Types/Serializable.hpp"
+
+namespace Os {
+
+FwSizeType Queue::s_queueCount = 0;
+QueueRegistry* Queue::s_queueRegistry = nullptr;
+
+Queue::Queue() : m_name(""), m_depth(0), m_size(0), m_delegate(*QueueInterface::getDelegate(m_handle_storage)) {}
+
+Queue::~Queue() {
+    m_delegate.~QueueInterface();
+}
+
+QueueInterface::Status Queue ::create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<QueueInterface*>(&this->m_handle_storage[0]));
+    FW_ASSERT(depth > 0);
+    FW_ASSERT(messageSize > 0);
+    // Check for previous creation call
+    if (this->m_depth > 0 || this->m_size > 0) {
+        return QueueInterface::Status::ALREADY_CREATED;
+    }
+    QueueInterface::Status status = this->m_delegate.create(name, depth, messageSize);
+    if (status == QueueInterface::Status::OP_OK) {
+        this->m_name = name;
+        this->m_depth = depth;
+        this->m_size = messageSize;
+        ScopeLock lock(Queue::getStaticMutex());
+        Queue::s_queueCount++;
+        if (Queue::s_queueRegistry != nullptr) {
+            Queue::s_queueRegistry->registerQueue(this);
+        }
+    }
+    return status;
+}
+
+QueueInterface::Status Queue::send(const U8* buffer,
+                                   FwSizeType size,
+                                   PlatformIntType priority,
+                                   QueueInterface::BlockingType blockType) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<QueueInterface*>(&this->m_handle_storage[0]));
+    FW_ASSERT(buffer != nullptr);
+    // Check if initialized
+    if (this->m_depth == 0 || this->m_size == 0) {
+        return QueueInterface::Status::UNINITIALIZED;
+    }
+    // Check size before proceeding
+    else if (size > this->getMessageSize()) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    }
+    return this->m_delegate.send(buffer, size, priority, blockType);
+}
+
+QueueInterface::Status Queue::receive(U8* destination,
+                                      FwSizeType capacity,
+                                      QueueInterface::BlockingType blockType,
+                                      FwSizeType& actualSize,
+                                      PlatformIntType& priority) {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<QueueInterface*>(&this->m_handle_storage[0]));
+    FW_ASSERT(destination != nullptr);
+    // Check if initialized
+    if (this->m_depth == 0 || this->m_size == 0) {
+        return QueueInterface::Status::UNINITIALIZED;
+    }
+    // Check capacity before proceeding
+    else if (capacity < this->getMessageSize()) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    }
+    return this->m_delegate.receive(destination, capacity, blockType, actualSize, priority);
+}
+
+FwSizeType Queue::getMessagesAvailable() const {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<const QueueInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate.getMessagesAvailable();
+}
+
+FwSizeType Queue::getMessageHighWaterMark() const {
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<const QueueInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate.getMessageHighWaterMark();
+}
+
+QueueHandle* Queue::getHandle(){
+    FW_ASSERT(&this->m_delegate == reinterpret_cast<const QueueInterface*>(&this->m_handle_storage[0]));
+    return this->m_delegate.getHandle();
+}
+
+QueueInterface::Status Queue::send(const Fw::SerializeBufferBase& message,
+                                   PlatformIntType priority,
+                                   QueueInterface::BlockingType blockType) {
+    return this->send(message.getBuffAddr(), message.getBuffLength(), priority, blockType);
+}
+
+QueueInterface::Status Queue::receive(Fw::SerializeBufferBase& destination,
+                                      QueueInterface::BlockingType blockType,
+                                      PlatformIntType& priority) {
+    FwSizeType actualSize = 0;
+    destination.resetSer();  // Reset the buffer
+    QueueInterface::Status status =
+        this->receive(destination.getBuffAddrSer(), destination.getBuffCapacity(), blockType, actualSize, priority);
+    if (status == QueueInterface::Status::OP_OK) {
+        Fw::SerializeStatus serializeStatus =
+            destination.setBuffLen(static_cast<Fw::Serializable::SizeType>(actualSize));
+        if (serializeStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
+            status = QueueInterface::Status::SIZE_MISMATCH;
+        }
+    }
+    return status;
+}
+
+FwSizeType Queue::getDepth() const {
+    return this->m_depth;
+}
+
+FwSizeType Queue::getMessageSize() const {
+    return this->m_size;
+}
+
+const QueueString& Queue::getName() const {
+    return this->m_name;
+}
+
+FwSizeType Queue::getNumQueues() {
+    ScopeLock lock(Queue::getStaticMutex());
+    return Queue::s_queueCount;
+}
+
+Os::Mutex& Queue::getStaticMutex() {
+    static Os::Mutex s_mutex;
+    return s_mutex;
+}
+
+}  // namespace Os
diff --git a/Os/Queue.hpp b/Os/Queue.hpp
index 56c7804042..d2b72d3c70 100644
--- a/Os/Queue.hpp
+++ b/Os/Queue.hpp
@@ -1,94 +1,323 @@
-/**
- * Queue.hpp:
- *
- * Queues are used internally to F prime in order to support the messaging between components. The
- * Queue class is used to abstract away from the standard OS-based queue, allowing F prime support
- * multiple OSes in a consistent way.
- *
- * Like most items in the OS package, the implementation is done in two parts. One part is the file
- * `QueueCommon.cpp`. It contains the shared code for queues regardless of the OS. The other is a
- * .cpp file containing the OS specific backends for defined functions. (i.e. Posix/Queue.cpp).
- */
-#ifndef _Queue_hpp_
-#define _Queue_hpp_
+// ======================================================================
+// \title Os/Queue.hpp
+// \brief common function definitions for Os::Queue
+// ======================================================================
+#ifndef Os_Queue_hpp_
+#define Os_Queue_hpp_
 
 #include <FpConfig.hpp>
 #include <Fw/Obj/ObjBase.hpp>
 #include <Fw/Types/Serializable.hpp>
+#include <Os/Os.hpp>
 #include <Os/QueueString.hpp>
-
+#include <Os/Mutex.hpp>
 namespace Os {
-    // forward declaration for registry
-    class QueueRegistry;
-
-    class Queue {
-        public:
-
-            enum QueueStatus {
-                QUEUE_OK, //!<  message sent/received okay
-                QUEUE_NO_MORE_MSGS, //!<  If non-blocking, all the messages have been drained.
-                QUEUE_UNINITIALIZED, //!<  Queue wasn't initialized successfully
-                QUEUE_SIZE_MISMATCH, //!<  attempted to send or receive with buffer too large, too small
-                QUEUE_SEND_ERROR, //!<  message send error
-                QUEUE_RECEIVE_ERROR, //!<  message receive error
-                QUEUE_INVALID_PRIORITY, //!<  invalid priority requested
-                QUEUE_EMPTY_BUFFER, //!<  supplied buffer is empty
-                QUEUE_FULL, //!< queue was full when attempting to send a message
-                QUEUE_UNKNOWN_ERROR //!<  Unexpected error; can't match with returns
-            };
-
-            enum QueueBlocking {
-                QUEUE_BLOCKING, //!<  Queue receive blocks until a message arrives
-                QUEUE_NONBLOCKING //!<  Queue receive always returns even if there is no message
-            };
-
-            Queue();
-            virtual ~Queue();
-            QueueStatus create(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize); //!<  create a message queue
-
-            // Send serialized buffers
-            QueueStatus send(const Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE priority, QueueBlocking block); //!<  send a message
-            QueueStatus receive(Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE &priority, QueueBlocking block); //!<  receive a message
-
-            // Send raw buffers
-            QueueStatus send(const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority, QueueBlocking block); //!<  send a message
-            QueueStatus receive(U8* buffer, NATIVE_INT_TYPE capacity, NATIVE_INT_TYPE &actualSize, NATIVE_INT_TYPE &priority, QueueBlocking block); //!<  receive a message
-
-            NATIVE_INT_TYPE getNumMsgs() const; //!< get the number of messages in the queue
-            NATIVE_INT_TYPE getMaxMsgs() const; //!< get the maximum number of messages (high watermark)
-            NATIVE_INT_TYPE getQueueSize() const; //!< get the queue depth (maximum number of messages queue can hold)
-            NATIVE_INT_TYPE getMsgSize() const; //!< get the message size (maximum message size queue can hold)
-            const QueueString& getName(); //!< get the queue name
-            static NATIVE_INT_TYPE getNumQueues(); //!< get the number of queues in the system
-#if FW_QUEUE_REGISTRATION
-            static void setQueueRegistry(QueueRegistry* reg); // !< set the queue registry
-#endif
+// Forward declaration for registry
+class QueueRegistry;
 
-        protected:
-            //! Internal method used for creating allowing alternate implementations to implement different creation
-            //! behavior without needing to duplicate the majority of the creation functionality.
-            //! \param name: name of queue
-            //! \param depth: depth of queue
-            //! \param msgSize: size of a message stored on queue
-            //! \return queue creation status
-            QueueStatus createInternal(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize); //!<  create a message queue
-            POINTER_CAST m_handle; //!<  handle for implementation specific queue
-            QueueString m_name; //!< queue name
-#if FW_QUEUE_REGISTRATION
-            static QueueRegistry* s_queueRegistry; //!< pointer to registry
-#endif
-            static NATIVE_INT_TYPE s_numQueues; //!< tracks number of queues in the system
+//! \brief QueueHandle parent class
+class QueueHandle {};
 
-        private:
-            Queue(Queue&); //!<  Disabled copy constructor
-            Queue(Queue*); //!<  Disabled copy constructor
+//! \brief base queue interface
+//!
+//! Queues are used internally to fprime in order to support the messaging between components. The
+//! QueueInterface is used to abstract away from the standard OS-based queue, allowing F prime support
+//! multiple OSes in a consistent way.
+//!
+class QueueInterface {
+  public:
+    //! \brief status returned from the queue send function
+    enum Status {
+        OP_OK,             //!<  message sent/received okay
+        ALREADY_CREATED,   //!<  creating an already created queue
+        EMPTY,             //!<  If non-blocking, all the messages have been drained.
+        UNINITIALIZED,     //!<  Queue wasn't initialized successfully
+        SIZE_MISMATCH,     //!<  attempted to send or receive with buffer too large, too small
+        SEND_ERROR,        //!<  message send error
+        RECEIVE_ERROR,     //!<  message receive error
+        INVALID_PRIORITY,  //!<  invalid priority requested
+        FULL,              //!< queue was full when attempting to send a message
+        UNKNOWN_ERROR      //!<  Unexpected error; can't match with returns
     };
 
-    class QueueRegistry {
-        public:
-            virtual void regQueue(Queue* obj)=0; //!< method called by queue init() methods to register a new queue
-            virtual ~QueueRegistry() {}; //!< virtual destructor for registry object
+    //! \brief message type
+    enum BlockingType {
+        BLOCKING,    //!< Message will block until space is available
+        NONBLOCKING  //!< Message will return with status when space is unavailable
     };
-}
 
+    //! \brief default queue interface constructor
+    QueueInterface() = default;
+
+    //! \brief default queue destructor
+    virtual ~QueueInterface() = default;
+
+    //! \brief copy constructor is forbidden
+    QueueInterface(const QueueInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    QueueInterface(const QueueInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    virtual QueueInterface& operator=(const QueueInterface& other) = delete;
+
+    //! \brief create queue storage
+    //!
+    //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. Resource
+    //! allocation is dependent on the underlying implementation and users should assume that resource allocation is
+    //! possible.
+    //!
+    //! \param name: name of queue
+    //! \param depth: depth of queue in number of messages
+    //! \param messageSize: size of an individual message
+    //! \return: status of the creation
+    virtual Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) = 0;
+
+    //! \brief send a message into the queue
+    //!
+    //! Send a message into the queue, providing the message data, size, priority, and blocking type. When
+    //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error
+    //! status on queue full.
+    //!
+    //! It is invalid to send a null buffer.
+    //! This method will block if the queue is full and blockType is set to BLOCKING
+    //!
+    //! \param buffer: message data
+    //! \param size: size of message data
+    //! \param priority: priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return: status of the send
+    virtual Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) = 0;
+
+    //! \brief receive a message from the queue
+    //!
+    //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type.
+    //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an
+    //! error status on queue empty. Actual size received and priority of message is set on success status.
+    //!
+    //! It is invalid to send a null buffer.
+    //! This method will block if the queue is empty and blockType is set to BLOCKING
+    //!
+    //! \param destination: destination for message data
+    //! \param capacity: maximum size of message data
+    //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty
+    //! \param actualSize: (output) actual size of message read
+    //! \param priority: (output) priority of message read
+    //! \return: status of the send
+    virtual Status receive(U8* destination,
+                           FwSizeType capacity,
+                           BlockingType blockType,
+                           FwSizeType& actualSize,
+                           FwQueuePriorityType& priority) = 0;
+
+    //! \brief get number of messages available
+    //!
+    //! Returns the number of messages currently available in the queue.
+    //!
+    //! \return number of messages available
+    virtual FwSizeType getMessagesAvailable() const = 0;
+
+    //! \brief get maximum messages stored at any given time
+    //!
+    //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for this
+    //! queue.
+    //! \return queue message high-water mark
+    virtual FwSizeType getMessageHighWaterMark() const = 0;
+
+    //! \brief return the underlying queue handle (implementation specific)
+    //! \return internal task handle representation
+    virtual QueueHandle* getHandle() = 0;
+
+    //! \brief provide a pointer to a queue delegate object
+    //!
+    //! This function must return a pointer to a `QueueInterface` object that contains the real implementation of the
+    //! queue functions as defined by the implementor.  This function must do several things to be considered correctly
+    //! implemented:
+    //!
+    //! 1. Assert that the supplied memory is non-null. e.g `FW_ASSERT(aligned_placement_new_memory != NULL);`
+    //! 2. Assert that their implementation fits within FW_HANDLE_MAX_SIZE.
+    //!    e.g. `static_assert(sizeof(PosixQueueImplementation) <= sizeof Os::Queue::m_handle_storage,
+    //!        "FW_HANDLE_MAX_SIZE to small");`
+    //! 3. Assert that their implementation aligns within FW_HANDLE_ALIGNMENT.
+    //!    e.g. `static_assert((FW_HANDLE_ALIGNMENT % alignof(PosixQueueImplementation)) == 0, "Bad handle alignment");`
+    //! 4. Placement new their implementation into `aligned_placement_new_memory`
+    //!    e.g. `TaskInterface* interface = new (aligned_placement_new_memory) PosixQueueImplementation;`
+    //! 5. Return the result of the placement new
+    //!    e.g. `return interface;`
+    //!
+    //! \return result of placement new, must be equivalent to `aligned_placement_new_memory`
+    //!
+    static QueueInterface* getDelegate(QueueHandleStorage& aligned_placement_new_memory);
+};
+
+class Queue final : public QueueInterface {
+  public:
+    //! \brief queue constructor
+    Queue();
+
+    //! \brief default queue destructor
+    virtual ~Queue();
+
+    //! \brief copy constructor is forbidden
+    Queue(const Queue& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    Queue(const Queue* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    QueueInterface& operator=(const QueueInterface& other) override = delete;
+
+    //! \brief create queue storage through delegate
+    //!
+    //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. This method
+    //! delegates to the underlying implementation. Resource allocation is dependent on the underlying implementation
+    //! and users should assume that resource allocation is possible.
+    //!
+    //! \param name: name of queue
+    //! \param depth: depth of queue in number of messages
+    //! \param messageSize: size of an individual message
+    //! \return: status of the creation
+    Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override;
+
+    //! \brief send a message into the queue through delegate
+    //!
+    //! Send a message into the queue, providing the message data, size, priority, and blocking type. When
+    //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error
+    //! status on queue full. This method delegates to the underlying implementation.
+    //!
+    //! \warning It is invalid to send a null buffer
+    //! \warning This method will block if the queue is full and blockType is set to BLOCKING
+    //!
+    //! \param buffer: message data
+    //! \param size: size of message data
+    //! \param priority: priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return: status of the send
+    Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) override;
+
+    //! \brief receive a message from the queue through delegate
+    //!
+    //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type.
+    //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an
+    //! error status on queue empty. Actual size received and priority of message is set on success status. This method
+    //! delegates to the underlying implementation.
+    //!
+    //! \warning It is invalid to send a null buffer.
+    //! \warning This method will block if the queue is empty and blockType is set to BLOCKING
+    //!
+    //! \param destination: destination for message data
+    //! \param capacity: maximum size of message data
+    //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty
+    //! \param actualSize: (output) actual size of message read
+    //! \param priority: (output) priority of message read
+    //! \return: status of the send
+    Status receive(U8* destination,
+                   FwSizeType capacity,
+                   BlockingType blockType,
+                   FwSizeType& actualSize,
+                   FwQueuePriorityType& priority) override;
+
+    //! \brief get number of messages available
+    //!
+    //! Returns the number of messages currently available in the queue. This method delegates to the underlying
+    //! implementation.
+    //!
+    //! \return number of messages available
+    FwSizeType getMessagesAvailable() const override;
+
+    //! \brief get maximum messages stored at any given time through delegate
+    //!
+    //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for
+    //! this queue.
+    //! \return queue message high-water mark
+    FwSizeType getMessageHighWaterMark() const override;
+
+    //! \brief return the underlying queue handle (implementation specific). Delegates to implementation.
+    //! \return internal task handle representation
+    QueueHandle* getHandle() override;
+
+    //! \brief send a message to a queue
+    //!
+    //! Send a message to a queue with the given priority and block type. See: QueueInterface::send
+    //!
+    //! \warning This method will block if the queue is full and blockType is set to BLOCKING
+    //!
+    //! \param message: reference to serialize buffer storing message
+    //! \param priority: priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return status of the send
+    Status send(const Fw::SerializeBufferBase& message, FwQueuePriorityType priority, BlockingType blockType);
+
+    //! \brief receive a message from a queue
+    //!
+    //! Receive a message from a queue with the given block type. See: QueueInterface::receive. Note: this will entirely
+    //! overwrite the buffer.
+    //!
+    //! \warning This method will block if the queue is full and blockType is set to BLOCKING
+    //!
+    //! \param destination: reference to serialize buffer for storing message
+    //! \param priority: (output) priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return status of the send
+    Status receive(Fw::SerializeBufferBase& destination, BlockingType blockType, FwQueuePriorityType& priority);
+
+    //! \brief get the queue's depth in messages
+    FwSizeType getDepth() const;
+
+    //! \brief get the queue's message maximum size
+    FwSizeType getMessageSize() const;
+
+    //! \brief get the queue's name
+    const QueueString& getName() const;
+
+    //! \brief get number of queues system-wide
+    static FwSizeType getNumQueues();
+
+    //! \brief get static mutex
+    static Os::Mutex& getStaticMutex();
+
+  private:
+    QueueString m_name;                           //!< queue name
+    FwSizeType m_depth;                           //!< Queue depth
+    FwSizeType m_size;                            //!< Maximum message size
+    static Os::Mutex s_countLock;                 //!< Lock the count
+    static FwSizeType s_queueCount;               //!< Count of the number of queues
+
+#if FW_QUEUE_REGISTRATION
+  public:
+    //! \brief set QueueRegistry for tracking queues
+    //!
+    //! \param registry: registry to set
+    static void setRegistry(QueueRegistry* registry);
+
+  private:
+    static QueueRegistry* s_queueRegistry;  //!< Queue registry store
+#endif
+
+    // This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is
+    // opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in
+    // the byte-array here and set `handle` to that address for storage.
+    //
+    alignas(FW_HANDLE_ALIGNMENT) QueueHandleStorage m_handle_storage;  //!< Storage for aligned handle
+    QueueInterface& m_delegate;                                        //!< Delegate for the real implementation
+};
+//! \brief queue registry interface
+//!
+//! The QueueRegistry is used to track queues in the system. There is intended to be a single, global, queue registry
+//! across the system. It is used to track queues and will receive a callback on the creation of each queue.
+class QueueRegistry {
+  public:
+    //! Default QueueRegistry
+    QueueRegistry() = default;
+    //! Default ~QueueRegistry
+    virtual ~QueueRegistry() = default;
+
+    //! \brief queue registry callback
+    //!
+    //! Register the queue with this queue registry. Must be implemented by QueueRegistry implementations.
+    //!
+    //! \param queue: queue being registered
+    virtual void registerQueue(Queue* queue) = 0;  //!< method called by queue init() methods to register a new queue
+};
+}  // namespace Os
 #endif
diff --git a/Os/QueueCommon.cpp b/Os/QueueCommon.cpp
deleted file mode 100644
index 904713de00..0000000000
--- a/Os/QueueCommon.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <Os/Queue.hpp>
-#include <Fw/Types/Assert.hpp>
-#include <cstring>
-
-namespace Os {
-
-#if FW_QUEUE_REGISTRATION
-    QueueRegistry* Queue::s_queueRegistry = nullptr;
-#endif
-
-    NATIVE_INT_TYPE Queue::s_numQueues = 0;
-
-    Queue::QueueStatus Queue::send(const Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE priority, QueueBlocking block) {
-
-        const U8* msgBuff = buffer.getBuffAddr();
-        NATIVE_INT_TYPE buffLength = static_cast<NATIVE_INT_TYPE>(buffer.getBuffLength());
-
-        return this->send(msgBuff,buffLength,priority, block);
-
-    }
-
-    Queue::QueueStatus Queue::receive(Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE &priority, QueueBlocking block) {
-
-        U8* msgBuff = buffer.getBuffAddr();
-        NATIVE_INT_TYPE buffCapacity = static_cast<NATIVE_INT_TYPE>(buffer.getBuffCapacity());
-        NATIVE_INT_TYPE recvSize = 0;
-
-        Queue::QueueStatus recvStat = this->receive(msgBuff, buffCapacity, recvSize, priority, block);
-
-        if (QUEUE_OK == recvStat) {
-            if (buffer.setBuffLen(static_cast<NATIVE_UINT_TYPE>(recvSize)) == Fw::FW_SERIALIZE_OK) {
-                return QUEUE_OK;
-            } else {
-                return QUEUE_SIZE_MISMATCH;
-            }
-        } else {
-            return recvStat;
-        }
-    }
-
-    Queue::QueueStatus Queue::create(const Fw::StringBase &name, NATIVE_INT_TYPE depth, NATIVE_INT_TYPE msgSize) {
-        FW_ASSERT(depth > 0, depth);
-        FW_ASSERT(msgSize > 0, depth);
-        return createInternal(name, depth, msgSize);
-    }
-
-
-#if FW_QUEUE_REGISTRATION
-
-    void Queue::setQueueRegistry(QueueRegistry* reg) {
-        // NULL is okay if a deregistration is desired
-        Queue::s_queueRegistry = reg;
-    }
-
-#endif
-
-    NATIVE_INT_TYPE Queue::getNumQueues() {
-        return Queue::s_numQueues;
-    }
-
-    const QueueString& Queue::getName() {
-        return this->m_name;
-    }
-
-}
diff --git a/Os/SimpleQueueRegistry.cpp b/Os/SimpleQueueRegistry.cpp
deleted file mode 100644
index 5dd48aa32f..0000000000
--- a/Os/SimpleQueueRegistry.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SimpleQueueRegistry.cpp
- *
- *  Created on: Apr 7, 2016
- *      Author: tcanham
- */
-
-#if FW_QUEUE_REGISTRATION
-
-#include <Os/SimpleQueueRegistry.hpp>
-
-namespace Os {
-
-    SimpleQueueRegistry::SimpleQueueRegistry() {
-    }
-
-    SimpleQueueRegistry::~SimpleQueueRegistry() {
-    }
-
-    void SimpleQueueRegistry::regQueue(Queue* obj) {
-    }
-
-    void SimpleQueueRegistry::dump() {
-    }
-
-} /* namespace Os */
-
-#endif
diff --git a/Os/SimpleQueueRegistry.hpp b/Os/SimpleQueueRegistry.hpp
deleted file mode 100644
index ddf1ef6804..0000000000
--- a/Os/SimpleQueueRegistry.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * \file
- * \author T. Canham
- * \brief Class declaration for a simple queue registry
- *
- * The simple object registry is meant to give a default implementation
- * and an example of a queue registry. When the registry is instantiated,
- * it registers itself with the setQueueRegistry() static method. When
- * queues in the system are instantiated, they will register themselves.
- * The registry can then query the instances about their names, sizes,
- * and high watermarks.
- *
- * \copyright
- * Copyright 2013-2016, by the California Institute of Technology.
- * ALL RIGHTS RESERVED.  United States Government Sponsorship
- * acknowledged.
- *
- */
-
-#ifndef SIMPLEQUEUEREGISTRY_HPP_
-#define SIMPLEQUEUEREGISTRY_HPP_
-
-#if FW_QUEUE_REGISTRATION
-
-#include <Os/Queue.hpp>
-
-namespace Os {
-
-    class SimpleQueueRegistry: public QueueRegistry {
-        public:
-            SimpleQueueRegistry(); //!< constructor
-            virtual ~SimpleQueueRegistry(); //!< destructor
-            void regQueue(Queue* obj); //!< method called by queue init() methods to register a new queue
-            void dump(); //!< dump list of queues and stats
-    };
-
-} /* namespace Os */
-
-#endif // FW_QUEUE_REGISTRATION
-
-#endif /* SIMPLEQUEUEREGISTRY_HPP_ */
diff --git a/Os/Stub/CMakeLists.txt b/Os/Stub/CMakeLists.txt
index 5f66a79921..658e51daa9 100644
--- a/Os/Stub/CMakeLists.txt
+++ b/Os/Stub/CMakeLists.txt
@@ -18,11 +18,34 @@ register_fprime_implementation(Os/File Os_File_Stub)
 ######## Mutex Stub ########
 set(SOURCE_FILES
     "${CMAKE_CURRENT_LIST_DIR}/Mutex.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/ConditionVariable.cpp"
 )
 register_fprime_module(Os_Mutex_Stub)
 register_fprime_implementation(Os/Mutex Os_Mutex_Stub "${CMAKE_CURRENT_LIST_DIR}/DefaultMutex.cpp")
 
-######## Console Stub ########
+#### Queue Stub ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Queue.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Queue.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Queue_Stub)
+register_fprime_implementation(Os/Queue Os_Queue_Stub "${CMAKE_CURRENT_LIST_DIR}/DefaultQueue.cpp")
+
+#### Task Stub ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Task.cpp"
+)
+set(HEADER_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/Task.hpp"
+)
+set(MOD_DEPS)
+register_fprime_module(Os_Task_Stub)
+register_fprime_implementation(Os/Task Os_Task_Stub "${CMAKE_CURRENT_LIST_DIR}/DefaultTask.cpp")
+
+#### Console Stub ####
 set(SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/Console.cpp"
 )
@@ -93,13 +116,36 @@ choose_fprime_implementation(Os/Console Os_Console_Test_Stub)
 register_fprime_ut(StubConsoleTest)
 
 
+#### Queue Stub Testing ####
+set(SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/Queue.cpp"
+)
+register_fprime_module(Os_Queue_Test_Stub)
+register_fprime_implementation(Os/Queue Os_Queue_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultQueue.cpp")
+
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubQueueTests.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/queue/QueueRules.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/../test/ut/queue/CommonTests.cpp"
+)
+set(UT_MOD_DEPS
+        Fw/Time
+        Os
+        STest
+)
+choose_fprime_implementation(Os/Queue Os_Queue_Test_Stub)
+register_fprime_ut(StubQueueTest)
+if (TARGET StubQueueTest)
+    target_include_directories(StubQueueTest PRIVATE "${CMAKE_CURRENT_LIST_DIR}/test/ut")
+endif ()
+
 #### Task Stub Testing ####
 set(SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/test/Task.cpp"
-        "${CMAKE_CURRENT_LIST_DIR}/test/DefaultTask.cpp"
+
 )
 register_fprime_module(Os_Task_Test_Stub)
-register_fprime_implementation(Os/Task Os_Task_Test_Stub)
+register_fprime_implementation(Os/Task Os_Task_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultTask.cpp")
 
 set(UT_SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubTaskTests.cpp"
@@ -107,7 +153,7 @@ set(UT_SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/../test/ut/task/TaskRules.cpp"
 )
 set(UT_MOD_DEPS
-        Fw/Time
+        Fw_Time
         Os
         Os_Models
         STest
@@ -118,6 +164,8 @@ register_fprime_ut(StubTaskTest)
 #### Mutex Stub Testing ####
 set(SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/test/Mutex.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/test/ConditionVariable.cpp"
+
 )
 register_fprime_module(Os_Mutex_Test_Stub)
 register_fprime_implementation(Os/Mutex Os_Mutex_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultMutex.cpp")
@@ -128,10 +176,12 @@ set(UT_SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/../test/ut/mutex/MutexRules.cpp"
 )
 set(UT_MOD_DEPS
+        Fw_Time
         Os
         Os_Models
         STest
 )
+choose_fprime_implementation(Os/Task Os_Task_Posix)
 choose_fprime_implementation(Os/Mutex Os_Mutex_Test_Stub)
 register_fprime_ut(StubMutexTest)
 
@@ -144,10 +194,9 @@ register_fprime_implementation(Os/FileSystem Os_FileSystem_Test_Stub "${CMAKE_CU
 
 set(UT_SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubFileSystemTests.cpp"
-        # "${CMAKE_CURRENT_LIST_DIR}/../test/ut/filesystem/CommonTests.cpp"
-        # "${CMAKE_CURRENT_LIST_DIR}/../test/ut/filesystem/FileSystemRules.cpp"
 )
 set(UT_MOD_DEPS
+        Fw_Time
         Os
         Os_Models
         STest
@@ -164,8 +213,6 @@ register_fprime_implementation(Os/Directory Os_Directory_Test_Stub "${CMAKE_CURR
 
 set(UT_SOURCE_FILES
         "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubDirectoryTests.cpp"
-        # "${CMAKE_CURRENT_LIST_DIR}/../test/ut/directory/CommonTests.cpp"
-        # "${CMAKE_CURRENT_LIST_DIR}/../test/ut/directory/DirectoryRules.cpp"
 )
 set(UT_MOD_DEPS
         Os
@@ -175,3 +222,28 @@ set(UT_MOD_DEPS
 choose_fprime_implementation(Os/Directory Os_Directory_Test_Stub)
 register_fprime_ut(StubDirectoryTest)
 
+## Condition variable tests
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubConditionTests.cpp"
+)
+set(UT_MOD_DEPS
+        Fw_Time
+)
+choose_fprime_implementation(Os/Task Os_Task_Posix)
+choose_fprime_implementation(Os/Mutex Os_Mutex_Test_Stub)
+register_fprime_ut(StubConditionVariableTest)
+
+## Stubs test: checks that all the no-op stubs can be selected and compile ##
+set(UT_SOURCE_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubTests.cpp"
+)
+set(UT_MOD_DEPS
+        Os
+)
+choose_fprime_implementation(Os/Task Os_Task_Stub)
+choose_fprime_implementation(Os/Mutex Os_Mutex_Stub)
+choose_fprime_implementation(Os/File Os_File_Stub)
+choose_fprime_implementation(Os/Console Os_Console_Stub)
+choose_fprime_implementation(Os/FileSystem Os_FileSystem_Stub)
+choose_fprime_implementation(Os/Directory Os_Directory_Stub)
+register_fprime_ut(StubTest)
diff --git a/Os/Stub/ConditionVariable.cpp b/Os/Stub/ConditionVariable.cpp
new file mode 100644
index 0000000000..1298f2ae09
--- /dev/null
+++ b/Os/Stub/ConditionVariable.cpp
@@ -0,0 +1,28 @@
+// ======================================================================
+// \title Os/Stub/ConditionVariable.cpp
+// \brief Stub implementations for Os::ConditionVariable
+// ======================================================================
+#include "Os/Stub/ConditionVariable.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+namespace Stub {
+namespace Mutex {
+
+void StubConditionVariable::wait(Os::Mutex& mutex) {
+    FW_ASSERT(0);
+}
+void StubConditionVariable::notify() {
+    FW_ASSERT(0);
+}
+void StubConditionVariable::notifyAll() {
+    FW_ASSERT(0);
+}
+
+ConditionVariableHandle* StubConditionVariable::getHandle() {
+    return &m_handle;
+}
+
+}
+}
+}
diff --git a/Os/Stub/ConditionVariable.hpp b/Os/Stub/ConditionVariable.hpp
new file mode 100644
index 0000000000..1093760b3e
--- /dev/null
+++ b/Os/Stub/ConditionVariable.hpp
@@ -0,0 +1,49 @@
+// ======================================================================
+// \title Os/Stub/ConditionVariable.hpp
+// \brief Stub definitions for Os::ConditionVariable
+// ======================================================================
+#ifndef OS_STUB_CONDITION_VARIABLE_HPP
+#define OS_STUB_CONDITION_VARIABLE_HPP
+#include <Os/Condition.hpp>
+
+namespace Os {
+namespace Stub {
+namespace Mutex {
+
+struct StubConditionVariableHandle : public ConditionVariableHandle {};
+
+//! \brief Stub implementation of Os::ConditionVariable
+//!
+//! Stub implementation of `ConditionVariable` for use as a delegate class handling error-only file operations.
+//!
+class StubConditionVariable : public ConditionVariableInterface {
+  public:
+    //! \brief constructor
+    //!
+    StubConditionVariable() = default;
+
+    //! \brief destructor
+    //!
+    ~StubConditionVariable() override = default;
+
+    //! \brief wait releasing mutex
+    void wait(Os::Mutex& mutex) override;
+
+    //! \brief notify a single waiter
+    void notify() override;
+
+    //! \brief notify all current waiters
+    void notifyAll() override;
+
+    //! \brief get handle
+    ConditionVariableHandle* getHandle() override;
+
+  private:
+    //! Handle for PosixMutex
+    StubConditionVariableHandle m_handle;
+};
+
+}  // namespace Mutex
+}  // namespace Posix
+}  // namespace Os
+#endif  // OS_STUB_CONDITION_VARIABLE_HPP
diff --git a/Os/Stub/DefaultDirectory.cpp b/Os/Stub/DefaultDirectory.cpp
index 6224651bf5..6fd986c6bb 100644
--- a/Os/Stub/DefaultDirectory.cpp
+++ b/Os/Stub/DefaultDirectory.cpp
@@ -9,7 +9,7 @@ namespace Os {
 //! \brief get a delegate for DirectoryInterface that intercepts calls for stub Directory usage
 //! \param aligned_new_memory: aligned memory to fill
 //! \return: pointer to delegate
-DirectoryInterface *DirectoryInterface::getDelegate(HandleStorage& aligned_placement_new_memory) {
+DirectoryInterface *DirectoryInterface::getDelegate(DirectoryHandleStorage& aligned_placement_new_memory) {
     return Os::Delegate::makeDelegate<DirectoryInterface, Os::Stub::Directory::StubDirectory>(
             aligned_placement_new_memory
     );
diff --git a/Os/Stub/DefaultFileSystem.cpp b/Os/Stub/DefaultFileSystem.cpp
index 58a3527d23..29b15670b0 100644
--- a/Os/Stub/DefaultFileSystem.cpp
+++ b/Os/Stub/DefaultFileSystem.cpp
@@ -10,7 +10,7 @@ namespace Os {
 //! \param aligned_new_memory: aligned memory to fill
 //! \param to_copy: pointer to copy-constructor input
 //! \return: pointer to delegate
-FileSystemInterface *FileSystemInterface::getDelegate(HandleStorage& aligned_placement_new_memory) {
+FileSystemInterface *FileSystemInterface::getDelegate(FileSystemHandleStorage& aligned_placement_new_memory) {
     return Os::Delegate::makeDelegate<FileSystemInterface, Os::Stub::FileSystem::StubFileSystem>(
             aligned_placement_new_memory
     );
diff --git a/Os/Stub/DefaultMutex.cpp b/Os/Stub/DefaultMutex.cpp
index 56381815f3..afded661f1 100644
--- a/Os/Stub/DefaultMutex.cpp
+++ b/Os/Stub/DefaultMutex.cpp
@@ -3,6 +3,7 @@
 // \brief sets default Os::Mutex to no-op stub implementation via linker
 // ======================================================================
 #include "Os/Stub/Mutex.hpp"
+#include "Os/Stub/ConditionVariable.hpp"
 #include "Os/Delegate.hpp"
 namespace Os {
 
@@ -15,4 +16,13 @@ MutexInterface *MutexInterface::getDelegate(HandleStorage& aligned_new_memory) {
             aligned_new_memory
     );
 }
+
+//! \brief get a delegate for condition variable
+//! \param aligned_new_memory: aligned memory to fill
+//! \return: pointer to delegate
+ConditionVariableInterface *ConditionVariableInterface::getDelegate(ConditionVariableHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<ConditionVariableInterface, Os::Stub::Mutex::StubConditionVariable, ConditionVariableHandleStorage>(
+        aligned_new_memory
+    );
+}
 }
diff --git a/Os/Stub/DefaultQueue.cpp b/Os/Stub/DefaultQueue.cpp
new file mode 100644
index 0000000000..5f2111e0c5
--- /dev/null
+++ b/Os/Stub/DefaultQueue.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Stub/DefaultQueue.cpp
+// \brief sets default Os::Queue to stub implementation via linker
+// ======================================================================
+#include "Os/Queue.hpp"
+#include "Os/Stub/Queue.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+QueueInterface* QueueInterface::getDelegate(QueueHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<QueueInterface, Os::Stub::Queue::StubQueue>(aligned_new_memory);
+}
+}
diff --git a/Os/Stub/DefaultTask.cpp b/Os/Stub/DefaultTask.cpp
new file mode 100644
index 0000000000..0719b00980
--- /dev/null
+++ b/Os/Stub/DefaultTask.cpp
@@ -0,0 +1,21 @@
+// ======================================================================
+// \title Os/Stub/test/DefaultTask.cpp
+// \brief sets default Os::Task to test stub implementation via linker
+// ======================================================================
+#include <cerrno>
+#include "Os/Task.hpp"
+#include "Os/Stub/Task.hpp"
+#include "Os/Delegate.hpp"
+#include <sys/time.h>
+
+namespace Os {
+    Os::Task::Status TaskInterface::delay(Fw::Time interval) {
+        FW_ASSERT(0);
+        return Os::Task::Status::UNKNOWN_ERROR;
+    }
+
+    TaskInterface* TaskInterface::getDelegate(HandleStorage& aligned_new_memory) {
+        return Os::Delegate::makeDelegate<TaskInterface, Os::Stub::Task::StubTask>(aligned_new_memory);
+    }
+
+}
diff --git a/Os/Stub/Queue.cpp b/Os/Stub/Queue.cpp
new file mode 100644
index 0000000000..2aadfce890
--- /dev/null
+++ b/Os/Stub/Queue.cpp
@@ -0,0 +1,44 @@
+// ======================================================================
+// \title Os/Stub/Queue.cpp
+// \brief stub implementation for Os::Queue
+// ======================================================================
+#include "Queue.hpp"
+
+namespace Os {
+namespace Stub {
+namespace Queue {
+
+QueueInterface::Status StubQueue::create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) {
+    return QueueInterface::Status::UNKNOWN_ERROR;
+}
+
+QueueInterface::Status StubQueue::send(const U8* buffer,
+                                       FwSizeType size,
+                                       FwQueuePriorityType priority,
+                                       QueueInterface::BlockingType blockType) {
+    return QueueInterface::Status::UNINITIALIZED;
+}
+
+QueueInterface::Status StubQueue::receive(U8* destination,
+                                          FwSizeType capacity,
+                                          QueueInterface::BlockingType blockType,
+                                          FwSizeType& actualSize,
+                                          FwQueuePriorityType& priority) {
+    return QueueInterface::Status::UNINITIALIZED;
+}
+
+FwSizeType StubQueue::getMessagesAvailable() const {
+    return 0;
+}
+
+FwSizeType StubQueue::getMessageHighWaterMark() const {
+    return 0;
+}
+
+QueueHandle* StubQueue::getHandle() {
+    return &this->m_handle;
+}
+
+}  // namespace Queue
+}  // namespace Stub
+}  // namespace Os
diff --git a/Os/Stub/Queue.hpp b/Os/Stub/Queue.hpp
new file mode 100644
index 0000000000..810bf08b73
--- /dev/null
+++ b/Os/Stub/Queue.hpp
@@ -0,0 +1,94 @@
+// ======================================================================
+// \title Os/Stub/Queue.hpp
+// \brief stub definitions for Os::Queue
+// ======================================================================
+#ifndef OS_STUB_QUEUE_HPP
+#define OS_STUB_QUEUE_HPP
+#include "Os/Queue.hpp"
+
+namespace Os {
+namespace Stub {
+namespace Queue {
+
+struct StubQueueHandle : public QueueHandle {};
+
+//! \brief stub queue implementation with injectable statuses
+class StubQueue : public QueueInterface {
+  public:
+    //! \brief default queue interface constructor
+    StubQueue() = default;
+
+    //! \brief default queue destructor
+    virtual ~StubQueue() = default;
+
+    //! \brief copy constructor is forbidden
+    StubQueue(const QueueInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    StubQueue(const QueueInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    StubQueue& operator=(const QueueInterface& other) override = delete;
+
+    //! \brief create queue storage
+    //!
+    //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each.
+    //! \param name: name of queue
+    //! \param depth: depth of queue in number of messages
+    //! \param messageSize: size of an individual message
+    //! \return: status of the creation
+    Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override;
+
+    //! \brief send a message into the queue
+    //!
+    //! Send a message into the queue, providing the message data, size, priority, and blocking type. When
+    //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error
+    //! status on queue full.
+    //!
+    //! \param buffer: message data
+    //! \param size: size of message data
+    //! \param priority: priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return: status of the send
+    Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) override;
+
+    //! \brief receive a message from the queue
+    //!
+    //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type.
+    //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an
+    //! error status on queue empty. Actual size received and priority of message is set on success status.
+    //!
+    //! \param destination: destination for message data
+    //! \param capacity: maximum size of message data
+    //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty
+    //! \param actualSize: (output) actual size of message read
+    //! \param priority: (output) priority of message read
+    //! \return: status of the send
+    Status receive(U8* destination,
+                   FwSizeType capacity,
+                   BlockingType blockType,
+                   FwSizeType& actualSize,
+                   FwQueuePriorityType& priority) override;
+
+    //! \brief get number of messages available
+    //!
+    //! \return number of messages available
+    FwSizeType getMessagesAvailable() const override;
+
+    //! \brief get maximum messages stored at any given time
+    //!
+    //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for this
+    //! queue.
+    //! \return queue message high-water mark
+    FwSizeType getMessageHighWaterMark() const override;
+
+    QueueHandle* getHandle() override;
+
+    StubQueueHandle m_handle;
+};
+
+}  // namespace Queue
+}  // namespace Stub
+}  // namespace Os
+
+#endif  // OS_STUB_QUEUE_HPP
diff --git a/Os/Stub/Task.cpp b/Os/Stub/Task.cpp
new file mode 100644
index 0000000000..29b404095a
--- /dev/null
+++ b/Os/Stub/Task.cpp
@@ -0,0 +1,36 @@
+// ======================================================================
+// \title Os/Stub/Task.cpp
+// \brief stub implementations for Os::Task
+// ======================================================================
+#include "Os/Stub/Task.hpp"
+namespace Os {
+namespace Stub {
+namespace Task {
+
+void StubTask::onStart() {
+
+}
+
+Os::TaskInterface::Status StubTask::join() {
+    return Os::TaskInterface::Status::UNKNOWN_ERROR;
+}
+
+void StubTask::suspend(Os::TaskInterface::SuspensionType suspensionType) {}
+
+void StubTask::resume() {}
+
+Os::TaskHandle *StubTask::getHandle() {
+    return nullptr;
+}
+
+Os::TaskInterface::Status StubTask::start(const Os::TaskInterface::Arguments &arguments) {
+    return Os::TaskInterface::Status::UNKNOWN_ERROR;
+}
+
+bool StubTask::isCooperative() {
+    return true;
+}
+
+}
+}
+}
diff --git a/Os/Stub/Task.hpp b/Os/Stub/Task.hpp
new file mode 100644
index 0000000000..daffabec19
--- /dev/null
+++ b/Os/Stub/Task.hpp
@@ -0,0 +1,79 @@
+// ======================================================================
+// \title Os/Stub/Task.hpp
+// \brief stub definitions for Os::Task
+// ======================================================================
+#include "Os/Task.hpp"
+
+#ifndef OS_STUB_TASK_HPP
+#define OS_STUB_TASK_HPP
+namespace Os {
+namespace Stub {
+namespace Task {
+
+//! Test task handle
+class StubTaskHandle : public TaskHandle {};
+
+//! Implementation of task
+class StubTask : public TaskInterface {
+  public:
+    //! Constructor
+    StubTask() = default;
+
+    //! Destructor
+    ~StubTask() override = default;
+
+    //! \brief perform required task start actions
+    void onStart() override;
+
+    //! \brief block until the task has ended
+    //!
+    //! Blocks the current (calling) task until this task execution has ended. Callers should ensure that any
+    //! signals required to stop this task have already been emitted or will be emitted by another task.
+    //!
+    //! \return status of the block
+    Status join() override;
+
+    //! \brief suspend the task given the suspension type
+    //!
+    //! Suspends the task. Some implementations track if the suspension of a task was intentional or
+    //! unintentional. The supplied `suspensionType` parameter indicates that this was intentional or
+    //! unintentional. The type of suspension is also returned when calling `isSuspended`.
+    //!
+    //! \param suspensionType intentionality of the suspension
+    void suspend(SuspensionType suspensionType) override;
+
+    //! \brief resume a suspended task
+    //!
+    //! Resumes this task. Not started, running, and exited tasks take no action.
+    //!
+    void resume() override;
+
+    //! \brief return the underlying task handle (implementation specific)
+    //! \return internal task handle representation
+    TaskHandle* getHandle() override;
+
+    //! \brief determine if the task requires cooperative multitasking
+    //!
+    //! Some task implementations require cooperative multitasking where the task execution is run by a user
+    //! defined task scheduler and not the operating system task scheduler. These tasks cooperatively on
+    //! multitask by doing one unit of work and return from the function.
+    //!
+    //! This function indicates if the task requires cooperative support.
+    //! The default implementation returns false.
+    //!
+    //! \return true when the task expects cooperation, false otherwise
+    bool isCooperative() override;
+
+    //! \brief start the task
+    //!
+    //! Starts the task given the supplied arguments.
+    //!
+    //! \param arguments: arguments supplied to the task start call
+    //! \return status of the task start
+    Status start(const Arguments& arguments) override;
+};
+
+}
+}
+}
+#endif // End OS_STUB_TASK_HPP
diff --git a/Os/Task.cpp b/Os/Task.cpp
index caa36ed8ef..497ccfdd0b 100644
--- a/Os/Task.cpp
+++ b/Os/Task.cpp
@@ -32,9 +32,9 @@ void Task::TaskRoutineWrapper::run(void* wrapper_pointer) {
     wrapper.m_task.m_lock.lock();
     Task::State state = wrapper.m_task.m_state;
     wrapper.m_task.m_lock.unlock();
-
+    FW_ASSERT(state != Task::State::NOT_STARTED);
     // Run once start code
-    if (state == Task::State::NOT_STARTED) {
+    if (state == Task::State::STARTING) {
         wrapper.m_task.m_lock.lock();
         wrapper.m_task.m_state = Task::State::RUNNING;
         wrapper.m_task.m_lock.unlock();
@@ -95,6 +95,7 @@ Task::Status Task::start(const Task::Arguments& arguments) {
     FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
     FW_ASSERT(arguments.m_routine != nullptr);
     this->m_name = arguments.m_name;
+    this->m_state = State::STARTING;
 
     Arguments wrapped_arguments = arguments;
     // Intercept routine and argument with the local wrapper
@@ -131,7 +132,7 @@ Task::Status Task::join() {
     FW_ASSERT(&this->m_delegate == reinterpret_cast<TaskInterface*>(&this->m_handle_storage[0]));
     Task::Status status = Task::Status::INVALID_STATE;
     Task::State state = this->getState();
-    if (state == Task::RUNNING) {
+    if (state == Task::RUNNING || state == STARTING) {
         status = this->m_delegate.join();
         this->m_lock.lock();
         if (status == Task::Status::OP_OK) {
diff --git a/Os/Task.hpp b/Os/Task.hpp
index 1c88779858..dd9a5883a1 100644
--- a/Os/Task.hpp
+++ b/Os/Task.hpp
@@ -47,6 +47,7 @@ namespace Os {
 
             enum State {
                 NOT_STARTED,
+                STARTING,
                 RUNNING,
                 SUSPENDED_INTENTIONALLY,
                 SUSPENDED_UNINTENTIONALLY,
diff --git a/Svc/FileDownlink/FileDownlink.cpp b/Svc/FileDownlink/FileDownlink.cpp
index ff3622188b..7cb4efd3a9 100644
--- a/Svc/FileDownlink/FileDownlink.cpp
+++ b/Svc/FileDownlink/FileDownlink.cpp
@@ -56,12 +56,12 @@ namespace Svc {
     this->m_cycleTime = cycleTime;
     this->m_configured = true;
 
-    Os::Queue::QueueStatus stat = m_fileQueue.create(
+    Os::Queue::Status stat = m_fileQueue.create(
       Os::QueueString("fileDownlinkQueue"),
-      static_cast<NATIVE_INT_TYPE>(fileQueueDepth),
-      sizeof(struct FileEntry)
+      static_cast<FwSizeType>(fileQueueDepth),
+      static_cast<FwSizeType>(sizeof(struct FileEntry))
     );
-    FW_ASSERT(stat == Os::Queue::QUEUE_OK, stat);
+    FW_ASSERT(stat == Os::Queue::OP_OK, stat);
   }
 
   void FileDownlink ::
@@ -89,17 +89,17 @@ namespace Svc {
     switch(this->m_mode.get())
     {
       case Mode::IDLE: {
-        NATIVE_INT_TYPE real_size = 0;
-        NATIVE_INT_TYPE prio = 0;
-        Os::Queue::QueueStatus stat = m_fileQueue.receive(
+        FwSizeType real_size = 0;
+        FwQueuePriorityType prio = 0;
+        Os::Queue::Status stat = m_fileQueue.receive(
           reinterpret_cast<U8*>(&this->m_curEntry),
-          sizeof(this->m_curEntry),
+          static_cast<FwSizeType>(sizeof(this->m_curEntry)),
+          Os::Queue::BlockingType::NONBLOCKING,
           real_size,
-          prio,
-          Os::Queue::QUEUE_NONBLOCKING
+          prio
         );
 
-        if(stat != Os::Queue::QUEUE_OK || sizeof(this->m_curEntry) != real_size) {
+        if(stat != Os::Queue::Status::OP_OK || sizeof(this->m_curEntry) != real_size) {
           return;
         }
 
@@ -161,9 +161,9 @@ namespace Svc {
     (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), static_cast<FwSizeType>(sizeof(entry.srcFilename)));
     (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), static_cast<FwSizeType>(sizeof(entry.destFilename)));
 
-    Os::Queue::QueueStatus status = m_fileQueue.send(reinterpret_cast<U8*>(&entry), sizeof(entry), 0, Os::Queue::QUEUE_NONBLOCKING);
+    Os::Queue::Status status = m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0, Os::Queue::BlockingType::NONBLOCKING);
 
-    if(status != Os::Queue::QUEUE_OK) {
+    if(status != Os::Queue::Status::OP_OK) {
       return SendFileResponse(SendFileStatus::STATUS_ERROR, std::numeric_limits<U32>::max());
     }
     return SendFileResponse(SendFileStatus::STATUS_OK, entry.context);
@@ -234,9 +234,9 @@ namespace Svc {
     (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), static_cast<FwSizeType>(sizeof(entry.srcFilename)));
     (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), static_cast<FwSizeType>(sizeof(entry.destFilename)));
 
-    Os::Queue::QueueStatus status = m_fileQueue.send(reinterpret_cast<U8*>(&entry), sizeof(entry), 0, Os::Queue::QUEUE_NONBLOCKING);
+    Os::Queue::Status status = m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0, Os::Queue::BlockingType::NONBLOCKING);
 
-    if(status != Os::Queue::QUEUE_OK) {
+    if(status != Os::Queue::Status::OP_OK) {
       this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
     }
   }
@@ -267,9 +267,9 @@ namespace Svc {
     (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), static_cast<FwSizeType>(sizeof(entry.srcFilename)));
     (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), static_cast<FwSizeType>(sizeof(entry.destFilename)));
 
-    Os::Queue::QueueStatus status = m_fileQueue.send(reinterpret_cast<U8*>(&entry), sizeof(entry), 0, Os::Queue::QUEUE_NONBLOCKING);
+    Os::Queue::Status status = m_fileQueue.send(reinterpret_cast<U8*>(&entry), static_cast<FwSizeType>(sizeof(entry)), 0, Os::Queue::BlockingType::NONBLOCKING);
 
-    if(status != Os::Queue::QUEUE_OK) {
+    if(status != Os::Queue::Status::OP_OK) {
       this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
     }
   }
diff --git a/Svc/Health/HealthComponentImpl.cpp b/Svc/Health/HealthComponentImpl.cpp
index 01f1cb4bfd..3121a25328 100644
--- a/Svc/Health/HealthComponentImpl.cpp
+++ b/Svc/Health/HealthComponentImpl.cpp
@@ -36,9 +36,9 @@ namespace Svc {
         }
     }
 
-    void HealthImpl::init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance) {
+    void HealthImpl::init(const FwSizeType queueDepth, const NATIVE_INT_TYPE instance) {
         HealthComponentBase::init(queueDepth, instance);
-        this->queue_depth = static_cast<U32>(queueDepth);
+        this->queue_depth = queueDepth;
 
     }
 
diff --git a/Svc/Health/HealthComponentImpl.hpp b/Svc/Health/HealthComponentImpl.hpp
index abaf9aa666..b517da361a 100644
--- a/Svc/Health/HealthComponentImpl.hpp
+++ b/Svc/Health/HealthComponentImpl.hpp
@@ -61,7 +61,7 @@ namespace Svc {
             //!
             //!  \param queueDepth Depth of queue
             //!  \param instance The instance number
-            void init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance);
+            void init(const FwSizeType queueDepth, const NATIVE_INT_TYPE instance);
 
             //! \brief Set ping entry tables
             //!
@@ -150,7 +150,7 @@ namespace Svc {
             U32 m_watchDogCode; //!< stores code used for watchdog stroking
             U32 m_warnings; //!< number of slip warnings issued
             Fw::Enabled m_enabled; //!< if the pinger is enabled
-            U32 queue_depth; //!< queue depth passed by user
+            FwSizeType queue_depth; //!< queue depth passed by user
 
     };
 
diff --git a/Utils/LockGuard.cpp b/Utils/LockGuard.cpp
index 9aeaa1a83b..7178f6f156 100644
--- a/Utils/LockGuard.cpp
+++ b/Utils/LockGuard.cpp
@@ -1,4 +1,4 @@
-// ====================================================================== 
+// ======================================================================
 // \title  LockGuard.cpp
 // \author vwong
 // \brief  cpp file for a lock guard utility class
diff --git a/Utils/Types/CMakeLists.txt b/Utils/Types/CMakeLists.txt
index 5e098fb115..1287b8c71a 100644
--- a/Utils/Types/CMakeLists.txt
+++ b/Utils/Types/CMakeLists.txt
@@ -20,9 +20,9 @@ set(UT_MOD_DEPS
     Fw/Types
 )
 set(UT_SOURCE_FILES
-    "test/ut/CircularBuffer/CircularState.cpp"
-    "test/ut/CircularBuffer/CircularRules.cpp"
-    "test/ut/CircularBuffer/Main.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/test/ut/CircularBuffer/CircularState.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/test/ut/CircularBuffer/CircularRules.cpp"
+    "${CMAKE_CURRENT_LIST_DIR}/test/ut/CircularBuffer/Main.cpp"
 )
 # STest Includes for this UT
 register_fprime_ut("Types_Circular_Buffer_ut_exe")
diff --git a/Utils/Types/Queue.cpp b/Utils/Types/Queue.cpp
index 1a32400de6..23bfa989f2 100644
--- a/Utils/Types/Queue.cpp
+++ b/Utils/Types/Queue.cpp
@@ -63,4 +63,4 @@ NATIVE_UINT_TYPE Queue::getQueueSize() const {
 }
 
 
-}  // namespace Types
\ No newline at end of file
+}  // namespace Types
diff --git a/cmake/platform/Darwin.cmake b/cmake/platform/Darwin.cmake
index 35a0049320..e31696aa1c 100644
--- a/cmake/platform/Darwin.cmake
+++ b/cmake/platform/Darwin.cmake
@@ -24,6 +24,7 @@ choose_fprime_implementation(Os/Directory Os/Directory/Posix)
 choose_fprime_implementation(Os/Console Os/Console/Posix)
 choose_fprime_implementation(Os/Task Os/Task/Posix)
 choose_fprime_implementation(Os/Mutex Os/Mutex/Posix)
+choose_fprime_implementation(Os/Queue Os/Generic/PriorityQueue)
 
 # Add linux include path which is compatible with Darwin for PlatformTypes.hpp
 include_directories(SYSTEM "${CMAKE_CURRENT_LIST_DIR}/types")
diff --git a/cmake/platform/Linux.cmake b/cmake/platform/Linux.cmake
index 9b3fc41508..ddffd42699 100644
--- a/cmake/platform/Linux.cmake
+++ b/cmake/platform/Linux.cmake
@@ -15,6 +15,7 @@ choose_fprime_implementation(Os/Directory Os/Directory/Posix)
 choose_fprime_implementation(Os/Console Os/Console/Posix)
 choose_fprime_implementation(Os/Task Os/Task/Posix)
 choose_fprime_implementation(Os/Mutex Os/Mutex/Posix)
+choose_fprime_implementation(Os/Queue Os/Generic/PriorityQueue)
 
 # Use common linux setup
 add_definitions(-DTGT_OS_TYPE_LINUX)
diff --git a/cmake/platform/types/PlatformTypes.h b/cmake/platform/types/PlatformTypes.h
index 725ce9528a..ca5962779b 100644
--- a/cmake/platform/types/PlatformTypes.h
+++ b/cmake/platform/types/PlatformTypes.h
@@ -56,6 +56,12 @@ typedef uint64_t PlatformSizeType;
 typedef PlatformIntType PlatformAssertArgType;
 #define PRI_PlatformAssertArgType PRI_PlatformIntType
 
+typedef PlatformIntType PlatformTaskPriorityType;
+#define PRI_PlatformTaskPriorityType PRI_PlatformIntType
+
+typedef PlatformIntType PlatformQueuePriorityType;
+#define PRI_PlatformQueuePriorityType PRI_PlatformIntType
+
 // Linux/Darwin definitions for pointer have various sizes across platforms
 // and since these definitions need to be consistent we must ask the size.
 #ifndef PLATFORM_POINTER_CAST_TYPE_DEFINED
diff --git a/config/FpConfig.h b/config/FpConfig.h
index c6e0e8db37..f23a4de907 100644
--- a/config/FpConfig.h
+++ b/config/FpConfig.h
@@ -43,6 +43,14 @@ typedef PlatformIntType FwNativeIntType;
 typedef PlatformUIntType FwNativeUIntType;
 #define PRI_FwNativeUIntType PRI_PlatformUIntType
 
+// Task priority type
+typedef PlatformTaskPriorityType FwTaskPriorityType;
+#define PRI_FwTaskPriorityType PRI_PlatformTaskPriorityType
+
+// Queue priority type
+typedef PlatformQueuePriorityType FwQueuePriorityType;
+#define PRI_FwQueuePriorityType PRI_PlatformQueuePriorityType
+
 // The type used to serialize a size value
 typedef U16 FwSizeStoreType;
 #define PRI_FwSizeStoreType PRIu16
@@ -95,10 +103,6 @@ typedef U32 FwPrmIdType;
 typedef U16 FwTlmPacketizeIdType;
 #define PRI_FwTlmPacketizeIdType PRIu16
 
-// The type of a queue priority
-typedef I32 FwQueuePriorityType;
-#define PRI_FwQueuePriorityType PRId32
-
 // The type of a data product identifier
 typedef U32 FwDpIdType;
 #define PRI_FwDpIdType PRIu32
@@ -385,7 +389,11 @@ typedef FwIndexType FwQueueSizeType;
 // OS configuration
 
 #ifndef FW_HANDLE_MAX_SIZE
-#define FW_HANDLE_MAX_SIZE 72  //!< Maximum size of a handle for OS resources (files, queues, locks, etc.)
+#define FW_HANDLE_MAX_SIZE 104  //!< Maximum size of a handle for OS resources (files, locks, etc.)
+#endif
+
+#ifndef FW_QUEUE_HANDLE_MAX_SIZE
+#define FW_QUEUE_HANDLE_MAX_SIZE 464  //!< Maximum size of a handle for OS queues
 #endif
 
 #ifndef FW_DIRECTORY_HANDLE_MAX_SIZE
@@ -396,6 +404,10 @@ typedef FwIndexType FwQueueSizeType;
 #define FW_FILESYSTEM_HANDLE_MAX_SIZE 72  //!< Maximum size of a handle for OS resources (files, queues, locks, etc.)
 #endif
 
+#ifndef FW_CONDITION_VARIABLE_HANDLE_MAX_SIZE
+#define FW_CONDITION_VARIABLE_HANDLE_MAX_SIZE 56  //!< Maximum size of a handle for OS condition variables
+#endif
+
 #ifndef FW_HANDLE_ALIGNMENT
 #define FW_HANDLE_ALIGNMENT 8  //!< Alignment of handle storage
 #endif
diff --git a/requirements.txt b/requirements.txt
index dfc036df53..5a6dd71144 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,18 +18,18 @@ fprime-fpl-convert-xml==1.0.3
 fprime-fpl-extract-xml==1.0.3
 fprime-fpl-layout==1.0.3
 fprime-fpl-write-pic==1.0.3
-fprime-fpp-check==2.2.0a3
-fprime-fpp-depend==2.2.0a3
-fprime-fpp-filenames==2.2.0a3
-fprime-fpp-format==2.2.0a3
-fprime-fpp-from-xml==2.2.0a3
-fprime-fpp-locate-defs==2.2.0a3
-fprime-fpp-locate-uses==2.2.0a3
-fprime-fpp-syntax==2.2.0a3
-fprime-fpp-to-cpp==2.2.0a3
-fprime-fpp-to-dict==2.2.0a3
-fprime-fpp-to-json==2.2.0a3
-fprime-fpp-to-xml==2.2.0a3
+fprime-fpp-check==v2.2.0a4
+fprime-fpp-depend==2.2.0a4
+fprime-fpp-filenames==2.2.0a4
+fprime-fpp-format==2.2.0a4
+fprime-fpp-from-xml==2.2.0a4
+fprime-fpp-locate-defs==2.2.0a4
+fprime-fpp-locate-uses==2.2.0a4
+fprime-fpp-syntax==2.2.0a4
+fprime-fpp-to-cpp==2.2.0a4
+fprime-fpp-to-dict==2.2.0a4
+fprime-fpp-to-json==2.2.0a4
+fprime-fpp-to-xml==2.2.0a4
 fprime-gds==3.4.4a3
 fprime-tools==v3.4.5a1
 fprime-visual==1.0.2


Test patch:
diff --git a/FppTest/state_machine/test/ut/SmTestTester.cpp b/FppTest/state_machine/test/ut/SmTestTester.cpp
index ebca73c4a0..b16b77fa3d 100644
--- a/FppTest/state_machine/test/ut/SmTestTester.cpp
+++ b/FppTest/state_machine/test/ut/SmTestTester.cpp
@@ -68,7 +68,7 @@ void SmTestTester::schedIn_OK() {
 void SmTestTester ::
     dispatchAll()
   {
-    while (this->component.m_queue.getNumMsgs() > 0)
+    while (this->component.m_queue.getMessagesAvailable() > 0)
         this->component.doDispatch();
   }
 
diff --git a/Os/Generic/Types/test/ut/MaxHeap/MaxHeapTest.cpp b/Os/Generic/Types/test/ut/MaxHeap/MaxHeapTest.cpp
new file mode 100644
index 0000000000..434b0f3dc1
--- /dev/null
+++ b/Os/Generic/Types/test/ut/MaxHeap/MaxHeapTest.cpp
@@ -0,0 +1,219 @@
+#include "Os/Generic/Types/MaxHeap.hpp"
+#include <gtest/gtest.h>
+#include <cstdio>
+#include <cstring>
+
+
+#define DEPTH 5
+#define DATA_SIZE 3
+
+TEST(Nominal, Creation) {
+    bool ret;
+    {
+        Types::MaxHeap heap;
+        ret = heap.create(0);
+        ASSERT_TRUE(ret);
+    }
+    {
+        Types::MaxHeap heap;
+        ret = heap.create(1000000);
+        ASSERT_TRUE(ret);
+    }
+    {
+        Types::MaxHeap heap;
+        ret = heap.create(1);
+        ASSERT_TRUE(ret);
+    }
+    {
+        Types::MaxHeap heap;
+        ret = heap.create(DEPTH);
+        ASSERT_TRUE(ret);
+    }
+    {
+        Types::MaxHeap heap;
+        ret = heap.create(DEPTH);
+        ASSERT_TRUE(ret);
+    }
+}
+
+TEST(Nominal, Empty) {
+    bool ret;
+    Types::MaxHeap heap;
+    ret = heap.create(DEPTH);
+    ASSERT_TRUE(ret);
+
+
+    FwQueuePriorityType value;
+    FwSizeType id=0;
+
+    printf("Testing empty...\n");
+    ret = heap.pop(value, id);
+    ASSERT_EQ(id, 0);
+    ASSERT_FALSE(ret);
+    ret = heap.pop(value, id);
+    ASSERT_EQ(id, 0);
+    ASSERT_FALSE(ret);
+    ret = heap.pop(value, id);
+    ASSERT_EQ(id, 0);
+    ASSERT_FALSE(ret);
+}
+
+TEST(Nominal, PushPop) {
+    printf("Creating heap.\n");
+    bool ret;
+    Types::MaxHeap heap;
+    ret = heap.create(DEPTH);
+    ASSERT_TRUE(ret);
+
+
+    FwQueuePriorityType value;
+    FwSizeType size;
+    FwSizeType id=0;
+
+    printf("Testing push...\n");
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        //printf("Inserting value %d\n", ii);
+        ret = heap.push(ii, ii);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size,ii+1);
+    }
+    ret = heap.push(50, id);
+    ASSERT_FALSE(ret);
+    ret = heap.push(50, id);
+    ASSERT_FALSE(ret);
+    ret = heap.push(50, id);
+    ASSERT_FALSE(ret);
+    printf("Passed.\n");
+
+    printf("Testing pop...\n");
+    //heap.print();
+    for(FwQueuePriorityType ii = DEPTH-1; ii >= 0; --ii) {
+        ret = heap.pop(value, id);
+        ASSERT_TRUE(ret);
+        ASSERT_EQ(id, static_cast<FwSizeType>(ii));
+        size = heap.getSize();
+        ASSERT_EQ(size, static_cast<FwSizeType>(ii));
+        //printf("Heap state after pop:\n");
+        //heap.print();
+        //printf("Got value %d\n", value);
+        ASSERT_EQ(value, ii);
+    }
+    ret = heap.pop(value, id);
+    ASSERT_FALSE(ret);
+    printf("Passed.\n");
+
+    printf("Testing random...\n");
+    FwQueuePriorityType values[DEPTH] = {56, 0, 500, 57, 5};
+    FwSizeType sorted[DEPTH] = {500, 57, 56, 5, 0};
+    //heap.print();
+    // Push values on in random order:
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        // Push next value in the list:
+        ret = heap.push(values[ii], id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, ii+1);
+
+        // Pop the top value:
+        ret = heap.pop(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, ii);
+        ASSERT_GE(value, values[ii]);
+
+        // Push the popped value:
+        ret = heap.push(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, ii+1);
+    }
+    ret = heap.push(values[0], id);
+    ASSERT_FALSE(ret);
+
+    // Get values out from largest to smallest:
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        // Pop the top value:
+        ret = heap.pop(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, (DEPTH-ii-1));
+        ASSERT_EQ(value, sorted[ii]);
+
+        // Push the top value:
+        ret = heap.push(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, (DEPTH-ii));
+
+        // Pop again:
+        ret = heap.pop(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, (DEPTH-ii-1));
+        ASSERT_EQ(value, sorted[ii]);
+    }
+    ret = heap.pop(value, id);
+    ASSERT_FALSE(ret);
+    printf("Passed.\n");
+
+    printf("Testing no priority...\n");
+    // For this test we expect things to come in fifo order
+    // since all the priorities are the same:
+    FwQueuePriorityType priorities[DEPTH] = {7, 7, 7, 7, 7};
+    FwSizeType data[DEPTH] = {43, 56, 47, 33, 11};
+    // Push values on in random order:
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        // Push next value in the list:
+        ret = heap.push(priorities[ii], data[ii]);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, ii+1);
+    }
+
+    // Get values out in FIFO order:
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        // Pop the top value:
+        ret = heap.pop(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, (DEPTH-ii-1));
+        ASSERT_EQ(value, priorities[ii]);
+        ASSERT_EQ(id, data[ii]);
+    }
+    printf("Passed.\n");
+
+    printf("Testing mixed priority...\n");
+    // For this test we expect things to come in fifo order
+    // for things of the same priority and in priority
+    // order for things of different priorities.
+    FwQueuePriorityType pries[DEPTH] = {1, 7, 100, 1, 7};
+    FwQueuePriorityType data2[DEPTH] = {4, 22, 99, 12344, 33};
+    FwQueuePriorityType orderedPries[DEPTH] = {100, 7, 7, 1, 1};
+    FwSizeType ordered[DEPTH] = {99, 22, 33, 4, 12344};
+    // Push values on in random order:
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        // Push next value in the list:
+        ret = heap.push(pries[ii], data2[ii]);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, ii+1);
+    }
+
+    // Get values out in FIFO order:
+    for(FwSizeType ii = 0; ii < DEPTH; ++ii) {
+        // Pop the top value:
+        ret = heap.pop(value, id);
+        ASSERT_TRUE(ret);
+        size = heap.getSize();
+        ASSERT_EQ(size, (DEPTH-ii-1));
+        ASSERT_EQ(value, orderedPries[ii]);
+        ASSERT_EQ(id, ordered[ii]);
+    }
+    printf("Passed.\n");
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Generic/test/ut/PriorityQueueTests.cpp b/Os/Generic/test/ut/PriorityQueueTests.cpp
new file mode 100644
index 0000000000..1f5675c050
--- /dev/null
+++ b/Os/Generic/test/ut/PriorityQueueTests.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Generic/test/ut/PriorityQueueTests.cpp
+// \brief tests using generic priority implementation for Os::Queue interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Os/Generic/PriorityQueue.hpp"
+#include "STest/Random/Random.hpp"
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    STest::Random::seed();
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Generic/test/ut/QueueRulesDefinitions.hpp b/Os/Generic/test/ut/QueueRulesDefinitions.hpp
new file mode 100644
index 0000000000..c539e58583
--- /dev/null
+++ b/Os/Generic/test/ut/QueueRulesDefinitions.hpp
@@ -0,0 +1,14 @@
+// ======================================================================
+// \title Os/Generic/test/ut/QueueRulesDefinitions.hpp
+// \brief definitions for queue testing
+// ======================================================================
+#ifndef OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS
+#define OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS
+#include <deque>
+#include <queue>
+#include "FpConfig.h"
+using PriorityCompare = std::less<FwQueuePriorityType>;
+constexpr FwSizeType QUEUE_MESSAGE_SIZE_UPPER_BOUND = 1024;
+constexpr FwSizeType QUEUE_DEPTH_UPPER_BOUND = 100;
+constexpr bool TESTS_SUPPORT_BLOCKING = true;
+#endif  // OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS
diff --git a/Os/Posix/test/ut/PosixConditionTests.cpp b/Os/Posix/test/ut/PosixConditionTests.cpp
new file mode 100644
index 0000000000..d2994a818b
--- /dev/null
+++ b/Os/Posix/test/ut/PosixConditionTests.cpp
@@ -0,0 +1,12 @@
+// ======================================================================
+// \title Os/Posix/test/ut/PosixConditionTests.cpp
+// \brief tests using posix condition variable tests
+// ======================================================================
+#include <gtest/gtest.h>
+#include "STest/Random/Random.hpp"
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    STest::Random::seed();
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Pthreads/MaxHeap/test/ut/MaxHeapTest.cpp b/Os/Pthreads/MaxHeap/test/ut/MaxHeapTest.cpp
deleted file mode 100644
index 3da975c07c..0000000000
--- a/Os/Pthreads/MaxHeap/test/ut/MaxHeapTest.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-#include "Os/Pthreads/MaxHeap/MaxHeap.hpp"
-#include <Fw/Types/Assert.hpp>
-#include <cstdio>
-#include <cstring>
-
-using namespace Os;
-
-#define DEPTH 5
-#define DATA_SIZE 3
-int main() {
-  printf("Creating heap.\n");
-  bool ret;
-  MaxHeap heap;
-  ret = heap.create(0);
-  FW_ASSERT(ret, ret);
-  ret = heap.create(1000000);
-  FW_ASSERT(ret, ret);
-  ret = heap.create(1);
-  FW_ASSERT(ret, ret);
-  ret = heap.create(DEPTH);
-  FW_ASSERT(ret, ret);
-  ret = heap.create(DEPTH);
-  FW_ASSERT(ret, ret);
-  NATIVE_INT_TYPE value;
-  NATIVE_UINT_TYPE size;
-  NATIVE_UINT_TYPE id=0;
-
-  printf("Testing empty...\n");
-  ret = heap.pop(value, id);
-  FW_ASSERT(id == 0, id);
-  FW_ASSERT(!ret, ret);
-  ret = heap.pop(value, id);
-  FW_ASSERT(id == 0, id);
-  FW_ASSERT(!ret, ret);
-  ret = heap.pop(value, id);
-  FW_ASSERT(id == 0, id);
-  FW_ASSERT(!ret, ret);
-  printf("Passed.\n");
-
-  printf("Testing push...\n");
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    //printf("Inserting value %d\n", ii);
-    ret = heap.push(ii, ii);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == ii+1, size, ii+1);
-  }
-  ret = heap.push(50, id);
-  FW_ASSERT(!ret, ret);
-  ret = heap.push(50, id);
-  FW_ASSERT(!ret, ret);
-  ret = heap.push(50, id);
-  FW_ASSERT(!ret, ret);
-  printf("Passed.\n");
-
-  printf("Testing pop...\n");
-  //heap.print();
-  for(NATIVE_INT_TYPE ii = DEPTH-1; ii >= 0; --ii) {
-    ret = heap.pop(value, id);
-    FW_ASSERT(ret, ret);
-    FW_ASSERT(id == static_cast<NATIVE_UINT_TYPE>(ii), id, ii);
-    size = heap.getSize();
-    FW_ASSERT(size == static_cast<NATIVE_UINT_TYPE>(ii), size, ii);
-    //printf("Heap state after pop:\n");
-    //heap.print();
-    //printf("Got value %d\n", value);
-    FW_ASSERT(value == ii, value, ii);
-  }
-  ret = heap.pop(value, id);
-  FW_ASSERT(!ret, ret);
-  printf("Passed.\n");
-
-  printf("Testing random...\n");
-  NATIVE_INT_TYPE values[DEPTH] = {56, 0, 500, 57, 5};
-  NATIVE_INT_TYPE sorted[DEPTH] = {500, 57, 56, 5, 0};
-  //heap.print();
-  // Push values on in random order:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    // Push next value in the list:
-    ret = heap.push(values[ii], id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == ii+1, size, ii+1);
-
-    // Pop the top value:
-    ret = heap.pop(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == ii, size, ii);
-    FW_ASSERT(value >= values[ii], value, values[ii]);
-
-    // Push the popped value:
-    ret = heap.push(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == ii+1, size, ii+1);
-  }
-  ret = heap.push(values[0], id);
-  FW_ASSERT(!ret, ret);
-
-  // Get values out from largest to smallest:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    // Pop the top value:
-    ret = heap.pop(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == (DEPTH-ii-1), size, (DEPTH-ii-1));
-    FW_ASSERT(value == sorted[ii], value, sorted[ii]);
-
-    // Push the top value:
-    ret = heap.push(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == (DEPTH-ii), size, (DEPTH-ii));
-
-    // Pop again:
-    ret = heap.pop(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == (DEPTH-ii-1), size, (DEPTH-ii-1));
-    FW_ASSERT(value == sorted[ii], value, sorted[ii]);
-  }
-  ret = heap.pop(value, id);
-  FW_ASSERT(!ret, ret);
-  printf("Passed.\n");
-
-  printf("Testing no priority...\n");
-  // For this test we expect things to come in fifo order
-  // since all the priorities are the same:
-  NATIVE_INT_TYPE priorities[DEPTH] = {7, 7, 7, 7, 7};
-  NATIVE_UINT_TYPE data[DEPTH] = {43, 56, 47, 33, 11};
-  // Push values on in random order:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    // Push next value in the list:
-    ret = heap.push(priorities[ii], data[ii]);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == ii+1, size, ii+1);
-  }
-
-  // Get values out in FIFO order:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    // Pop the top value:
-    ret = heap.pop(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == (DEPTH-ii-1), size, (DEPTH-ii-1));
-    FW_ASSERT(value == priorities[ii], value, priorities[ii]);
-    FW_ASSERT(id == data[ii], id, data[ii]);
-  }
-  printf("Passed.\n");
-
-  printf("Testing mixed priority...\n");
-  // For this test we expect things to come in fifo order
-  // for things of the same priority and in priority
-  // order for things of different priorities.
-  NATIVE_INT_TYPE pries[DEPTH] = {1, 7, 100, 1, 7};
-  NATIVE_INT_TYPE data2[DEPTH] = {4, 22, 99, 12344, 33};
-  NATIVE_INT_TYPE orderedPries[DEPTH] = {100, 7, 7, 1, 1};
-  NATIVE_UINT_TYPE ordered[DEPTH] = {99, 22, 33, 4, 12344};
-  // Push values on in random order:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    // Push next value in the list:
-    ret = heap.push(pries[ii], data2[ii]);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == ii+1, size, ii+1);
-  }
-
-  // Get values out in FIFO order:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    // Pop the top value:
-    ret = heap.pop(value, id);
-    FW_ASSERT(ret, ret);
-    size = heap.getSize();
-    FW_ASSERT(size == (DEPTH-ii-1), size, (DEPTH-ii-1));
-    FW_ASSERT(value == orderedPries[ii], value, orderedPries[ii]);
-    FW_ASSERT(id == ordered[ii], id, ordered[ii]);
-  }
-  printf("Passed.\n");
-
-  printf("Test done.\n");
-}
diff --git a/Os/Pthreads/test/ut/BufferQueueTest.cpp b/Os/Pthreads/test/ut/BufferQueueTest.cpp
deleted file mode 100644
index 2368c261a7..0000000000
--- a/Os/Pthreads/test/ut/BufferQueueTest.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "Os/Pthreads/BufferQueue.hpp"
-#include <Fw/Types/Assert.hpp>
-#include <cstdio>
-#include <cstring>
-
-using namespace Os;
-
-// Set this to 1 if testing a priority queue
-// Set this to 0 if testing a fifo queue
-#define PRIORITY_QUEUE 1
-
-#define DEPTH 5
-#define MSG_SIZE 3
-int main() {
-  printf("Creating queue.\n");
-  bool ret;
-  NATIVE_UINT_TYPE size;
-  NATIVE_UINT_TYPE count;
-  NATIVE_UINT_TYPE maxCount;
-  NATIVE_INT_TYPE priority = 0;
-  BufferQueue queue;
-  ret = queue.create(15, 34);
-  FW_ASSERT(ret, ret);
-  ret = queue.create(DEPTH, MSG_SIZE);
-  FW_ASSERT(ret, ret);
-  U8 recv[MSG_SIZE];
-
-  U8 send[MSG_SIZE];
-  for(U32 ii = 0; ii < sizeof(send); ++ii) {
-    send[ii] = ii;
-  }
-
-  printf("Test empty queue...\n");
-  size = sizeof(recv);
-  ret = queue.pop(&recv[0], size, priority);
-  FW_ASSERT(size == 0);
-  FW_ASSERT(!ret, ret);
-  FW_ASSERT(priority == 0, priority);
-  printf("Passed.\n");
-
-  printf("Test full queue...\n");
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    printf("Pushing %d.\n", ii);
-    ret = queue.push(&send[0], sizeof(send), priority);
-    FW_ASSERT(ret, ret);
-    count = queue.getCount();
-    maxCount = queue.getMaxCount();
-    FW_ASSERT(count == ii+1, count);
-    FW_ASSERT(maxCount == ii+1, maxCount);
-  }
-  ret = queue.push(&send[0], sizeof(send), priority);
-  FW_ASSERT(!ret, ret);
-  printf("Passed.\n");
-
-  printf("Test weird size...\n");
-  size = 1;
-  ret = queue.pop(&recv[0], size, priority);
-  FW_ASSERT(!ret, ret);
-  FW_ASSERT(size == sizeof(send), size);
-  FW_ASSERT(priority == 0, priority);
-  printf("Passed.\n");
-
-  printf("Test pop...\n");
-  for(NATIVE_UINT_TYPE ii = DEPTH; ii > 0; --ii) {
-    printf("Popping %d.\n", ii);
-    size = sizeof(recv);
-    ret = queue.pop(&recv[0], size, priority);
-    FW_ASSERT(size == sizeof(recv), size);
-    FW_ASSERT(ret, ret);
-    FW_ASSERT(memcmp(recv, send, size) == 0);
-    FW_ASSERT(priority == 0, priority);
-    count = queue.getCount();
-    maxCount = queue.getMaxCount();
-    FW_ASSERT(count == ii-1, count);
-    FW_ASSERT(maxCount == DEPTH, maxCount);
-  }
-  size = sizeof(recv);
-  ret = queue.pop(&recv[0], size, priority);
-  FW_ASSERT(size == 0);
-  FW_ASSERT(!ret, ret);
-  FW_ASSERT(priority == 0, priority);
-  printf("Passed.\n");
-
-  printf("Test priorities...\n");
-  // Send messages with mixed priorities,
-  // and make sure we get back the buffers in
-  // the correct order.
-  BufferQueue queue2;
-  ret = queue2.create(1, 1);
-  FW_ASSERT(ret, ret);
-  ret = queue2.create(1, 1);
-  FW_ASSERT(ret, ret);
-  ret = queue2.create(DEPTH, 100);
-  FW_ASSERT(ret, ret);
-  ret = queue2.create(DEPTH, 100);
-  FW_ASSERT(ret, ret);
-  NATIVE_INT_TYPE priorities[DEPTH] = {9, 4, 100, 4, 9};
-  const char* messages[DEPTH] = {"hello", "how are you", "pretty good", "cosmic bro", "kthxbye"};
-  // Fill queue:
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    printf("Pushing '%s' at priority %d with size %zu\n", messages[ii], priorities[ii], strlen(messages[ii]));
-    ret = queue2.push(reinterpret_cast<const U8*>(messages[ii]), strlen(messages[ii]), priorities[ii]);
-    FW_ASSERT(ret, ret);
-    count = queue2.getCount();
-    maxCount = queue2.getMaxCount();
-    FW_ASSERT(count == ii+1, count);
-    FW_ASSERT(maxCount == ii+1, maxCount);
-  }
-
-#if PRIORITY_QUEUE
-  // Pop things off the queue in the expected order:
-  NATIVE_INT_TYPE orderedPriorities[DEPTH] = {100, 9, 9, 4, 4};
-  const char* orderedMessages[DEPTH] = {"pretty good", "hello", "kthxbye", "how are you", "cosmic bro"};
-#else
-  NATIVE_INT_TYPE orderedPriorities[DEPTH] = {0, 0, 0, 0, 0};
-  const char* orderedMessages[DEPTH] = {"hello", "how are you", "pretty good", "cosmic bro", "kthxbye"};
-#endif
-  char temp[101];
-  size = sizeof(temp) - 1; // Leave room for extra \0 because of the message print
-  for(NATIVE_UINT_TYPE ii = 0; ii < DEPTH; ++ii) {
-    ret = queue2.pop(reinterpret_cast<U8*>(temp), size, priority);
-    temp[size] = '\0';
-    FW_ASSERT(ret, ret);
-    FW_ASSERT(priority == orderedPriorities[ii], priority);
-    FW_ASSERT(size == strlen(orderedMessages[ii]), strlen(orderedMessages[ii]));
-    printf("Popped '%s' at priority %d. Expected '%s' at priority %d.\n",
-           temp, priority, orderedMessages[ii], orderedPriorities[ii]);
-    FW_ASSERT(memcmp(temp, orderedMessages[ii], size) == 0, ii);
-    size = sizeof(temp) - 1; //Reset size
-  }
-
-
-  printf("Passed.\n");
-
-  printf("Test done.\n");
-}
diff --git a/Os/Stub/test/ConditionVariable.cpp b/Os/Stub/test/ConditionVariable.cpp
new file mode 100644
index 0000000000..eb09693725
--- /dev/null
+++ b/Os/Stub/test/ConditionVariable.cpp
@@ -0,0 +1,47 @@
+//
+// Created by Michael Starch on 8/27/24.
+//
+#include <cstring>
+#include "ConditionVariable.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+namespace Stub {
+namespace ConditionVariable {
+namespace Test {
+
+StaticData StaticData::data;
+
+TestConditionVariable::TestConditionVariable() {
+    StaticData::data.lastCalled = StaticData::LastFn::CONSTRUCT_FN;
+}
+
+TestConditionVariable::~TestConditionVariable() {
+    StaticData::data.lastCalled = StaticData::LastFn::DESTRUCT_FN;
+}
+
+
+void TestConditionVariable::wait(Os::Mutex& mutex) {
+    StaticData::data.lastCalled = StaticData::LastFn::WAIT_FN;
+    StaticData::data.passed = &mutex;
+}
+
+void TestConditionVariable::notify() {
+    StaticData::data.lastCalled = StaticData::LastFn::NOTIFY_FN;
+}
+
+void TestConditionVariable::notifyAll()  {
+    StaticData::data.lastCalled = StaticData::LastFn::NOTIFY_ALL_FN;
+
+}
+ConditionVariableHandle* TestConditionVariable::getHandle() {
+    StaticData::data.lastCalled = StaticData::LastFn::HANDLE_FN;
+    StaticData::data.handle = &this->m_handle;
+    return &this->m_handle;
+}
+
+
+}  // namespace Test
+}  // namespace Queue
+}  // namespace Stub
+}  // namespace Os
diff --git a/Os/Stub/test/ConditionVariable.hpp b/Os/Stub/test/ConditionVariable.hpp
new file mode 100644
index 0000000000..7062b5ced9
--- /dev/null
+++ b/Os/Stub/test/ConditionVariable.hpp
@@ -0,0 +1,80 @@
+
+#ifndef OS_STUB_TEST_CONDITION_VARIABLE_HPP
+#define OS_STUB_TEST_CONDITION_VARIABLE_HPP
+#include "Os/Condition.hpp"
+#include <queue>
+#include <deque>
+
+
+namespace Os {
+namespace Stub {
+namespace ConditionVariable {
+namespace Test {
+
+//! Data that supports the stubbed File implementation.
+//!
+struct StaticData {
+    //! Enumeration of last function called
+    //!
+    enum LastFn {
+        NONE_FN,
+        CONSTRUCT_FN,
+        DESTRUCT_FN,
+        WAIT_FN,
+        NOTIFY_FN,
+        NOTIFY_ALL_FN,
+        HANDLE_FN
+    };
+    StaticData() = default;
+    ~StaticData() = default;
+
+    //! Last function called
+    LastFn lastCalled = NONE_FN;
+    Os::Mutex* passed = nullptr;
+    ConditionVariableHandle* handle = nullptr;
+
+    // Singleton data
+    static StaticData data;
+};
+
+
+struct TestConditionVariableHandle : public ConditionVariableHandle {};
+
+//! \brief interface testing condition variable
+class TestConditionVariable : public ConditionVariableInterface {
+  public:
+    //! \brief default interface constructor
+    TestConditionVariable();
+
+    //! \brief default destructor
+    ~TestConditionVariable() override;
+
+    //! \brief copy constructor is forbidden
+    TestConditionVariable(const ConditionVariableInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    TestConditionVariable(const ConditionVariableInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
+
+    //! \brief wait releasing mutex
+    void wait(Os::Mutex& mutex) override;
+
+    //! \brief notify a single waiter
+    void notify() override;
+
+    //! \brief notify all current waiters
+    void notifyAll() override;
+
+    ConditionVariableHandle* getHandle() override;
+
+    TestConditionVariableHandle m_handle;
+};
+
+}  // namespace Test
+}  // namespace Queue
+}  // namespace Stub
+}  // namespace Os
+
+#endif  // OS_STUB_TEST_CONDITION_VARIABLE_HPP
diff --git a/Os/Stub/test/DefaultDirectory.cpp b/Os/Stub/test/DefaultDirectory.cpp
index 63ea50288d..91b7334acd 100644
--- a/Os/Stub/test/DefaultDirectory.cpp
+++ b/Os/Stub/test/DefaultDirectory.cpp
@@ -7,7 +7,7 @@
 #include "Os/Delegate.hpp"
 
 namespace Os {
-DirectoryInterface* DirectoryInterface::getDelegate(HandleStorage& aligned_new_memory) {
+DirectoryInterface* DirectoryInterface::getDelegate(DirectoryHandleStorage& aligned_new_memory) {
     return Os::Delegate::makeDelegate<DirectoryInterface, Os::Stub::Directory::Test::TestDirectory>(aligned_new_memory);
 }
 }
diff --git a/Os/Stub/test/DefaultFileSystem.cpp b/Os/Stub/test/DefaultFileSystem.cpp
index 1d960cfa09..06576533cf 100644
--- a/Os/Stub/test/DefaultFileSystem.cpp
+++ b/Os/Stub/test/DefaultFileSystem.cpp
@@ -11,7 +11,7 @@ namespace Os {
 //! \param aligned_new_memory: aligned memory to fill
 //! \param to_copy: pointer to copy-constructor input
 //! \return: pointer to delegate
-FileSystemInterface *FileSystemInterface::getDelegate(HandleStorage& aligned_placement_new_memory) {
+FileSystemInterface *FileSystemInterface::getDelegate(FileSystemHandleStorage& aligned_placement_new_memory) {
     return Os::Delegate::makeDelegate<FileSystemInterface, Os::Stub::FileSystem::Test::TestFileSystem>(
             aligned_placement_new_memory
     );
diff --git a/Os/Stub/test/DefaultMutex.cpp b/Os/Stub/test/DefaultMutex.cpp
index 5201d67af0..9f7537b830 100644
--- a/Os/Stub/test/DefaultMutex.cpp
+++ b/Os/Stub/test/DefaultMutex.cpp
@@ -3,6 +3,7 @@
 // \brief sets default Os::Mutex to test stub implementation via linker
 // ======================================================================
 #include "Os/Stub/test/Mutex.hpp"
+#include "Os/Stub/test/ConditionVariable.hpp"
 #include "Os/Delegate.hpp"
 
 namespace Os {
@@ -15,4 +16,13 @@ MutexInterface *MutexInterface::getDelegate(HandleStorage& aligned_placement_new
             aligned_placement_new_memory
     );
 }
+
+//! \brief get a delegate for MutexInterface that intercepts calls for Posix
+//! \param aligned_new_memory: aligned memory to fill
+//! \return: pointer to delegate
+ConditionVariableInterface *ConditionVariableInterface::getDelegate(ConditionVariableHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<ConditionVariableInterface, Os::Stub::ConditionVariable::Test::TestConditionVariable, ConditionVariableHandleStorage>(
+        aligned_new_memory
+    );
+}
 }
diff --git a/Os/Stub/test/DefaultQueue.cpp b/Os/Stub/test/DefaultQueue.cpp
new file mode 100644
index 0000000000..4ade930caa
--- /dev/null
+++ b/Os/Stub/test/DefaultQueue.cpp
@@ -0,0 +1,13 @@
+// ======================================================================
+// \title Os/Stub/test/DefaultQueue.cpp
+// \brief sets default Os::Queue to stub test implementation via linker
+// ======================================================================
+#include "Os/Queue.hpp"
+#include "Os/Stub/test/Queue.hpp"
+#include "Os/Delegate.hpp"
+
+namespace Os {
+QueueInterface* QueueInterface::getDelegate(QueueHandleStorage& aligned_new_memory) {
+    return Os::Delegate::makeDelegate<QueueInterface, Os::Stub::Queue::Test::InjectableStlQueue, QueueHandleStorage>(aligned_new_memory);
+}
+}
diff --git a/Os/Stub/test/Queue.cpp b/Os/Stub/test/Queue.cpp
new file mode 100644
index 0000000000..b1dbb6a601
--- /dev/null
+++ b/Os/Stub/test/Queue.cpp
@@ -0,0 +1,128 @@
+//
+// Created by Michael Starch on 8/27/24.
+//
+#include <cstring>
+#include "Queue.hpp"
+#include "Fw/Types/Assert.hpp"
+
+namespace Os {
+namespace Stub {
+namespace Queue {
+namespace Test {
+
+StaticData StaticData::data;
+
+InjectableStlQueueHandle::InjectableStlQueueHandle() :
+      // Creates the necessary handle on the heap to keep the handle size small
+      m_storage(*new std::priority_queue<Message, std::deque<Message>, Message::LessMessage>),
+      m_high_water(0),
+      m_max_depth(0) {}
+
+InjectableStlQueueHandle::~InjectableStlQueueHandle() {
+    // Clean-up heap
+    delete &m_storage;
+}
+
+InjectableStlQueue::InjectableStlQueue() {
+    StaticData::data.lastCalled = StaticData::LastFn::CONSTRUCT_FN;
+}
+
+InjectableStlQueue::~InjectableStlQueue() {
+    StaticData::data.lastCalled = StaticData::LastFn::DESTRUCT_FN;
+}
+
+QueueInterface::Status InjectableStlQueue::create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) {
+    StaticData::data.lastCalled = StaticData::LastFn::CREATE_FN;
+    // This must be the case or this test queue will not work
+    if (StaticData::data.sendStatus != QueueInterface::Status::OP_OK) {
+        FW_ASSERT(messageSize <= sizeof InjectableStlQueueHandle::Message::data);
+    }
+    StaticData::data.name = name;
+    StaticData::data.depth = depth;
+    StaticData::data.size = messageSize;
+    this->m_handle.m_max_depth = depth;
+    return StaticData::data.createStatus;
+}
+
+
+QueueInterface::Status InjectableStlQueue::send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, QueueInterface::BlockingType blockType) {
+    StaticData::data.lastCalled = StaticData::LastFn::SEND_FN;
+    StaticData::data.buffer = const_cast<U8*>(buffer);
+    StaticData::data.size = size;
+    StaticData::data.priority = priority;
+    StaticData::data.blockType = blockType;
+    if (StaticData::data.sendStatus != QueueInterface::Status::OP_OK) {
+        return StaticData::data.sendStatus;
+    } else if (size > sizeof InjectableStlQueueHandle::Message::data) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    } else if (this->m_handle.m_storage.size() >= this->m_handle.m_max_depth) {
+        return QueueInterface::Status::FULL;
+    }
+
+    InjectableStlQueueHandle::Message message;
+    (void) std::memcpy(message.data, buffer, size);
+    message.priority = priority;
+    message.size = size;
+    this->m_handle.m_storage.push(message);
+    this->m_handle.m_high_water = FW_MAX(this->m_handle.m_high_water, this->m_handle.m_storage.size());
+    return QueueInterface::Status::OP_OK;
+}
+
+QueueInterface::Status InjectableStlQueue::receive(U8* destination,
+               FwSizeType capacity,
+               QueueInterface::BlockingType blockType,
+               FwSizeType& actualSize,
+               FwQueuePriorityType& priority) {
+    StaticData::data.lastCalled = StaticData::LastFn::RECEIVE_FN;
+    StaticData::data.buffer = const_cast<U8*>(destination);
+    StaticData::data.capacity = capacity;
+    StaticData::data.blockType = blockType;
+    if (StaticData::data.receiveStatus != QueueInterface::Status::OP_OK) {
+        actualSize = StaticData::data.size;
+        priority = StaticData::data.priority;
+        return StaticData::data.receiveStatus;
+    }
+    if (this->m_handle.m_storage.empty()) {
+        return Status::EMPTY;
+    }
+    InjectableStlQueueHandle::Message message = this->m_handle.m_storage.top();
+    // Fail with size miss-match when the destination cannot store message
+    if (message.size > capacity) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    }
+    std::memcpy(destination, message.data, message.size);
+    priority = message.priority;
+    actualSize = message.size;
+    this->m_handle.m_storage.pop();
+    return QueueInterface::Status::OP_OK;
+}
+
+FwSizeType InjectableStlQueue::getMessagesAvailable() const {
+    StaticData::data.lastCalled = StaticData::LastFn::MESSAGES_FN;
+    // Injection detected
+    if (StaticData::data.messages != -1) {
+        return StaticData::data.messages;
+    }
+    return this->m_handle.m_storage.size();
+}
+
+FwSizeType InjectableStlQueue::getMessageHighWaterMark() const {
+    StaticData::data.lastCalled = StaticData::LastFn::HIGH_WATER_FN;
+    // Injection detected
+    if (StaticData::data.highWaterMark != -1) {
+        return StaticData::data.highWaterMark;
+    }
+    return this->m_handle.m_high_water;
+}
+
+QueueHandle* InjectableStlQueue::getHandle() {
+    StaticData::data.lastCalled = StaticData::LastFn::HANDLE_FN;
+    StaticData::data.handle = &this->m_handle;
+    return &this->m_handle;
+}
+
+
+}  // namespace Test
+}  // namespace Queue
+}  // namespace Stub
+}  // namespace Os
diff --git a/Os/Stub/test/Queue.hpp b/Os/Stub/test/Queue.hpp
new file mode 100644
index 0000000000..17cd2e3da7
--- /dev/null
+++ b/Os/Stub/test/Queue.hpp
@@ -0,0 +1,160 @@
+
+#ifndef OS_STUB_TEST_QUEUE_HPP
+#define OS_STUB_TEST_QUEUE_HPP
+#include "Os/Queue.hpp"
+#include <queue>
+#include <deque>
+
+
+namespace Os {
+namespace Stub {
+namespace Queue {
+namespace Test {
+constexpr FwSizeType STUB_QUEUE_TEST_MESSAGE_MAX_SIZE = 1024;
+
+//! Data that supports the stubbed File implementation.
+//!
+struct StaticData {
+    //! Enumeration of last function called
+    //!
+    enum LastFn {
+        NONE_FN,
+        CONSTRUCT_FN,
+        DESTRUCT_FN,
+        CREATE_FN,
+        SEND_FN,
+        RECEIVE_FN,
+        MESSAGES_FN,
+        HIGH_WATER_FN,
+        HANDLE_FN
+    };
+    StaticData() = default;
+    ~StaticData() = default;
+
+    //! Last function called
+    LastFn lastCalled = NONE_FN;
+
+    Os::QueueInterface::Status createStatus = Os::QueueInterface::Status::OP_OK;
+    Os::QueueInterface::Status sendStatus = Os::QueueInterface::Status::OP_OK;
+    Os::QueueInterface::Status receiveStatus = Os::QueueInterface::Status::OP_OK;
+
+    FwSignedSizeType messages = -1;
+    FwSignedSizeType highWaterMark = -1;
+    QueueHandle* handle = nullptr;
+
+    // Received variables
+    Os::QueueString name;
+    FwSizeType depth;
+    FwSizeType size;
+    FwSizeType capacity;
+    U8* buffer;
+    FwQueuePriorityType priority;
+    QueueInterface::BlockingType blockType;
+
+    // Singleton data
+    static StaticData data;
+};
+
+
+struct InjectableStlQueueHandle : public QueueHandle {
+    //! \brief message type
+    struct Message {
+        U8 data[STUB_QUEUE_TEST_MESSAGE_MAX_SIZE];
+        FwQueuePriorityType priority;
+        FwSizeType size;
+        //! \brief comparison utility for messages
+        struct LessMessage {
+            bool operator()(const Message& a, const Message& b) {
+                return std::greater<FwQueuePriorityType>()(a.priority, b.priority);
+            }
+        };
+    };
+    InjectableStlQueueHandle();
+    ~InjectableStlQueueHandle();
+
+    std::priority_queue<Message, std::deque<Message>, Message::LessMessage>& m_storage;
+    FwSizeType m_high_water;
+    FwSizeType m_max_depth;
+};
+
+//! \brief standard library powered queue implementation with injectable statuses
+class InjectableStlQueue : public QueueInterface {
+  public:
+    //! \brief default queue interface constructor
+    InjectableStlQueue();
+
+    //! \brief default queue destructor
+    virtual ~InjectableStlQueue();
+
+    //! \brief copy constructor is forbidden
+    InjectableStlQueue(const QueueInterface& other) = delete;
+
+    //! \brief copy constructor is forbidden
+    InjectableStlQueue(const QueueInterface* other) = delete;
+
+    //! \brief assignment operator is forbidden
+    InjectableStlQueue& operator=(const QueueInterface& other) override = delete;
+
+    //! \brief create queue storage
+    //!
+    //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each.
+    //! \param name: name of queue
+    //! \param depth: depth of queue in number of messages
+    //! \param messageSize: size of an individual message
+    //! \return: status of the creation
+    Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override;
+
+    //! \brief send a message into the queue
+    //!
+    //! Send a message into the queue, providing the message data, size, priority, and blocking type. When
+    //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error
+    //! status on queue full.
+    //!
+    //! \param buffer: message data
+    //! \param size: size of message data
+    //! \param priority: priority of the message
+    //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full
+    //! \return: status of the send
+    Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) override;
+
+    //! \brief receive a message from the queue
+    //!
+    //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type.
+    //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an
+    //! error status on queue empty. Actual size received and priority of message is set on success status.
+    //!
+    //! \param destination: destination for message data
+    //! \param capacity: maximum size of message data
+    //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty
+    //! \param actualSize: (output) actual size of message read
+    //! \param priority: (output) priority of message read
+    //! \return: status of the send
+    Status receive(U8* destination,
+                           FwSizeType capacity,
+                           BlockingType blockType,
+                           FwSizeType& actualSize,
+                           FwQueuePriorityType& priority) override;
+
+    //! \brief get number of messages available
+    //!
+    //! \return number of messages available
+    FwSizeType getMessagesAvailable() const override;
+
+    //! \brief get maximum messages stored at any given time
+    //!
+    //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for this
+    //! queue.
+    //! \return queue message high-water mark
+    FwSizeType getMessageHighWaterMark() const override;
+
+    QueueHandle* getHandle() override;
+
+    InjectableStlQueueHandle m_handle;
+};
+
+}  // namespace Test
+}  // namespace Queue
+}  // namespace Stub
+}  // namespace Os
+
+#endif  // OS_STUB_TEST_QUEUE_HPP
diff --git a/Os/Stub/test/ut/QueueRulesDefinitions.hpp b/Os/Stub/test/ut/QueueRulesDefinitions.hpp
new file mode 100644
index 0000000000..430b0a2a2d
--- /dev/null
+++ b/Os/Stub/test/ut/QueueRulesDefinitions.hpp
@@ -0,0 +1,12 @@
+#ifndef OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS
+#define OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS
+#include "Os/Stub/test/Queue.hpp"
+
+using PriorityCompare = std::greater<FwQueuePriorityType>;
+constexpr FwSizeType QUEUE_MESSAGE_SIZE_UPPER_BOUND = Os::Stub::Queue::Test::STUB_QUEUE_TEST_MESSAGE_MAX_SIZE;
+constexpr FwSizeType QUEUE_DEPTH_UPPER_BOUND = 100;
+constexpr bool TESTS_SUPPORT_BLOCKING = false;
+
+
+
+#endif // OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS
diff --git a/Os/Stub/test/ut/StubConditionTests.cpp b/Os/Stub/test/ut/StubConditionTests.cpp
new file mode 100644
index 0000000000..bca5a9a309
--- /dev/null
+++ b/Os/Stub/test/ut/StubConditionTests.cpp
@@ -0,0 +1,65 @@
+// ======================================================================
+// \title Os/Stub/test/ut/StubConditionTests.cpp
+// \brief tests using stub implementation for Os::ConditionVariable interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Os/Condition.hpp"
+#include "Os/Stub/test/ConditionVariable.hpp"
+#include "Os/Stub/test/Mutex.hpp"
+
+
+// Construction test
+TEST(Interface, Construction) {
+    Os::ConditionVariable variable;
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::CONSTRUCT_FN);
+}
+
+// Destruct test
+TEST(Interface, Destruction) {
+    delete (new Os::ConditionVariable);
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::DESTRUCT_FN);
+}
+
+// Wait test
+TEST(Interface, WaitNotHeld) {
+    Os::Mutex mutex;
+    Os::ConditionVariable variable;
+    variable.wait(mutex);
+    ASSERT_EQ(Os::Stub::Mutex::Test::StaticData::data.lastCalled, Os::Stub::Mutex::Test::StaticData::TAKE_FN);
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::WAIT_FN);
+}
+
+// Wait test
+TEST(Interface, WaitHeld) {
+    Os::Mutex mutex;
+    Os::ConditionVariable variable;
+    mutex.lock();
+    variable.wait(mutex);
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::WAIT_FN);
+}
+
+// Notify test
+TEST(Interface, Notify) {
+    Os::ConditionVariable variable;
+    variable.notify();
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::NOTIFY_FN);
+}
+
+// NotifyAll test
+TEST(Interface, NotifyAll) {
+    Os::ConditionVariable variable;
+    variable.notifyAll();
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::NOTIFY_ALL_FN);
+}
+
+
+TEST(Interface, Handle) {
+    Os::ConditionVariable variable;
+    ASSERT_EQ(variable.getHandle(), Os::Stub::ConditionVariable::Test::StaticData::data.handle);
+    ASSERT_EQ(Os::Stub::ConditionVariable::Test::StaticData::data.lastCalled, Os::Stub::ConditionVariable::Test::StaticData::HANDLE_FN);
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Stub/test/ut/StubQueueTests.cpp b/Os/Stub/test/ut/StubQueueTests.cpp
new file mode 100644
index 0000000000..556c2294b7
--- /dev/null
+++ b/Os/Stub/test/ut/StubQueueTests.cpp
@@ -0,0 +1,241 @@
+// ======================================================================
+// \title Os/Stub/test/ut/StubFileTests.cpp
+// \brief tests using stub implementation for Os::File interface testing
+// ======================================================================
+#include <gtest/gtest.h>
+#include "Fw/Types/String.hpp"
+#include "Os/Queue.hpp"
+#include "Os/Stub/test/Queue.hpp"
+#include "STest/Random/Random.hpp"
+
+
+void resetInjections() {
+    Os::Stub::Queue::Test::StaticData::data.createStatus = Os::QueueInterface::Status::OP_OK;
+    Os::Stub::Queue::Test::StaticData::data.sendStatus = Os::QueueInterface::Status::OP_OK;
+    Os::Stub::Queue::Test::StaticData::data.receiveStatus = Os::QueueInterface::Status::OP_OK;
+    Os::Stub::Queue::Test::StaticData::data.messages = -1;
+    Os::Stub::Queue::Test::StaticData::data.highWaterMark = -1;
+}
+
+// Construction test
+TEST(Interface, Construction) {
+    Os::Queue queue;
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::CONSTRUCT_FN);
+    resetInjections();
+}
+
+// Destruct test
+TEST(Interface, Destruction) {
+    delete (new Os::Queue);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::DESTRUCT_FN);
+    resetInjections();
+}
+
+// Create test
+TEST(Interface, Create) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    const FwSizeType messageSize = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    Os::Stub::Queue::Test::StaticData::data.createStatus = Os::QueueInterface::Status::INVALID_PRIORITY;
+    Os::QueueInterface::Status status = queue.create(name, depth, messageSize);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::CREATE_FN);
+    ASSERT_EQ(Os::QueueInterface::Status::INVALID_PRIORITY, status);
+    ASSERT_STREQ(name.toChar(), Os::Stub::Queue::Test::StaticData::data.name.toChar());
+    ASSERT_EQ(depth, Os::Stub::Queue::Test::StaticData::data.depth);
+    ASSERT_EQ(messageSize, Os::Stub::Queue::Test::StaticData::data.size);
+    resetInjections();
+}
+
+// Send test
+TEST(Interface, SendPointer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    const FwSizeType messageSize = sizeof Os::Stub::Queue::Test::InjectableStlQueueHandle::Message::data;
+    const FwQueuePriorityType priority =  STest::Random::lowerUpper(
+        0,
+        FW_MIN(std::numeric_limits<FwQueuePriorityType>::max(), std::numeric_limits<U32>::max())
+    );
+    U8 buffer[messageSize];
+    ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
+    ASSERT_STREQ(name.toChar(), queue.getName().toChar());
+    Os::Stub::Queue::Test::StaticData::data.sendStatus = Os::QueueInterface::Status::EMPTY;
+    Os::QueueInterface::Status status =
+        queue.send(buffer, sizeof buffer, priority, Os::QueueInterface::BlockingType::BLOCKING);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::SEND_FN);
+    ASSERT_EQ(Os::QueueInterface::Status::EMPTY, status);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.buffer, &buffer[0]);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.size, messageSize);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.priority, priority);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.blockType, Os::QueueInterface::BlockingType::BLOCKING);
+    ASSERT_EQ(depth, queue.getDepth());
+    ASSERT_EQ(messageSize, queue.getMessageSize());
+    resetInjections();
+}
+
+// Send test
+TEST(Interface, SendBuffer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    const FwSizeType messageSize = sizeof Os::Stub::Queue::Test::InjectableStlQueueHandle::Message::data;
+    const FwQueuePriorityType priority =  STest::Random::lowerUpper(
+        0,
+        FW_MIN(std::numeric_limits<FwQueuePriorityType>::max(), std::numeric_limits<U32>::max())
+    );
+    U8 storage[messageSize];
+    Fw::ExternalSerializeBuffer buffer(storage, sizeof storage);
+    Fw::String message = "hello";
+    buffer.serialize(message);
+
+    ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
+    Os::Stub::Queue::Test::StaticData::data.sendStatus = Os::QueueInterface::Status::UNKNOWN_ERROR;
+    Os::QueueInterface::Status status = queue.send(buffer, priority, Os::QueueInterface::BlockingType::NONBLOCKING);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::SEND_FN);
+    ASSERT_EQ(Os::QueueInterface::Status::UNKNOWN_ERROR, status);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.buffer, storage);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.size, 7);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.priority, priority);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.blockType, Os::QueueInterface::BlockingType::NONBLOCKING);
+    ASSERT_EQ(depth, queue.getDepth());
+    ASSERT_EQ(messageSize, queue.getMessageSize());
+
+    resetInjections();
+}
+
+// Receive test
+TEST(Interface, ReceivePointer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    const FwSizeType sizeOut = sizeof Os::Stub::Queue::Test::InjectableStlQueueHandle::Message::data;
+    const FwQueuePriorityType priorityOut =  STest::Random::lowerUpper(
+        0,
+        FW_MIN(std::numeric_limits<FwQueuePriorityType>::max(), std::numeric_limits<U32>::max())
+    );
+
+    FwSizeType size = sizeof Os::Stub::Queue::Test::InjectableStlQueueHandle::Message::data;
+    FwQueuePriorityType priority;
+    U8 storage[size];
+
+    ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, size));
+    Os::Stub::Queue::Test::StaticData::data.receiveStatus = Os::QueueInterface::Status::FULL;
+    Os::Stub::Queue::Test::StaticData::data.size = sizeOut;
+    Os::Stub::Queue::Test::StaticData::data.priority = priorityOut;
+    Os::QueueInterface::Status status = queue.receive(storage, sizeof storage,
+                                                      Os::QueueInterface::BlockingType::NONBLOCKING,
+                                                      size, priority);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::RECEIVE_FN);
+    ASSERT_EQ(Os::QueueInterface::Status::FULL, status);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.buffer, &storage[0]);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.capacity, sizeof storage);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.priority, priority);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.blockType, Os::QueueInterface::BlockingType::NONBLOCKING);
+    ASSERT_EQ(size, sizeOut);
+    ASSERT_EQ(priority, priorityOut);
+    ASSERT_EQ(depth, queue.getDepth());
+    ASSERT_EQ(size, queue.getMessageSize());
+
+    resetInjections();
+}
+
+// Receive test
+TEST(Interface, ReceiveBuffer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    const FwSizeType sizeOut = sizeof Os::Stub::Queue::Test::InjectableStlQueueHandle::Message::data;
+    const FwQueuePriorityType priorityOut =  STest::Random::lowerUpper(
+        0,
+        FW_MIN(std::numeric_limits<FwQueuePriorityType>::max(), std::numeric_limits<U32>::max())
+    );
+
+    FwSizeType size = sizeof Os::Stub::Queue::Test::InjectableStlQueueHandle::Message::data;
+    FwQueuePriorityType priority;
+    U8 storage[size];
+    Fw::ExternalSerializeBuffer buffer(storage, sizeof storage);
+
+    ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, size));
+    Os::Stub::Queue::Test::StaticData::data.receiveStatus = Os::QueueInterface::Status::FULL;
+    Os::Stub::Queue::Test::StaticData::data.size = sizeOut;
+    Os::Stub::Queue::Test::StaticData::data.priority = priorityOut;
+    Os::QueueInterface::Status status = queue.receive(buffer,
+                                                      Os::QueueInterface::BlockingType::NONBLOCKING,
+                                                      priority);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::RECEIVE_FN);
+    ASSERT_EQ(Os::QueueInterface::Status::FULL, status);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.buffer, &storage[0]);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.capacity, sizeof storage);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.priority, priority);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.blockType, Os::QueueInterface::BlockingType::NONBLOCKING);
+    ASSERT_EQ(size, sizeOut);
+    ASSERT_EQ(priority, priorityOut);
+    ASSERT_EQ(depth, queue.getDepth());
+    ASSERT_EQ(size, queue.getMessageSize());
+
+    resetInjections();
+}
+
+TEST(Interface, MessageCount) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = 1;
+    const FwSizeType messageSize = 1;
+    const FwSizeType messages = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
+    Os::Stub::Queue::Test::StaticData::data.messages = messages;
+    ASSERT_EQ(queue.getMessagesAvailable(), messages);
+
+    resetInjections();
+}
+
+TEST(Interface, MessageHighWaterMarkCount) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType depth = 100;
+    const FwSizeType messageSize = 200;
+    const FwSizeType highWater = STest::Random::lowerUpper(
+        std::numeric_limits<FwSizeType>::min(),
+        FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max())
+    );
+    ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
+    Os::Stub::Queue::Test::StaticData::data.highWaterMark = highWater;
+    ASSERT_EQ(queue.getMessageHighWaterMark(), highWater);
+
+    resetInjections();
+}
+
+TEST(Interface, QueueHandle) {
+    Os::Queue queue;
+    ASSERT_EQ(queue.getHandle(), Os::Stub::Queue::Test::StaticData::data.handle);
+    ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::HANDLE_FN);
+    resetInjections();
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    STest::Random::seed();
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/Stub/test/ut/StubTests.cpp b/Os/Stub/test/ut/StubTests.cpp
new file mode 100644
index 0000000000..ec8b2b0a3b
--- /dev/null
+++ b/Os/Stub/test/ut/StubTests.cpp
@@ -0,0 +1,47 @@
+#include <gtest/gtest.h>
+#include <Os/File.hpp>
+#include <Os/Task.hpp>
+#include <Os/Queue.hpp>
+#include <Os/Mutex.hpp>
+#include <Os/Condition.hpp>
+#include <Os/Console.hpp>
+#include <Os/FileSystem.hpp>
+#include <Os/Directory.hpp>
+
+
+TEST(Stub, File) {
+    Os::File _;
+}
+
+TEST(Stub, Task) {
+    Os::Task _;
+}
+
+TEST(Stub, Queue) {
+    Os::Queue _;
+}
+
+TEST(Stub, ConditionVariable) {
+    Os::ConditionVariable _;
+}
+
+TEST(Stub, Mutex) {
+    Os::Mutex _;
+}
+
+TEST(Stub, Console) {
+    Os::Console _;
+}
+
+TEST(Stub, FileSystem) {
+    Os::FileSystem::getSingleton();
+}
+
+TEST(Stub, Directory) {
+    Os::Directory _;
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/Os/test/ConcurrentRule.hpp b/Os/test/ConcurrentRule.hpp
new file mode 100644
index 0000000000..a3b716e491
--- /dev/null
+++ b/Os/test/ConcurrentRule.hpp
@@ -0,0 +1,222 @@
+// ======================================================================
+// \title Os/test/ut/queue/RulesHeaders.cpp
+// \brief definitions for concurrent running rules
+// ======================================================================
+#include <STest/Rule/Rule.hpp>
+#include <gtest/gtest.h>
+#include "Os/Task.hpp"
+#include "Os/Mutex.hpp"
+#include "Os/Condition.hpp"
+#include <list>
+#include <map>
+#include <iterator>
+#ifndef OS_TEST_CONCURRENT_RULE
+#define OS_TEST_CONCURRENT_RULE
+
+
+// Forward declaration of the aggregated concurrent rule
+template<typename State> class AggregatedConcurrentRule;
+
+template<typename State> class ConcurrentRule : public STest::Rule<State> {
+    friend class AggregatedConcurrentRule<State>;
+  public:
+    ConcurrentRule(const char *const name, AggregatedConcurrentRule<State>& runner) : STest::Rule<State>(name), m_runner(runner) {
+        this->m_runner.add(*this);
+        this->m_condition_value = false;
+    }
+
+    virtual ~ConcurrentRule() {
+        this->m_runner.remove(*this);
+    }
+
+    //! Launch this rule asynchronously
+    void action_async(State& state) {
+        this->is_asynchronous = true;
+        this->m_state = &state;
+        Os::Task::Arguments arguments(Os::TaskString(this->getName()), this->run, this);
+        m_task.start(arguments);
+    }
+
+    //! Static function to "apply" this rule using a task
+    static void run(void* rule_pointer) {
+        ASSERT_NE(rule_pointer, nullptr) << "Passed null input to task";
+        ConcurrentRule<State>* self = reinterpret_cast<ConcurrentRule<State>*>(rule_pointer);
+        ASSERT_TRUE(self->is_asynchronous) << "Rule " << self->getName() << " not run in aggregated concurrent rule";
+        ASSERT_TRUE(self->precondition(*self->m_state)) << "precondition failed applying rule " << self->getName();
+
+        // Ensure this rule owns the global state
+        Os::ScopeLock lock(self->getLock());
+        self->action(*self->m_state);
+    }
+
+  protected:
+    //! \brief wait until notified to take the next step
+    void wait_for_next_step() {
+        ASSERT_TRUE(this->is_asynchronous) << "Rule " << this->getName() << " not run in aggregated concurrent rule";
+        while (not this->m_condition_value) {
+            this->m_condition.wait(this->getLock());
+        }
+        this->m_condition_value = false;
+    }
+
+    //! \brief get lock
+    Os::Mutex& getLock() {
+        return this->m_runner.getLock();
+    }
+
+    //! \brief notify another rule by nae,
+    void notify_other(std::string other) {
+        this->m_runner.notify(other);
+    }
+
+    //! \brief get the condition variable
+    bool getCondition() {
+        return this->m_condition_value;
+    }
+
+  protected:
+    void join() {
+        this->m_task.join();
+    }
+
+    //! \brief notify this rule to take the next step
+    void step() {
+        this->m_condition_value = true;
+        this->m_condition.notify();
+    }
+
+    //! Reference to the runner
+    AggregatedConcurrentRule<State>& m_runner;
+
+    //! Local store of state for concurrent action
+    State* m_state;
+    //! Task to run this rule in asynchronous context
+    Os::Task m_task;
+    //! Condition variable used to set up this rule
+    Os::ConditionVariable m_condition;
+
+    //! Condition guarded by condition variable
+    std::atomic<bool> m_condition_value;
+
+    //! A check to ensure this rule was launched asynchronously when using the blocking wait function
+    bool is_asynchronous = false;
+};
+
+template<typename State> class PseudoRule : public ConcurrentRule<State> {
+  public:
+    PseudoRule(const char* name, AggregatedConcurrentRule<State>& runner)
+        : ConcurrentRule<State>(name, runner) {}
+
+    bool precondition(const State& state) override {
+        return true;
+    }
+
+    void action(State& state) override {}
+
+    void wait_for_next_step() {
+        this->ConcurrentRule<State>::wait_for_next_step();
+    }
+
+
+};
+
+template<typename State> class ConcurrentWrapperRule : public ConcurrentRule<State> {
+  public:
+    ConcurrentWrapperRule(AggregatedConcurrentRule<State>& runner, STest::Rule<State>& wrapped, std::string notify, const char* name=nullptr)
+        : ConcurrentRule<State>((name == nullptr) ? wrapped.getName() : name, runner), m_wrapped(wrapped), m_notify(notify) {
+
+    }
+
+    bool precondition(const State& state) override {
+        return m_wrapped.precondition(state);
+    }
+
+    void action(State& state) override {
+        this->wait_for_next_step(); // Wait until told to go
+        this->m_wrapped.apply(state); // Go
+        this->notify_other(this->m_notify); // Notify when done
+    }
+  private:
+
+    STest::Rule<State>& m_wrapped;
+    std::string m_notify;
+};
+
+
+template<typename State> class AggregatedConcurrentRule : public STest::Rule<State> {
+  public:
+    //! Creation
+    AggregatedConcurrentRule() : STest::Rule<State>("aggregated-rule") {}
+    ~AggregatedConcurrentRule() = default;
+
+    //! Add a rule (on construction of rule)
+    void add(ConcurrentRule<State>& rule) {
+        Os::ScopeLock lock(this->m_lock);
+        m_rules.push_back(&rule);
+        m_rule_map[rule.getName()] = &rule;
+    }
+
+    //! Remove a rule (on destruction of rule)
+    void remove(ConcurrentRule<State>& rule) {
+        Os::ScopeLock lock(this->m_lock);
+        m_rules.remove(&rule);
+        // Remove rule from m_rules_map
+        for (auto it = m_rule_map.begin(); it != m_rule_map.end(); it++) {
+            if (it->second == &rule) {
+                m_rule_map.erase(it);
+                break;
+            }
+        }
+    }
+
+    // Notify a rule by name
+    void notify(std::string& name) {
+        // Notify all matching rules
+        for (auto pair : m_rule_map) {
+            if (std::string(pair.second->getName()) == name) {
+                pair.second->step();
+                return;
+            }
+        }
+        ASSERT_TRUE(false) << "Failed to find rule to notify";
+    }
+
+    Os::Mutex& getLock() {
+        return this->m_lock;
+    }
+
+    //! Aggregate rule may only run if
+    bool precondition(const State& state) override {
+        for (ConcurrentRule<State>* rule : m_rules) {
+            if (not rule->precondition(state)) {
+                return false;
+            }
+        }
+        return true;
+    };
+
+    //! Action is to run all rules then wait for all rules to finish
+    void action(State& state) override {
+        // Launch asynchronous rules
+        {
+            Os::ScopeLock lock(this->m_lock);
+            for (ConcurrentRule<State>* rule : m_rules) {
+                rule->action_async(state);
+            }
+        }
+    }
+
+    void join() {
+        // Wait for asynchronous rules to finish
+        for (ConcurrentRule<State>* rule : m_rules) {
+            rule->join();
+        }
+    }
+
+  private:
+    Os::Mutex m_lock;
+    std::list<ConcurrentRule<State>*> m_rules;
+    std::map<std::string, ConcurrentRule<State>*> m_rule_map;
+};
+
+#endif //OS_TEST_CONCURRENT_RULE
diff --git a/Os/test/ut/OsQueueTest.cpp b/Os/test/ut/OsQueueTest.cpp
deleted file mode 100644
index 8d24a57544..0000000000
--- a/Os/test/ut/OsQueueTest.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
-#include "gtest/gtest.h"
-#include <Os/Queue.hpp>
-#include <cstdio>
-#include <cstring>
-#include <Fw/Types/Assert.hpp>
-#include <unistd.h>
-#include <csignal>
-#include <pthread.h>
-
-#if defined TGT_OS_TYPE_LINUX
-#include <ctime>
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-#include <sys/time.h>
-#endif
-
-// Set this to 1 if testing a priority queue
-// Set this to 0 if testing a fifo queue
-#define PRIORITY_QUEUE 1
-
-enum {
-        SER_BUFFER_SIZE = 100,
-        QUEUE_SIZE = 10
-};
-
-class MyTestSerializedBuffer : public Fw::SerializeBufferBase {
-    public:
-        MyTestSerializedBuffer() { memset(m_someBuffer, 0, sizeof(m_someBuffer)); }
-        ~MyTestSerializedBuffer() {}
-        NATIVE_UINT_TYPE getBuffCapacity() const { return sizeof(this->m_someBuffer); }
-        U8* getBuffAddr() { return m_someBuffer;}
-        const U8* getBuffAddr() const {return m_someBuffer;}
-    private:
-        U8 m_someBuffer[SER_BUFFER_SIZE];
-};
-
-Os::Queue* createTestQueue(const char *name, U32 size, I32 depth) {
-    Os::Queue* testQueue = new Os::Queue();
-    Os::Queue::QueueStatus stat = testQueue->create(Os::QueueString(name), depth, size);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-
-    // Make sure the queue is of the correct size:
-    NATIVE_INT_TYPE num;
-    num = testQueue->getNumMsgs(); //!< get the number of messages in the queue
-    EXPECT_EQ(num, 0);
-    num = testQueue->getMaxMsgs(); //!< get the maximum number of messages (high watermark)
-    EXPECT_EQ(num, 0);
-    num = testQueue->getQueueSize(); //!< get the queue depth (maximum number of messages queue can hold)
-    EXPECT_EQ(num, depth);
-    num = testQueue->getMsgSize(); //!< get the message size (maximum message size queue can hold)
-    EXPECT_EQ(num, static_cast<I32>(size));
-
-    return testQueue;
-}
-
-MyTestSerializedBuffer getSendBuffer(I32 startByte) {
-    Fw::SerializeStatus serStat;
-    MyTestSerializedBuffer sendBuff;
-    NATIVE_UINT_TYPE size = sendBuff.getBuffCapacity() - sizeof(NATIVE_UINT_TYPE);
-
-    // Fill serialized buffer with data:
-    U8 sendDataBuff[SER_BUFFER_SIZE];
-    I32 count = startByte;
-    for (U32 byte = 0; byte < size; byte++) {
-        sendDataBuff[byte] = count;
-        count++;
-    }
-    serStat = sendBuff.serialize(sendDataBuff, size);
-    EXPECT_EQ(serStat,Fw::FW_SERIALIZE_OK);
-    return sendBuff;
-}
-
-void compareBuffers(MyTestSerializedBuffer& a, MyTestSerializedBuffer& b) {
-    NATIVE_UINT_TYPE size = a.getBuffCapacity() - sizeof(NATIVE_UINT_TYPE);
-    Fw::SerializeStatus serStat;
-    U8 aBuff[SER_BUFFER_SIZE];
-    serStat = a.deserialize(aBuff, size);
-    EXPECT_EQ(serStat,Fw::FW_SERIALIZE_OK);
-    U8 bBuff[SER_BUFFER_SIZE];
-    serStat = b.deserialize(bBuff, size);
-    EXPECT_EQ(serStat,Fw::FW_SERIALIZE_OK);
-
-    for (U32 ii = 0; ii < size; ii++) {
-        if (aBuff[ii] != bBuff[ii]) {
-            printf("Byte %u mismatch. A: %d B: %d\n", ii, aBuff[ii], bBuff[ii]);
-            EXPECT_TRUE(0);
-        }
-    }
-}
-
-void fillQueue(Os::Queue* queue) {
-    // Fill the queue.
-    // Note this loop should only need to go to QUEUE_SIZE,
-    // but the SysV queues don't actually have a size, so
-    // instead we loop until we get a queue full response:
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    Os::Queue::QueueStatus stat;
-    for( NATIVE_INT_TYPE ii = 0; ii < QUEUE_SIZE*100; ii++ ) {
-        stat = queue->send(sendBuff, 0, Os::Queue::QUEUE_NONBLOCKING);
-        if(stat == Os::Queue::QUEUE_FULL)
-          break;
-        EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-    }
-}
-
-void drainQueue(Os::Queue* queue) {
-    // Fill the queue.
-    // Note this loop should only need to go to QUEUE_SIZE,
-    // but the SysV queues don't actually have a size, so
-    // instead we loop until we get a queue full response:
-    MyTestSerializedBuffer recvBuff;
-    I32 prio;
-    Os::Queue::QueueStatus stat;
-    while (queue->getNumMsgs() > 0) {
-        stat = queue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-        EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-    }
-}
-
-extern "C" {
-    void qtest_block_receive();
-    void qtest_nonblock_receive();
-    void qtest_performance();
-    void qtest_nonblock_send();
-    void qtest_block_send();
-    void qtest_concurrent();
-}
-
-// Alarm signal handler for waking up a blocked queue:
-Os::Queue* globalQueue = nullptr;
-void alarm_send_block(int sig)
-{
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    Os::Queue::QueueStatus stat;
-    stat = globalQueue->send(sendBuff, 0, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-}
-
-void alarm_send_nonblock(int sig)
-{
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    Os::Queue::QueueStatus stat;
-    stat = globalQueue->send(sendBuff, 0, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-}
-
-void alarm_receive_block(int sig)
-{
-    MyTestSerializedBuffer recvBuff;
-    Os::Queue::QueueStatus stat;
-    I32 prio;
-    stat = globalQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-}
-
-void alarm_receive_nonblock(int sig)
-{
-    MyTestSerializedBuffer recvBuff;
-    Os::Queue::QueueStatus stat;
-    I32 prio;
-    stat = globalQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-}
-
-void alarm_error(int sig)
-{
-    // A failure here means that something blocked that was
-    // not supposed to block!
-    EXPECT_TRUE(0);
-}
-
-// This test verifies queue behavior for active components
-// ie. non-blocking send on queue full, blocking receive on queue empty
-void qtest_nonblock_send() {
-    printf("-----------------------------\n");
-    printf("-- nonblocking send test ----\n");
-    printf("-----------------------------\n");
-    Os::Queue* testQueue = createTestQueue("TestQ",SER_BUFFER_SIZE,QUEUE_SIZE);
-    Os::Queue::QueueStatus stat;
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-
-    // TEST 1
-    printf("Testing non-blocking send on queue full...\n");
-    // Register an alarm handler to wake us up in case we block:
-    globalQueue = testQueue;
-    signal(SIGALRM, alarm_error);
-    alarm(2);
-    fillQueue(testQueue);
-    // Make sure we get a queue full response:
-    stat = testQueue->send(sendBuff, 0, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_FULL);
-    // Reset the alarm:
-    alarm(0);
-    drainQueue(testQueue);
-    globalQueue = nullptr;
-    printf("Passed.\n");
-
-    delete testQueue;
-    printf("Test complete.\n");
-    printf("-----------------------------\n");
-    printf("-----------------------------\n");
-}
-
-void qtest_block_send() {
-    printf("-----------------------------\n");
-    printf("---- blocking send test -----\n");
-    printf("-----------------------------\n");
-    Os::Queue* testQueue = createTestQueue("TestQ",SER_BUFFER_SIZE,QUEUE_SIZE);
-    Os::Queue::QueueStatus stat;
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-
-    // TEST 1
-    printf("Testing blocking send on queue full with blocking receive...\n");
-    // Register an alarm handler to wake us up in case we block:
-    globalQueue = testQueue;
-    signal(SIGALRM, alarm_receive_block);
-    alarm(2);
-    fillQueue(testQueue);
-    // Make sure we get a queue full response:
-    stat = testQueue->send(sendBuff, 0, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-    // Reset the alarm:
-    alarm(0);
-    drainQueue(testQueue);
-    globalQueue = nullptr;
-    printf("Passed.\n");
-
-    // TEST 2
-    printf("Testing blocking send on queue full nonblocking receive...\n");
-    // Register an alarm handler to wake us up in case we block:
-    globalQueue = testQueue;
-    signal(SIGALRM, alarm_receive_nonblock);
-    alarm(2);
-    fillQueue(testQueue);
-    // Make sure we get a queue full response:
-    stat = testQueue->send(sendBuff, 0, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat, Os::Queue::QUEUE_OK);
-    // Reset the alarm:
-    alarm(0);
-    drainQueue(testQueue);
-    globalQueue = nullptr;
-    printf("Passed.\n");
-
-    delete testQueue;
-    printf("Test complete.\n");
-    printf("-----------------------------\n");
-    printf("-----------------------------\n");
-}
-
-// This test verifies queue behavior for active components
-// ie. non-blocking send on queue full, blocking receive on queue empty
-void qtest_block_receive() {
-    printf("-----------------------------\n");
-    printf("-- blocking receive test ----\n");
-    printf("-----------------------------\n");
-    Os::Queue* testQueue = createTestQueue("TestQ",SER_BUFFER_SIZE,QUEUE_SIZE);
-    Os::Queue::QueueStatus stat;
-    MyTestSerializedBuffer recvBuff;
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    I32 prio; // not used
-
-    // TEST 1
-    printf("Testing successful receive after send...\n");
-    stat = testQueue->send(sendBuff, 0, Os::Queue::QUEUE_NONBLOCKING);
-    ASSERT_EQ(stat, Os::Queue::QUEUE_OK);
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    ASSERT_EQ(stat, Os::Queue::QUEUE_OK);
-    compareBuffers(sendBuff, recvBuff);
-    printf("Passed.\n");
-
-    // TEST 2
-    printf("Testing blocking receive on queue empty with blocking send...\n");
-    // Register an alarm handler to wake us after waiting on the queue:
-    globalQueue = testQueue;
-    signal(SIGALRM, alarm_send_block);
-    alarm(2);
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    globalQueue = nullptr;
-    printf("Passed.\n");
-
-    // TEST 3
-    printf("Testing blocking receive on queue empty with nonblocking send...\n");
-    // Register an alarm handler to wake us after waiting on the queue:
-    globalQueue = testQueue;
-    signal(SIGALRM, alarm_send_nonblock);
-    alarm(2);
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    globalQueue = nullptr;
-    printf("Passed.\n");
-
-    // TEST 5
-    printf("Test send and receive with priorities...\n");
-    // Send messages with mixed priorities,
-    // and make sure we get back the buffers in
-    // the correct order.
-    I32 sendBuffStart[6] = {11, 45, 70, 123, 200, 400};
-    NATIVE_INT_TYPE priorities[6] = {0, 50, 50, 99, 0, 16};
-    for( I32 ii = 0; ii < 6; ii++ ) {
-      // Generate a new send buffer for each enqueue:
-      MyTestSerializedBuffer sendBuff2 = getSendBuffer(sendBuffStart[ii]);
-      stat = testQueue->send(sendBuff2, priorities[ii], Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    }
-
-#if PRIORITY_QUEUE
-    I32 expectedSendBuffStart[6] = {123, 45, 70, 400, 11, 200};
-    NATIVE_INT_TYPE expectedPriorities[6] = {99, 50, 50, 16, 0, 0};
-#else
-    I32 expectedSendBuffStart[6] = {11, 45, 70, 123, 200, 400};
-    NATIVE_INT_TYPE expectedPriorities[6] = {0, 0, 0, 0, 0, 0};
-#endif
-    for( I32 ii = 0; ii < 6; ii++ ) {
-      // Generate a new send buffer for each enqueue:
-      MyTestSerializedBuffer expectedSendBuff2 = getSendBuffer(expectedSendBuffStart[ii]);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      EXPECT_EQ(prio,expectedPriorities[ii]);
-      EXPECT_TRUE(memcmp(recvBuff.getBuffAddr(), expectedSendBuff2.getBuffAddr(), recvBuff.getBuffLength()) == 0);
-    }
-    printf("Passed.\n");
-
-    delete testQueue;
-    printf("Test complete.\n");
-    printf("-----------------------------\n");
-    printf("-----------------------------\n");
-}
-
-// This test verifies queue behavior for queued components
-// ie. non-blocking send on queue full, non-blocking receive on queue empty
-void qtest_nonblock_receive() {
-    printf("-----------------------------\n");
-    printf("- nonblocking receive test --\n");
-    printf("-----------------------------\n");
-    Os::Queue* testQueue = createTestQueue("TestQ", SER_BUFFER_SIZE, QUEUE_SIZE);
-    Os::Queue::QueueStatus stat;
-    MyTestSerializedBuffer recvBuff;
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    I32 prio; // not used
-
-    // TEST 1
-    printf("Testing successful receive after send...\n");
-    stat = testQueue->send(sendBuff, 0, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    compareBuffers(sendBuff, recvBuff);
-    printf("Passed.\n");
-
-    // TEST 2
-    printf("Testing non-blocking receive on queue empty...\n");
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_NO_MORE_MSGS);
-    printf("Passed.\n");
-
-    // TEST 3
-    printf("Test send and receive with priorities...\n");
-    // Send messages with mixed priorities,
-    // and make sure we get back the buffers in
-    // the correct order.
-    I32 sendBuffStart[6] = {11, 45, 70, 123, 200, 400};
-    NATIVE_INT_TYPE priorities[6] = {0, 50, 50, 99, 0, 16};
-    for( I32 ii = 0; ii < 6; ii++ ) {
-      // Generate a new send buffer for each enqueue:
-      MyTestSerializedBuffer sendBuff2 = getSendBuffer(sendBuffStart[ii]);
-      stat = testQueue->send(sendBuff2, priorities[ii], Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    }
-
-#if PRIORITY_QUEUE
-    I32 expectedSendBuffStart[6] = {123, 45, 70, 400, 11, 200};
-    NATIVE_INT_TYPE expectedPriorities[6] = {99, 50, 50, 16, 0, 0};
-#else
-    I32 expectedSendBuffStart[6] = {11, 45, 70, 123, 200, 400};
-    NATIVE_INT_TYPE expectedPriorities[6] = {0, 0, 0, 0, 0, 0};
-#endif
-    for( I32 ii = 0; ii < 6; ii++ ) {
-      // Generate a new send buffer for each enqueue:
-      MyTestSerializedBuffer expectedSendBuff2 = getSendBuffer(expectedSendBuffStart[ii]);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      EXPECT_EQ(prio,expectedPriorities[ii]);
-      EXPECT_TRUE(memcmp(recvBuff.getBuffAddr(), expectedSendBuff2.getBuffAddr(), recvBuff.getBuffLength()) == 0);
-    }
-    printf("Passed.\n");
-
-    delete testQueue;
-    printf("Test complete.\n");
-    printf("-----------------------------\n");
-    printf("-----------------------------\n");
-}
-
-// This test shows the performance of the queue:
-void qtest_performance() {
-    printf("-----------------------------\n");
-    printf("---- performance test -------\n");
-    printf("-----------------------------\n");
-    Os::Queue* testQueue = createTestQueue("TestQ", SER_BUFFER_SIZE, 10);
-    Os::Queue::QueueStatus stat;
-    MyTestSerializedBuffer recvBuff;
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    I32 prio; // not used
-    F64 elapsedTime;
-    I32 numIterations;
-
-#if defined TGT_OS_TYPE_LINUX
-    timespec stime;
-    timespec etime;
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    timeval stime;
-    timeval etime;
-#endif
-
-    // TEST 1
-    printf("Testing shallow queue...\n");
-#if defined TGT_OS_TYPE_LINUX
-    (void)clock_gettime(CLOCK_REALTIME,&stime);
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    (void)gettimeofday(&stime,nullptr);
-#endif
-    numIterations = 1000000;
-    for( NATIVE_INT_TYPE ii = 0; ii < numIterations; ii++ ) {
-      stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    }
-#if defined TGT_OS_TYPE_LINUX
-    (void)clock_gettime(CLOCK_REALTIME,&etime);
-    elapsedTime = static_cast<F64>(etime.tv_sec - stime.tv_sec) + static_cast<F64>(etime.tv_nsec - stime.tv_nsec)/1000000000;
-    printf("Time: %0.3fs (%0.3fus per)\n", elapsedTime, 1000000*elapsedTime/static_cast<F64>(numIterations));
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    (void)gettimeofday(&etime,nullptr);
-    elapsedTime = static_cast<F64>(etime.tv_sec - stime.tv_sec) + static_cast<F64>(etime.tv_usec - stime.tv_usec)/1000000;
-    printf("Time: %0.3fs (%0.3fus per)\n", elapsedTime, 1000000*elapsedTime/static_cast<F64>(numIterations));
-#endif
-
-    // TEST 2
-    printf("Testing deep queue...\n");
-    // Fill the queue up first:
-    U32 count = 0;
-    while(true) {
-      stat = testQueue->send(sendBuff, count%4, Os::Queue::QUEUE_NONBLOCKING);
-      count++;
-      if(stat == Os::Queue::QUEUE_FULL)
-        break;
-    }
-#if defined TGT_OS_TYPE_LINUX
-    (void)clock_gettime(CLOCK_REALTIME,&stime);
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    (void)gettimeofday(&stime,nullptr);
-#endif
-    numIterations = 1000000;
-    for( NATIVE_INT_TYPE ii = 0; ii < numIterations; ii++ ) {
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-      stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-      EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    }
-#if defined TGT_OS_TYPE_LINUX
-    (void)clock_gettime(CLOCK_REALTIME,&etime);
-    elapsedTime = static_cast<F64>(etime.tv_sec - stime.tv_sec) + static_cast<F64>(etime.tv_nsec - stime.tv_nsec)/1000000000;
-    printf("Time: %0.3fs (%0.3fus per)\n", elapsedTime, 1000000*elapsedTime/static_cast<F64>(numIterations));
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    (void)gettimeofday(&etime,nullptr);
-    elapsedTime = static_cast<F64>(etime.tv_sec - stime.tv_sec) + static_cast<F64>(etime.tv_usec - stime.tv_usec)/1000000;
-    printf("Time: %0.3fs (%0.3fus per)\n", elapsedTime, 1000000*elapsedTime/static_cast<F64>(numIterations));
-#endif
-    while(true) {
-      stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_NONBLOCKING);
-      if(stat == Os::Queue::QUEUE_NO_MORE_MSGS)
-        break;
-    }
-
-    delete testQueue;
-    printf("Test complete.\n");
-    printf("-----------------------------\n");
-    printf("-----------------------------\n");
-}
-
-#define NUM_THREADS 4
-I32 numIterations = 50000;
-void *run_task(void *ptr)
-{
-  Os::Queue* testQueue = static_cast<Os::Queue*>(ptr);
-  Os::Queue::QueueStatus stat;
-  I32 prio; // not used
-  MyTestSerializedBuffer recvBuff;
-  MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-  for( NATIVE_INT_TYPE ii = 0; ii < numIterations; ii++ ) {
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    stat = testQueue->receive(recvBuff, prio, Os::Queue::QUEUE_BLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-    stat = testQueue->send(sendBuff, ii%4, Os::Queue::QUEUE_NONBLOCKING);
-    EXPECT_EQ(stat,Os::Queue::QUEUE_OK);
-  }
-  return nullptr;
-}
-
-// This test shows the concurrent performance of the queue:
-void qtest_concurrent() {
-
-    printf("---------------------\n");
-    printf("-- concurrent test --\n");
-    printf("---------------------\n");
-    Os::Queue* testQueue = createTestQueue("TestQ", SER_BUFFER_SIZE, 10);
-    Os::Queue::QueueStatus stat;
-    MyTestSerializedBuffer recvBuff;
-    MyTestSerializedBuffer sendBuff = getSendBuffer(0);
-    F64 elapsedTime;
-
-#if defined TGT_OS_TYPE_LINUX
-    timespec stime;
-    timespec etime;
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    timeval stime;
-    timeval etime;
-#endif
-
-    printf("Testing deep queue...\n");
-    // Fill the queue up first:
-    U32 count = 0;
-    while(true) {
-      stat = testQueue->send(sendBuff,count%4, Os::Queue::QUEUE_NONBLOCKING);
-      count++;
-      if(stat == Os::Queue::QUEUE_FULL)
-        break;
-    }
-#if defined TGT_OS_TYPE_LINUX
-    (void)clock_gettime(CLOCK_REALTIME,&stime);
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    (void)gettimeofday(&stime,nullptr);
-#endif
-
-#if defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
-    pthread_t thread[NUM_THREADS];
-
-    for(U32 ii = 0; ii < NUM_THREADS; ++ii) {
-      if(pthread_create(&thread[ii], nullptr, run_task, testQueue)) {
-        EXPECT_TRUE(0);
-      }
-    }
-
-    for(U32 ii = 0; ii < NUM_THREADS; ++ii) {
-      if(pthread_join(thread[ii], nullptr)) {
-        EXPECT_TRUE(0);
-      }
-    }
-#endif
-
-#if defined TGT_OS_TYPE_LINUX
-    (void)clock_gettime(CLOCK_REALTIME,&etime);
-    elapsedTime = static_cast<F64>(etime.tv_sec - stime.tv_sec) + static_cast<F64>(etime.tv_nsec - stime.tv_nsec)/1000000000;
-    printf("Time: %0.3fs (%0.3fus per)\n", elapsedTime, 1000000*elapsedTime/static_cast<F64>(numIterations));
-#endif
-#if defined TGT_OS_TYPE_DARWIN
-    (void)gettimeofday(&etime,nullptr);
-    elapsedTime = static_cast<F64>(etime.tv_sec - stime.tv_sec) + static_cast<F64>(etime.tv_usec - stime.tv_usec)/1000000;
-    printf("Time: %0.3fs (%0.3fus per)\n", elapsedTime, 1000000*elapsedTime/static_cast<F64>(numIterations));
-#endif
-
-    delete testQueue;
-    printf("Test complete.\n");
-    printf("---------------------\n");
-    printf("---------------------\n");
-}
diff --git a/Os/test/ut/OsTestMain.cpp b/Os/test/ut/OsTestMain.cpp
index 0c3421f1a3..8a0d07687a 100644
--- a/Os/test/ut/OsTestMain.cpp
+++ b/Os/test/ut/OsTestMain.cpp
@@ -4,19 +4,19 @@
 #include <cstdio>
 
 extern "C" {
-  void qtest_block_receive();
+/*  void qtest_block_receive();
   void qtest_nonblock_receive();
   void qtest_nonblock_send();
   void qtest_block_send();
   void qtest_performance();
-  void qtest_concurrent();
+  void qtest_concurrent();*/
   void intervalTimerTest();
   void validateFileTest(const char* filename);
   void systemResourcesTest();
   void mutexBasicLockableTest();
 }
 const char* filename;
-TEST(Nominal, QTestBlockRecv) {
+/*TEST(Nominal, QTestBlockRecv) {
    qtest_block_receive();
 }
 TEST(Nominal, QTestNonBlockRecv) {
@@ -34,7 +34,7 @@ TEST(Nominal, QTestPerformance) {
 TEST(Nominal, QTestConcurrentTest) {
    qtest_concurrent();
 }
-
+*/
 // The interval timer unit test is timed off a 1 sec thread delay. Mac OS allows a large amount of
 // scheduling jitter to conserve energy, which rarely causes this sleep to be slightly shorter
 // (~0.99 s) or longer (~10 sec) than requested, causing the test to fail. The interval timer should
diff --git a/Os/test/ut/condition/CommonTests.cpp b/Os/test/ut/condition/CommonTests.cpp
new file mode 100644
index 0000000000..2bab51ef59
--- /dev/null
+++ b/Os/test/ut/condition/CommonTests.cpp
@@ -0,0 +1,46 @@
+// ======================================================================
+// \title Os/test/ut/condition/CommonTests.cpp
+// \brief common test implementations
+// ======================================================================
+#include "Os/test/ut/condition/CommonTests.hpp"
+#include <gtest/gtest.h>
+#include "Fw/Types/String.hpp"
+#include "Os/test/ConcurrentRule.hpp"
+#include "Os/test/ut/condition/RulesHeaders.hpp"
+
+
+TEST(Blocking, WaitSingle) {
+    Os::Test::Condition::Tester tester;
+    AggregatedConcurrentRule<Os::Test::Condition::Tester> aggregator;
+    Os::Test::Condition::Tester::Wait wait_rule(aggregator);
+    Os::Test::Condition::Tester::Notify notify_rule(aggregator);
+
+    aggregator.apply(tester);
+    aggregator.join();
+}
+
+TEST(Blocking, WaitAll) {
+    Os::Test::Condition::Tester tester;
+    AggregatedConcurrentRule<Os::Test::Condition::Tester> aggregator;
+    PseudoRule<Os::Test::Condition::Tester> pseudoRule("Notify", aggregator);
+    Os::Test::Condition::Tester::Wait wait_rule1(aggregator);
+    Os::Test::Condition::Tester::Wait wait_rule2(aggregator);
+    Os::Test::Condition::Tester::NotifyAll notify_rule(aggregator);
+    aggregator.apply(tester);
+    {
+        Os::ScopeLock lock(aggregator.getLock());
+        while (tester.m_waiters != 2) {
+            pseudoRule.wait_for_next_step();
+        }
+    }
+    std::string to_notify("NotifyAll");
+    aggregator.notify(to_notify);
+    {
+        Os::ScopeLock lock(aggregator.getLock());
+        while (tester.m_waiters > 0) {
+            pseudoRule.wait_for_next_step();
+        }
+    }
+    aggregator.notify(to_notify);
+    aggregator.join();
+}
diff --git a/Os/test/ut/condition/CommonTests.hpp b/Os/test/ut/condition/CommonTests.hpp
new file mode 100644
index 0000000000..af91f85598
--- /dev/null
+++ b/Os/test/ut/condition/CommonTests.hpp
@@ -0,0 +1,8 @@
+// ======================================================================
+// \title Os/test/ut/condition/CommonTests.hpp
+// \brief required header
+// ======================================================================
+#include "RulesHeaders.hpp"
+#ifndef OS_TEST_UT_QUEUE_COMMON_TESTS_HPP
+#define OS_TEST_UT_QUEUE_COMMON_TESTS_HPP
+#endif  // OS_TEST_UT_QUEUE_COMMON_TESTS_HPP
diff --git a/Os/test/ut/condition/ConditionRules.cpp b/Os/test/ut/condition/ConditionRules.cpp
new file mode 100644
index 0000000000..c086407b23
--- /dev/null
+++ b/Os/test/ut/condition/ConditionRules.cpp
@@ -0,0 +1,79 @@
+// ======================================================================
+// \title Os/test/ut/condition/ConditionRules.cpp
+// \brief condition variables rule implementations
+// ======================================================================
+
+#include "CommonTests.hpp"
+#include "Fw/Types/String.hpp"
+
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Wait
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Condition::Tester::Wait::Wait(AggregatedConcurrentRule<Os::Test::Condition::Tester>& runner)
+    : ConcurrentRule<Os::Test::Condition::Tester>("Wait", runner) {}
+
+bool Os::Test::Condition::Tester::Wait::precondition(const Os::Test::Condition::Tester& state  //!< The test state
+) {
+    return true;
+}
+
+void Os::Test::Condition::Tester::Wait::action(Os::Test::Condition::Tester& state  //!< The test state
+) {
+    state.m_notify = false;
+    state.m_waiters += 1;
+    this->notify_other("Notify");
+    state.m_condition.wait(this->getLock());
+    ASSERT_TRUE(state.m_notify) << "Notify was not set";
+    state.m_waiters -= 1;
+    this->notify_other("Notify");
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Notify
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Condition::Tester::Notify::Notify(AggregatedConcurrentRule<Os::Test::Condition::Tester>& runner)
+    : ConcurrentRule<Os::Test::Condition::Tester>("Notify", runner) {}
+
+bool Os::Test::Condition::Tester::Notify::precondition(const Os::Test::Condition::Tester& state  //!< The test state
+) {
+    return true;
+}
+
+void Os::Test::Condition::Tester::Notify::action(Os::Test::Condition::Tester& state  //!< The test state
+) {
+    FwSizeType waiters = 0;
+    this->wait_for_next_step();
+    waiters = state.m_waiters;
+    state.m_notify = true;
+    state.m_condition.notify();
+    // Wait for notification and ensure exactly one waiter woke up
+    this->wait_for_next_step();
+    ASSERT_EQ(waiters - 1, state.m_waiters);
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  NotifyAll
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Condition::Tester::NotifyAll::NotifyAll(AggregatedConcurrentRule<Os::Test::Condition::Tester>& runner)
+    : ConcurrentRule<Os::Test::Condition::Tester>("NotifyAll", runner) {}
+
+bool Os::Test::Condition::Tester::NotifyAll::precondition(const Os::Test::Condition::Tester& state  //!< The test state
+) {
+    return true;
+}
+
+void Os::Test::Condition::Tester::NotifyAll::action(Os::Test::Condition::Tester& state  //!< The test state
+) {
+    this->wait_for_next_step();
+    state.m_notify = true;
+    state.m_condition.notifyAll();
+    this->wait_for_next_step();
+    ASSERT_EQ(0, state.m_waiters);
+}
diff --git a/Os/test/ut/condition/ConditionRules.hpp b/Os/test/ut/condition/ConditionRules.hpp
new file mode 100644
index 0000000000..b204b82481
--- /dev/null
+++ b/Os/test/ut/condition/ConditionRules.hpp
@@ -0,0 +1,81 @@
+// ======================================================================
+// \title Os/test/ut/condition/ConditionRules.hpp
+// \brief condition variables rule definitions
+// ======================================================================
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Wait
+//
+// ------------------------------------------------------------------------------------------------------
+struct Wait : public ConcurrentRule<Os::Test::Condition::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit Wait(AggregatedConcurrentRule<Os::Test::Condition::Tester>& runner);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Condition::Tester& state  //!< The test state
+                      ) override;
+
+    //! Action
+    void action(Os::Test::Condition::Tester& state  //!< The test state
+                ) override;
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Notify
+//
+// ------------------------------------------------------------------------------------------------------
+struct Notify : public ConcurrentRule<Os::Test::Condition::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit Notify(AggregatedConcurrentRule<Os::Test::Condition::Tester>& runner);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Condition::Tester& state  //!< The test state
+                      ) override;
+
+    //! Action
+    void action(Os::Test::Condition::Tester& state  //!< The test state
+                ) override;
+};
+
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  NotifyAll
+//
+// ------------------------------------------------------------------------------------------------------
+struct NotifyAll : public ConcurrentRule<Os::Test::Condition::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit NotifyAll(AggregatedConcurrentRule<Os::Test::Condition::Tester>& runner);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Condition::Tester& state  //!< The test state
+                      ) override;
+
+    //! Action
+    void action(Os::Test::Condition::Tester& state  //!< The test state
+                ) override;
+
+};
diff --git a/Os/test/ut/condition/RulesHeaders.hpp b/Os/test/ut/condition/RulesHeaders.hpp
new file mode 100644
index 0000000000..97183ac9f6
--- /dev/null
+++ b/Os/test/ut/condition/RulesHeaders.hpp
@@ -0,0 +1,39 @@
+// ======================================================================
+// \title Os/test/ut/condition/RulesHeaders.cpp
+// \brief condition test rules headers
+// ======================================================================
+
+#ifndef OS_TEST_CONDITION_RULES_HEADERS__
+#define OS_TEST_CONDITION_RULES_HEADERS__
+
+#include "Os/Condition.hpp"
+#include "Os/test/ConcurrentRule.hpp"
+#include "STest/Rule/Rule.hpp"
+#include "STest/Scenario/BoundedScenario.hpp"
+#include "STest/Scenario/RandomScenario.hpp"
+#include "STest/Scenario/Scenario.hpp"
+
+
+namespace Os {
+namespace Test {
+namespace Condition {
+
+struct Tester {
+  public:
+    //! Constructor
+    Tester() = default;
+    virtual ~Tester() = default;
+
+    Os::ConditionVariable m_condition;
+    bool m_notify = false;
+    FwSizeType m_waiters = 0;
+
+  public:
+#include "ConditionRules.hpp"
+};
+
+}  // namespace Queue
+}  // namespace Test
+}  // namespace Os
+
+#endif
diff --git a/Os/test/ut/queue/CommonTests.cpp b/Os/test/ut/queue/CommonTests.cpp
new file mode 100644
index 0000000000..64c07ff14c
--- /dev/null
+++ b/Os/test/ut/queue/CommonTests.cpp
@@ -0,0 +1,335 @@
+// ======================================================================
+// \title Os/test/ut/queue/CommonTests.cpp
+// \brief common test implementations
+// ======================================================================
+#include "Os/test/ut/queue/CommonTests.hpp"
+#include <gtest/gtest.h>
+#include "Fw/Types/String.hpp"
+#include "Os/Queue.hpp"
+#include "Os/test/ConcurrentRule.hpp"
+#include "Os/test/ut/queue/RulesHeaders.hpp"
+
+const FwSizeType RANDOM_BOUND = 10000;
+
+namespace Os {
+namespace Test {
+namespace Queue {
+FwSizeType Tester::QueueState::queues = 0;
+
+PriorityCompare const Tester::QueueMessageComparer::HELPER = PriorityCompare();
+
+Os::QueueInterface::Status Tester::shadow_create(FwSizeType depth, FwSizeType messageSize) {
+    Os::QueueInterface::Status status = Os::QueueInterface::ALREADY_CREATED;
+    if (not this->shadow.created) {
+        this->shadow.depth = depth;
+        this->shadow.messageSize = messageSize;
+        this->shadow.created = true;
+        status = Os::QueueInterface::OP_OK;
+        Tester::QueueState::queues++;
+    }
+    return status;
+}
+
+Os::QueueInterface::Status Tester::shadow_send(const U8* buffer,
+                                               FwSizeType size,
+                                               FwQueuePriorityType priority,
+                                               Os::QueueInterface::BlockingType blockType) {
+    this->shadow_check();
+    QueueMessage qm;
+    qm.priority = priority;
+    qm.size = size;
+    std::memcpy(qm.data, buffer, size);
+    if (size > this->shadow.messageSize) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    } else if ((this->shadow.queue.size() == this->shadow.depth) &&
+               (blockType == Os::QueueInterface::BlockingType::BLOCKING)) {
+        this->shadow.send_block = qm;
+        return QueueInterface::Status::OP_OK;
+    } else if (this->shadow.queue.size() == this->shadow.depth) {
+        return QueueInterface::Status::FULL;
+    } else {
+        this->shadow.queue.push(qm);
+        this->shadow.highMark = FW_MAX(this->shadow.highMark, this->shadow.queue.size());
+        return QueueInterface::Status::OP_OK;
+    }
+    return QueueInterface::Status::OP_OK;
+}
+
+void Tester::shadow_send_unblock() {
+    // Send the shadow send buffered message
+    this->shadow.queue.push(this->shadow.send_block);
+    this->shadow.highMark = FW_MAX(this->shadow.highMark, this->shadow.queue.size());
+}
+
+Os::QueueInterface::Status Tester::shadow_receive(U8* destination,
+                                                  FwSizeType capacity,
+                                                  QueueInterface::BlockingType blockType,
+                                                  FwSizeType& actualSize,
+                                                  FwQueuePriorityType& priority) {
+    this->shadow_check();
+    if (capacity < this->shadow.messageSize) {
+        return QueueInterface::Status::SIZE_MISMATCH;
+    } else if (this->shadow.queue.empty() && (blockType == QueueInterface::BlockingType::BLOCKING)) {
+        this->shadow.receive_block.destination = destination;
+        this->shadow.receive_block.size = &actualSize;
+        this->shadow.receive_block.priority = &priority;
+        return QueueInterface::Status::OP_OK;
+    } else if (this->shadow.queue.empty()) {
+        return QueueInterface::Status::EMPTY;
+    } else {
+        const QueueMessage& qm = shadow.queue.top();
+        std::memcpy(destination, qm.data, qm.size);
+        actualSize = qm.size;
+        priority = qm.priority;
+        shadow.queue.pop();
+    }
+    return QueueInterface::Status::OP_OK;
+}
+
+void Tester::shadow_receive_unblock() {
+    // Make sure outputs were stored in the shadow receive buffer
+    ASSERT_NE(this->shadow.receive_block.destination, nullptr);
+    ASSERT_NE(this->shadow.receive_block.size, nullptr);
+    ASSERT_NE(this->shadow.receive_block.priority, nullptr);
+
+    // Fill the outputs stored in the shadow receive buffer
+    const QueueMessage& qm = shadow.queue.top();
+    std::memcpy(this->shadow.receive_block.destination, qm.data, qm.size);
+    *this->shadow.receive_block.size = qm.size;
+    *this->shadow.receive_block.priority = qm.priority;
+    shadow.queue.pop();
+
+    // Clear the shadow receive buffer
+    this->shadow.receive_block.destination = nullptr;
+    this->shadow.receive_block.size = nullptr;
+    this->shadow.receive_block.priority = nullptr;
+}
+
+}  // namespace Queue
+}  // namespace Test
+}  // namespace Os
+
+TEST(InterfaceUninitialized, SendPointer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType messageSize = 200;
+    const FwQueuePriorityType priority = 300;
+    U8 buffer[messageSize];
+
+    Os::QueueInterface::Status status =
+        queue.send(buffer, sizeof buffer, priority, Os::QueueInterface::BlockingType::BLOCKING);
+    ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
+}
+
+TEST(InterfaceUninitialized, SendBuffer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType messageSize = 200;
+    const FwQueuePriorityType priority = 300;
+    U8 storage[messageSize];
+    Fw::ExternalSerializeBuffer buffer(storage, sizeof storage);
+
+    Os::QueueInterface::Status status = queue.send(buffer, priority, Os::QueueInterface::BlockingType::BLOCKING);
+    ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
+}
+
+TEST(InterfaceUninitialized, ReceivePointer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    FwSizeType size = 200;
+    FwQueuePriorityType priority;
+    U8 storage[size];
+
+    Os::QueueInterface::Status status =
+        queue.receive(storage, sizeof storage, Os::QueueInterface::BlockingType::NONBLOCKING, size, priority);
+    ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
+}
+
+TEST(InterfaceUninitialized, ReceiveBuffer) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    FwSizeType size = 200;
+    FwQueuePriorityType priority;
+    U8 storage[size];
+    Fw::ExternalSerializeBuffer buffer(storage, sizeof storage);
+
+    Os::QueueInterface::Status status = queue.receive(buffer, Os::QueueInterface::BlockingType::NONBLOCKING, priority);
+    ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
+}
+
+TEST(InterfaceInvalid, CreateInvalidDepth) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    ASSERT_DEATH_IF_SUPPORTED(queue.create(name, 0, 10), "Assert:.*Queue\\.cpp");
+}
+
+TEST(InterfaceInvalid, CreateInvalidSize) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    ASSERT_DEATH_IF_SUPPORTED(queue.create(name, 10, 0), "Assert:.*Queue\\.cpp");
+}
+
+TEST(InterfaceInvalid, SendPointerNull) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType messageSize = 200;
+    const FwQueuePriorityType priority = 300;
+    ASSERT_DEATH_IF_SUPPORTED(queue.send(nullptr, messageSize, priority, Os::QueueInterface::BlockingType::BLOCKING),
+                              "Assert:.*Queue\\.cpp");
+}
+
+TEST(InterfaceInvalid, SendInvalidEnum) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    const FwSizeType messageSize = 200;
+    const FwQueuePriorityType priority = 300;
+    Os::QueueInterface::BlockingType blockingType =
+        static_cast<Os::QueueInterface::BlockingType>(Os::QueueInterface::BlockingType::BLOCKING + 1);
+    ASSERT_DEATH_IF_SUPPORTED(queue.send(nullptr, messageSize, priority, blockingType), "Assert:.*Queue\\.cpp");
+}
+
+TEST(InterfaceInvalid, ReceivePointerNull) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    FwSizeType size = 200;
+    FwQueuePriorityType priority;
+    ASSERT_DEATH_IF_SUPPORTED(
+        queue.receive(nullptr, size, Os::QueueInterface::BlockingType::NONBLOCKING, size, priority),
+        "Assert:.*Queue\\.cpp");
+}
+
+TEST(InterfaceInvalid, ReceiveInvalidEnum) {
+    Os::Queue queue;
+    Fw::String name = "My queue";
+    FwSizeType size = 200;
+    FwQueuePriorityType priority;
+    Os::QueueInterface::BlockingType blockingType =
+        static_cast<Os::QueueInterface::BlockingType>(Os::QueueInterface::BlockingType::BLOCKING + 1);
+    ASSERT_DEATH_IF_SUPPORTED(queue.receive(nullptr, size, blockingType, size, priority), "Assert:.*Queue\\.cpp");
+}
+
+TEST(BasicRules, Create) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    // Nominal create
+    create_rule.action(tester);
+    // Repetitive create
+    create_rule.action(tester);
+}
+
+TEST(BasicRules, Send) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::SendNotFull send_rule;
+    create_rule.action(tester);
+    send_rule.action(tester);
+}
+
+TEST(BasicRules, Overflow) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::Overflow overflow_rule;
+    create_rule.action(tester);
+    overflow_rule.action(tester);
+}
+
+TEST(BasicRules, Recv) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::ReceiveEmptyNoBlock receive_rule;
+
+    create_rule.action(tester);
+    receive_rule.action(tester);
+}
+
+TEST(BasicRules, Underflow) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::Underflow underflow_rule;
+    create_rule.action(tester);
+    underflow_rule.action(tester);
+}
+
+TEST(BasicRules, SendRecv) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::SendNotFull send_rule;
+    Os::Test::Queue::Tester::ReceiveNotEmpty receive_rule;
+
+    create_rule.action(tester);
+    send_rule.action(tester);
+    receive_rule.action(tester);
+}
+
+TEST(BasicRules, OverflowUnderflow) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::Overflow overflow_rule;
+    Os::Test::Queue::Tester::SendFullNoBlock send_full_no_block;
+    Os::Test::Queue::Tester::Underflow underflow_rule;
+    Os::Test::Queue::Tester::ReceiveEmptyNoBlock receive_empty_no_block;
+    create_rule.action(tester);
+    overflow_rule.action(tester);
+    send_full_no_block.action(tester);
+    underflow_rule.action(tester);
+    receive_empty_no_block.apply(tester);
+}
+
+TEST(Blocking, SendBlock) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::Overflow overflow_rule;
+    AggregatedConcurrentRule<Os::Test::Queue::Tester> aggregator;
+    Os::Test::Queue::Tester::SendBlock block(aggregator);
+    Os::Test::Queue::Tester::ReceiveNotEmpty receive_not_empty(false);
+    ConcurrentWrapperRule<Os::Test::Queue::Tester> unblock(aggregator, receive_not_empty, "SendBlock", "SendUnblock");
+
+    create_rule.apply(tester);
+    overflow_rule.apply(tester);
+    aggregator.apply(tester);
+    aggregator.join();
+}
+
+TEST(Blocking, ReceiveBlock) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::Underflow overflow_rule;
+    AggregatedConcurrentRule<Os::Test::Queue::Tester> aggregator;
+    Os::Test::Queue::Tester::ReceiveBlock block(aggregator);
+    Os::Test::Queue::Tester::SendNotFull send_not_full(false);
+    ConcurrentWrapperRule<Os::Test::Queue::Tester> unblock(aggregator, send_not_full, "ReceiveBlock", "ReceiveUnblock");
+
+    create_rule.apply(tester);
+    overflow_rule.apply(tester);
+    aggregator.apply(tester);
+    aggregator.join();
+}
+
+TEST(Random, RandomNominal) {
+    Os::Test::Queue::Tester tester;
+    Os::Test::Queue::Tester::Create create_rule;
+    Os::Test::Queue::Tester::SendNotFull send_rule;
+    Os::Test::Queue::Tester::SendFullNoBlock send_full_no_block_rule;
+    Os::Test::Queue::Tester::ReceiveNotEmpty receive_rule;
+    Os::Test::Queue::Tester::ReceiveEmptyNoBlock receive_empty_no_block_rule;
+    Os::Test::Queue::Tester::Overflow overflow_rule;
+    Os::Test::Queue::Tester::Underflow underflow_rule;
+
+    // Place these rules into a list of rules
+    STest::Rule<Os::Test::Queue::Tester>* rules[] = {&create_rule,
+                                                     &send_rule,
+                                                     &receive_rule,
+                                                     &overflow_rule,
+                                                     &underflow_rule,
+                                                     &send_full_no_block_rule,
+                                                     &receive_empty_no_block_rule};
+
+    // Take the rules and place them into a random scenario
+    STest::RandomScenario<Os::Test::Queue::Tester> random("Random Rules", rules, FW_NUM_ARRAY_ELEMENTS(rules));
+
+    // Create a bounded scenario wrapping the random scenario
+    STest::BoundedScenario<Os::Test::Queue::Tester> bounded("Bounded Random Rules Scenario", random, RANDOM_BOUND);
+    // Run!
+    const U32 numSteps = bounded.run(tester);
+    printf("Ran %u steps.\n", numSteps);
+}
diff --git a/Os/test/ut/queue/CommonTests.hpp b/Os/test/ut/queue/CommonTests.hpp
new file mode 100644
index 0000000000..3eb63e326c
--- /dev/null
+++ b/Os/test/ut/queue/CommonTests.hpp
@@ -0,0 +1,8 @@
+// ======================================================================
+// \title Os/test/ut/queue/CommonTests.hpp
+// \brief required header
+// ======================================================================
+#include "RulesHeaders.hpp"
+#ifndef OS_TEST_UT_QUEUE_COMMON_TESTS_HPP
+#define OS_TEST_UT_QUEUE_COMMON_TESTS_HPP
+#endif  // OS_TEST_UT_QUEUE_COMMON_TESTS_HPP
diff --git a/Os/test/ut/queue/QueueRules.cpp b/Os/test/ut/queue/QueueRules.cpp
new file mode 100644
index 0000000000..c792051349
--- /dev/null
+++ b/Os/test/ut/queue/QueueRules.cpp
@@ -0,0 +1,340 @@
+// ======================================================================
+// \title Os/test/ut/queue/QueueRules.cpp
+// \brief queue rule implementations
+// ======================================================================
+
+#include "CommonTests.hpp"
+#include "Fw/Types/String.hpp"
+
+struct PickedMessage {
+    FwSizeType size;
+    FwQueuePriorityType priority;
+    U8* sent;
+    U8 received[QUEUE_MESSAGE_SIZE_UPPER_BOUND];
+};
+
+PickedMessage pick_message(FwSizeType max_size) {
+    PickedMessage message;
+
+    message.size = STest::Random::lowerUpper(1, max_size);
+    message.priority = STest::Random::lowerUpper(0, std::numeric_limits<U32>::max());
+
+    message.sent = new U8[message.size];
+    for (FwSizeType i = 0; i < message.size; i++) {
+        message.sent[i] = STest::Random::lowerUpper(0, std::numeric_limits<U8>::max());
+    }
+    return message;
+}
+
+void check_received(PickedMessage& message, PickedMessage& test) {
+    EXPECT_EQ(message.size, test.size);
+    EXPECT_EQ(message.priority, test.priority);
+    for (FwSizeType i = 0; i < message.size; i++) {
+        ASSERT_EQ(message.received[i], test.received[i]) << "at index " << i;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Create
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::Create::Create() : STest::Rule<Os::Test::Queue::Tester>("Create") {}
+
+bool Os::Test::Queue::Tester::Create::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return true;
+}
+
+void Os::Test::Queue::Tester::Create::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    const bool created = state.is_shadow_created();
+    Fw::String name("nAmE");
+    FwSizeType depth = STest::Random::lowerUpper(1, QUEUE_DEPTH_UPPER_BOUND);
+    FwSizeType messageSize = STest::Random::lowerUpper(1, QUEUE_MESSAGE_SIZE_UPPER_BOUND);
+    QueueInterface::Status status = state.shadow_create(depth, messageSize);
+    QueueInterface::Status test_status = state.queue.create(name, depth, messageSize);
+    ASSERT_EQ(status, created ? QueueInterface::Status::ALREADY_CREATED : QueueInterface::Status::OP_OK);
+    ASSERT_EQ(status, test_status);
+    ASSERT_EQ(name, state.queue.getName());
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  SendNotFull
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::SendNotFull::SendNotFull(bool end_check) : STest::Rule<Os::Test::Queue::Tester>("SendNotFull"),
+    m_end_check(end_check)
+{}
+
+bool Os::Test::Queue::Tester::SendNotFull::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.shadow.created and not state.is_shadow_full();
+}
+
+void Os::Test::Queue::Tester::SendNotFull::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    QueueInterface::BlockingType blocking =
+        (STest::Random::lowerUpper(0, 1) == 1) ? QueueInterface::BLOCKING : QueueInterface::NONBLOCKING;
+    PickedMessage pick = pick_message(state.shadow.messageSize);
+    // Prevent lock-up
+    ASSERT_LT(state.queue.getMessagesAvailable(), state.queue.getDepth());
+    ASSERT_FALSE(state.is_shadow_full());
+    QueueInterface::Status status = state.shadow_send(pick.sent, pick.size, pick.priority, blocking);
+    QueueInterface::Status test_status = state.queue.send(pick.sent, pick.size, pick.priority, blocking);
+    delete[] pick.sent;  // Clean-up
+    ASSERT_EQ(status, QueueInterface::Status::OP_OK);
+    ASSERT_EQ(test_status, status);
+    if (this->m_end_check) {
+        state.shadow_check();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  SendFullNoBlock
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::SendFullNoBlock::SendFullNoBlock() : STest::Rule<Os::Test::Queue::Tester>("SendFullNoBlock") {}
+
+bool Os::Test::Queue::Tester::SendFullNoBlock::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.shadow.created and state.is_shadow_full();
+}
+
+void Os::Test::Queue::Tester::SendFullNoBlock::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    PickedMessage pick = pick_message(state.shadow.messageSize);
+    QueueInterface::Status status = state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::NONBLOCKING);
+    QueueInterface::Status test_status =
+        state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::NONBLOCKING);
+    delete[] pick.sent;
+
+    ASSERT_EQ(status, QueueInterface::Status::FULL);
+    ASSERT_EQ(test_status, status);
+    state.shadow_check();
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  ReceiveNotEmpty
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::ReceiveNotEmpty::ReceiveNotEmpty(bool end_check) : STest::Rule<Os::Test::Queue::Tester>("ReceiveNotEmpty"),
+      m_end_check(end_check) {}
+
+bool Os::Test::Queue::Tester::ReceiveNotEmpty::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.shadow.created and not state.is_shadow_empty();
+}
+
+void Os::Test::Queue::Tester::ReceiveNotEmpty::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    QueueInterface::BlockingType blocking =
+        (STest::Random::lowerUpper(0, 1) == 1) ? QueueInterface::BLOCKING : QueueInterface::NONBLOCKING;
+    PickedMessage message;
+    PickedMessage test;
+
+    // Prevent lock-up
+    ASSERT_GT(state.queue.getMessagesAvailable(), 0);
+    ASSERT_FALSE(state.is_shadow_empty());
+    QueueInterface::Status status = state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, blocking,
+                                                         message.size, message.priority);
+
+    QueueInterface::Status test_status =
+        state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, blocking, test.size, test.priority);
+    ASSERT_EQ(status, QueueInterface::Status::OP_OK);
+    ASSERT_EQ(status, test_status);
+    check_received(message, test);
+    if (this->m_end_check) {
+        state.shadow_check();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  ReceiveEmptyNoBlock
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::ReceiveEmptyNoBlock::ReceiveEmptyNoBlock()
+    : STest::Rule<Os::Test::Queue::Tester>("ReceiveEmptyNoBlock") {}
+
+bool Os::Test::Queue::Tester::ReceiveEmptyNoBlock::precondition(
+    const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.shadow.created and state.is_shadow_empty();
+}
+
+void Os::Test::Queue::Tester::ReceiveEmptyNoBlock::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    PickedMessage message;
+    PickedMessage test;
+
+    QueueInterface::Status status =
+        state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND,
+                             QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority);
+
+    QueueInterface::Status test_status =
+        state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::NONBLOCKING,
+                            test.size, test.priority);
+    ASSERT_EQ(status, QueueInterface::Status::EMPTY);
+    ASSERT_EQ(status, test_status);
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Overflow
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::Overflow::Overflow() : STest::Rule<Os::Test::Queue::Tester>("Overflow") {}
+
+bool Os::Test::Queue::Tester::Overflow::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.is_shadow_created();
+}
+
+void Os::Test::Queue::Tester::Overflow::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    while (not state.is_shadow_full()) {
+        PickedMessage pick = pick_message(state.shadow.messageSize);
+        QueueInterface::Status status =
+            state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING);
+        QueueInterface::Status test_status =
+            state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING);
+        delete[] pick.sent;
+        ASSERT_EQ(status, QueueInterface::Status::OP_OK);
+        ASSERT_EQ(status, test_status);
+    }
+    PickedMessage pick = pick_message(state.shadow.messageSize);
+    QueueInterface::Status status =
+        state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING);
+    QueueInterface::Status test_status =
+        state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING);
+    delete[] pick.sent;
+    ASSERT_EQ(status, QueueInterface::Status::FULL);
+    ASSERT_EQ(status, test_status);
+    state.shadow_check();
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Underflow
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::Underflow::Underflow() : STest::Rule<Os::Test::Queue::Tester>("Underflow") {}
+
+bool Os::Test::Queue::Tester::Underflow::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.is_shadow_created();
+}
+
+void Os::Test::Queue::Tester::Underflow::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    PickedMessage message;
+    PickedMessage test;
+    while (not state.is_shadow_empty()) {
+        QueueInterface::Status status =
+            state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND,
+                                 QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority);
+
+        QueueInterface::Status test_status =
+            state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND,
+                                QueueInterface::BlockingType::NONBLOCKING, test.size, test.priority);
+        ASSERT_EQ(status, QueueInterface::Status::OP_OK);
+        ASSERT_EQ(status, test_status);
+        check_received(message, test);
+    }
+    QueueInterface::Status status =
+        state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND,
+                             QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority);
+
+    QueueInterface::Status test_status =
+        state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::NONBLOCKING,
+                            test.size, test.priority);
+    ASSERT_EQ(status, QueueInterface::Status::EMPTY);
+    ASSERT_EQ(status, test_status);
+    state.shadow_check();
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  SendBlock
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::SendBlock::SendBlock(AggregatedConcurrentRule<Os::Test::Queue::Tester>& runner)
+    : ConcurrentRule<Os::Test::Queue::Tester>("SendBlock", runner) {}
+
+bool Os::Test::Queue::Tester::SendBlock::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.shadow.created && state.is_shadow_full();
+}
+
+void Os::Test::Queue::Tester::SendBlock::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    // Backend defined check
+    if (not TESTS_SUPPORT_BLOCKING) {
+        this->notify_other("SendUnblock");
+        return;
+    }
+    PickedMessage pick = pick_message(state.shadow.messageSize);
+    this->notify_other("SendUnblock");
+    QueueInterface::Status status =
+        state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::BLOCKING);
+    getLock().unlock();
+    QueueInterface::Status test_status =
+        state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::BLOCKING);
+    getLock().lock();
+    // Condition should be set after block
+    ASSERT_TRUE(this->getCondition());
+    // Unblock the shadow queue send
+    state.shadow_send_unblock();
+    delete[] pick.sent;
+
+    ASSERT_EQ(status, QueueInterface::Status::OP_OK);
+    ASSERT_EQ(test_status, status);
+    state.shadow_check();
+}
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  ReceiveBlock
+//
+// ------------------------------------------------------------------------------------------------------
+
+Os::Test::Queue::Tester::ReceiveBlock::ReceiveBlock(AggregatedConcurrentRule<Os::Test::Queue::Tester>& runner)
+    : ConcurrentRule<Os::Test::Queue::Tester>("ReceiveBlock", runner) {}
+
+bool Os::Test::Queue::Tester::ReceiveBlock::precondition(const Os::Test::Queue::Tester& state  //!< The test state
+) {
+    return state.shadow.created && state.is_shadow_empty();
+}
+
+void Os::Test::Queue::Tester::ReceiveBlock::action(Os::Test::Queue::Tester& state  //!< The test state
+) {
+    // Backend defined check
+    if (not TESTS_SUPPORT_BLOCKING) {
+        this->notify_other("ReceiveUnblock");
+        return;
+    }
+
+    PickedMessage message;
+    PickedMessage test;
+    this->notify_other("ReceiveUnblock");
+
+    QueueInterface::Status status =
+        state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::BLOCKING,
+                             message.size, message.priority);
+    this->getLock().unlock();
+    QueueInterface::Status test_status =
+        state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::BLOCKING,
+                            test.size, test.priority);
+    this->getLock().lock();
+    // Condition should be set after block
+    ASSERT_TRUE(this->getCondition());
+    // Unblock the shadow queue send
+    state.shadow_receive_unblock();
+
+    ASSERT_EQ(status, QueueInterface::Status::OP_OK);
+    ASSERT_EQ(status, test_status);
+    check_received(message, test);
+}
diff --git a/Os/test/ut/queue/QueueRules.hpp b/Os/test/ut/queue/QueueRules.hpp
new file mode 100644
index 0000000000..d613e2757e
--- /dev/null
+++ b/Os/test/ut/queue/QueueRules.hpp
@@ -0,0 +1,231 @@
+// ======================================================================
+// \title Os/test/ut/queue/QueueRules.hpp
+// \brief queue rule definitions
+// ======================================================================
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Create
+//
+// ------------------------------------------------------------------------------------------------------
+struct Create : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    Create();
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  SendNotFull
+//
+// ------------------------------------------------------------------------------------------------------
+struct SendNotFull : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit SendNotFull(bool end_check=true);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+    bool m_end_check;
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  SendFullNoBlock
+//
+// ------------------------------------------------------------------------------------------------------
+struct SendFullNoBlock : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    SendFullNoBlock();
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  ReceiveNotEmpty
+//
+// ------------------------------------------------------------------------------------------------------
+struct ReceiveNotEmpty : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit ReceiveNotEmpty(bool end_check=true);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+    bool m_end_check;
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  ReceiveEmptyNoBlock
+//
+// ------------------------------------------------------------------------------------------------------
+struct ReceiveEmptyNoBlock : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    ReceiveEmptyNoBlock();
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Overflow
+//
+// ------------------------------------------------------------------------------------------------------
+struct Overflow : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    Overflow();
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  Underflow
+//
+// ------------------------------------------------------------------------------------------------------
+struct Underflow : public STest::Rule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    Underflow();
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+    );
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+    );
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  SendBlock
+//
+// ------------------------------------------------------------------------------------------------------
+struct SendBlock : public ConcurrentRule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit SendBlock(AggregatedConcurrentRule<Os::Test::Queue::Tester>& runner);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+                      ) override;
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+                ) override;
+};
+
+// ------------------------------------------------------------------------------------------------------
+// Rule:  ReceiveBlock
+//
+// ------------------------------------------------------------------------------------------------------
+struct ReceiveBlock : public ConcurrentRule<Os::Test::Queue::Tester> {
+    // ----------------------------------------------------------------------
+    // Construction
+    // ----------------------------------------------------------------------
+
+    //! Constructor
+    explicit ReceiveBlock(AggregatedConcurrentRule<Os::Test::Queue::Tester>& runner);
+
+    // ----------------------------------------------------------------------
+    // Public member functions
+    // ----------------------------------------------------------------------
+
+    //! Precondition
+    bool precondition(const Os::Test::Queue::Tester& state  //!< The test state
+                      ) override;
+
+    //! Action
+    void action(Os::Test::Queue::Tester& state  //!< The test state
+                ) override;
+};
diff --git a/Os/test/ut/queue/RulesHeaders.hpp b/Os/test/ut/queue/RulesHeaders.hpp
new file mode 100644
index 0000000000..043250c29d
--- /dev/null
+++ b/Os/test/ut/queue/RulesHeaders.hpp
@@ -0,0 +1,119 @@
+// ======================================================================
+// \title Os/test/ut/queue/RulesHeaders.cpp
+// \brief queue test rules headers
+// ======================================================================
+
+#ifndef OS_TEST_QUEUE_RULES_HEADERS__
+#define OS_TEST_QUEUE_RULES_HEADERS__
+
+#include <queue>
+#include <vector>
+#include "Os/Queue.hpp"
+#include "Os/test/ConcurrentRule.hpp"
+#include "STest/Rule/Rule.hpp"
+#include "STest/Scenario/BoundedScenario.hpp"
+#include "STest/Scenario/RandomScenario.hpp"
+#include "STest/Scenario/Scenario.hpp"
+
+#include "QueueRulesDefinitions.hpp"
+
+namespace Os {
+namespace Test {
+namespace Queue {
+
+constexpr FwSizeType DEPTH_BOUND = 100000;
+
+struct Tester {
+  public:
+    //! Constructor
+    Tester() = default;
+    virtual ~Tester() = default;
+
+    struct QueueMessage {
+        U8 data[QUEUE_MESSAGE_SIZE_UPPER_BOUND];
+        FwQueuePriorityType priority = 0;
+        FwSizeType size = 0;
+    };
+
+    struct ReceiveMessage {
+        U8* destination = nullptr;
+        FwQueuePriorityType* priority = nullptr;
+        FwSizeType* size = nullptr;
+    };
+
+    struct QueueMessageComparer {
+        bool operator()(const QueueMessage& a, const QueueMessage& b) { return HELPER(a.priority, b.priority); }
+
+      private:
+        static const PriorityCompare HELPER;
+    };
+
+    struct QueueState {
+        FwSizeType depth = 0;
+        FwSizeType messageSize = 0;
+        FwSizeType highMark = 0;
+        static FwSizeType queues;
+        QueueMessage send_block;
+        ReceiveMessage receive_block;
+
+        bool created = false;
+        std::priority_queue<QueueMessage, std::vector<QueueMessage>, QueueMessageComparer> queue;
+    };
+    QueueState shadow;
+    Os::Queue queue;
+
+    //! Shadow is created
+    bool is_shadow_created() const {
+        this->shadow_check();
+        return this->shadow.created;
+    }
+
+    //! Shadow queue is full
+    bool is_shadow_full() const {
+        this->shadow_check();
+        return this->shadow.queue.size() == this->shadow.depth;
+    }
+
+    //! Shadow is empty
+    bool is_shadow_empty() const {
+        this->shadow_check();
+        return this->shadow.queue.empty();
+    }
+
+    void shadow_check() const {
+        EXPECT_LE(this->shadow.queue.size(), this->shadow.depth) << "Shadow queue inconsistent.";
+        EXPECT_EQ(this->shadow.depth, this->queue.getDepth());
+        EXPECT_EQ(this->shadow.messageSize, this->queue.getMessageSize());
+        EXPECT_EQ(this->shadow.queue.size(), this->queue.getMessagesAvailable());
+        EXPECT_EQ(this->shadow.highMark, this->queue.getMessageHighWaterMark());
+    }
+
+    Os::QueueInterface::Status shadow_create(FwSizeType depth, FwSizeType messageSize);
+
+    //! Must be called before the queue send
+    Os::QueueInterface::Status shadow_send(const U8* buffer,
+                                           FwSizeType size,
+                                           FwQueuePriorityType priority,
+                                           Os::QueueInterface::BlockingType blockType);
+
+    //! Complete a previous blocking queue send
+    void shadow_send_unblock();
+
+    //! Must be called before the queue receive
+    Os::QueueInterface::Status shadow_receive(U8* destination,
+                                              FwSizeType capacity,
+                                              QueueInterface::BlockingType blockType,
+                                              FwSizeType& actualSize,
+                                              FwQueuePriorityType& priority);
+    //! Complete a previous blocking queue receive
+    void shadow_receive_unblock();
+
+  public:
+#include "QueueRules.hpp"
+};
+
+}  // namespace Queue
+}  // namespace Test
+}  // namespace Os
+
+#endif
diff --git a/Os/test/ut/task/TaskRules.cpp b/Os/test/ut/task/TaskRules.cpp
index bca1289696..4fef313bc3 100644
--- a/Os/test/ut/task/TaskRules.cpp
+++ b/Os/test/ut/task/TaskRules.cpp
@@ -43,6 +43,7 @@ void Os::Test::Task::Tester::Start::action(
         Os::Test::Task::Tester &state //!< The test state
 ) {
     std::shared_ptr<TestTaskInfo> new_task = std::make_shared<TestTaskInfo>();
+    new_task->m_state = Os::Task::State::STARTING;
     state.m_tasks.push_back(new_task);
 
 
diff --git a/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp b/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp
index 800ed84be7..f1c6cf216e 100644
--- a/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp
+++ b/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp
@@ -200,7 +200,7 @@ namespace Svc {
   void BufferLoggerTester ::
     dispatchAll()
   {
-    while(this->component.m_queue.getNumMsgs() > 0)
+    while(this->component.m_queue.getMessagesAvailable() > 0)
       this->dispatchOne();
   }
 
diff --git a/Svc/ComLogger/test/ut/ComLoggerTester.cpp b/Svc/ComLogger/test/ut/ComLoggerTester.cpp
index 6618b16624..803819ab4b 100644
--- a/Svc/ComLogger/test/ut/ComLoggerTester.cpp
+++ b/Svc/ComLogger/test/ut/ComLoggerTester.cpp
@@ -72,7 +72,7 @@ namespace Svc {
   void ComLoggerTester ::
     dispatchAll()
   {
-    while(this->comLogger.m_queue.getNumMsgs() > 0)
+    while(this->comLogger.m_queue.getMessagesAvailable() > 0)
       this->dispatchOne();
   }
 
diff --git a/Svc/ComQueue/test/ut/ComQueueTester.cpp b/Svc/ComQueue/test/ut/ComQueueTester.cpp
index 02ba7cab98..3abb7212cc 100644
--- a/Svc/ComQueue/test/ut/ComQueueTester.cpp
+++ b/Svc/ComQueue/test/ut/ComQueueTester.cpp
@@ -27,7 +27,7 @@ ComQueueTester ::ComQueueTester() : ComQueueGTestBase("Tester", MAX_HISTORY_SIZE
 ComQueueTester ::~ComQueueTester() {}
 
 void ComQueueTester ::dispatchAll() {
-    while (this->component.m_queue.getNumMsgs() > 0) {
+    while (this->component.m_queue.getMessagesAvailable() > 0) {
         this->component.doDispatch();
     }
 }
@@ -264,12 +264,12 @@ void ComQueueTester::testInternalQueueOverflow() {
     Fw::Buffer buffer(data, sizeof(data));
 
     const NATIVE_INT_TYPE queueNum = ComQueue::COM_PORT_COUNT;
-    const NATIVE_INT_TYPE msgCountMax = this->component.m_queue.getQueueSize();
+    const FwSizeType msgCountMax = this->component.m_queue.getDepth();
     QueueType overflow_type;
     NATIVE_INT_TYPE portNum;
 
     // fill the queue
-    for (NATIVE_INT_TYPE msgCount = 0; msgCount < msgCountMax; msgCount++) {
+    for (FwSizeType msgCount = 0; msgCount < msgCountMax; msgCount++) {
         sendByQueueNumber(buffer, queueNum, portNum, overflow_type);
         ASSERT_EQ(overflow_type, QueueType::BUFFER_QUEUE);
     }
diff --git a/cmake/test/data/TestDeployment/Main.cpp b/cmake/test/data/TestDeployment/Main.cpp
index b3a97bff5e..6921ea003a 100644
--- a/cmake/test/data/TestDeployment/Main.cpp
+++ b/cmake/test/data/TestDeployment/Main.cpp
@@ -1,4 +1,4 @@
 // No operation executable
 int main(int argc, char** argv) {
     return 0;
-}
\ No newline at end of file
+}
diff --git a/cmake/test/data/test-implementations/Deployment/Main.cpp b/cmake/test/data/test-implementations/Deployment/Main.cpp
index b3a97bff5e..6921ea003a 100644
--- a/cmake/test/data/test-implementations/Deployment/Main.cpp
+++ b/cmake/test/data/test-implementations/Deployment/Main.cpp
@@ -1,4 +1,4 @@
 // No operation executable
 int main(int argc, char** argv) {
     return 0;
-}
\ No newline at end of file
+}