1 #pragma once 2 3 #include <QScopedPointer> 4 #include <QSharedPointer> 5 6 #include "rigtorp/SPSCQueue.h" 7 8 #include "util/class.h" 9 #include "util/reference.h" 10 11 // MessagePipe represents one side of a TwoWayMessagePipe. The direction of the 12 // pipe is with respect to the owner so sender and receiver are 13 // perspective-dependent. 14 template <class SenderMessageType, class ReceiverMessageType> 15 class MessagePipe { 16 public: MessagePipe(rigtorp::SPSCQueue<SenderMessageType> & receiver_messages,rigtorp::SPSCQueue<ReceiverMessageType> & sender_messages,BaseReferenceHolder * pTwoWayMessagePipeReference)17 MessagePipe(rigtorp::SPSCQueue<SenderMessageType>& receiver_messages, 18 rigtorp::SPSCQueue<ReceiverMessageType>& sender_messages, 19 BaseReferenceHolder* pTwoWayMessagePipeReference) 20 : m_receiver_messages(receiver_messages), 21 m_sender_messages(sender_messages), 22 m_pTwoWayMessagePipeReference(pTwoWayMessagePipeReference) { 23 } 24 25 // Returns the number of ReceiverMessageType messages waiting to be read by 26 // the receiver. Non-blocking. messageCount()27 int messageCount() const { 28 return m_sender_messages.size(); 29 } 30 31 // Try to read read a ReceiverMessageType written by the receiver 32 // addressed to the sender. Non-blocking. readMessage(ReceiverMessageType * message)33 bool readMessage(ReceiverMessageType* message) { 34 auto front = m_sender_messages.front(); 35 if (!front) { 36 return false; 37 } 38 *message = std::move(*front); 39 m_sender_messages.pop(); 40 return true; 41 } 42 43 // Writes a message to the receiver and returns true on success. writeMessage(const SenderMessageType & message)44 bool writeMessage(const SenderMessageType& message) { 45 return m_receiver_messages.try_push(message); 46 } 47 48 private: 49 rigtorp::SPSCQueue<SenderMessageType>& m_receiver_messages; 50 rigtorp::SPSCQueue<ReceiverMessageType>& m_sender_messages; 51 QScopedPointer<BaseReferenceHolder> m_pTwoWayMessagePipeReference; 52 53 #define COMMA , 54 DISALLOW_COPY_AND_ASSIGN(MessagePipe<SenderMessageType COMMA ReceiverMessageType>); 55 #undef COMMA 56 }; 57 58 // TwoWayMessagePipe is a bare-bones wrapper around the above rigtorp::SPSCQueue class that 59 // facilitates non-blocking two-way communication. To keep terminology clear, 60 // there are two sides to the message pipe, the sender side and the receiver 61 // side. The non-blocking aspect of the underlying rigtorp::SPSCQueue class requires that the 62 // sender methods and target methods each only be called from a single thread 63 // The most common use-case of this class is sending and receiving messages 64 // with the callback thread without the callback thread blocking. 65 // 66 // This class is an implementation detail and cannot be instantiated 67 // directly. Use makeTwoWayMessagePipe(...) to create a two-way pipe. 68 template <class SenderMessageType, class ReceiverMessageType> 69 class TwoWayMessagePipe { 70 public: 71 // Creates a TwoWayMessagePipe with SenderMessageType and 72 // ReceiverMessageType as the message types. Returns a pair of MessagePipes, 73 // the first is the sender's pipe (sends SenderMessageType and receives 74 // ReceiverMessageType messages) and the second is the receiver's pipe 75 // (sends ReceiverMessageType and receives SenderMessageType messages). 76 static QPair<MessagePipe<SenderMessageType, ReceiverMessageType>*, makeTwoWayMessagePipe(int sender_fifo_size,int receiver_fifo_size)77 MessagePipe<ReceiverMessageType, SenderMessageType>*> makeTwoWayMessagePipe( 78 int sender_fifo_size, 79 int receiver_fifo_size) { 80 QSharedPointer<TwoWayMessagePipe<SenderMessageType, ReceiverMessageType> > pipe( 81 new TwoWayMessagePipe<SenderMessageType, ReceiverMessageType>( 82 sender_fifo_size, receiver_fifo_size)); 83 84 return QPair<MessagePipe<SenderMessageType, ReceiverMessageType>*, 85 MessagePipe<ReceiverMessageType, SenderMessageType>*>( 86 new MessagePipe<SenderMessageType, ReceiverMessageType>( 87 pipe->m_receiver_messages, pipe->m_sender_messages, 88 new ReferenceHolder<TwoWayMessagePipe<SenderMessageType, ReceiverMessageType> >(pipe)), 89 new MessagePipe<ReceiverMessageType, SenderMessageType>( 90 pipe->m_sender_messages, pipe->m_receiver_messages, 91 new ReferenceHolder<TwoWayMessagePipe<SenderMessageType, ReceiverMessageType> >(pipe))); 92 } 93 94 private: TwoWayMessagePipe(int sender_fifo_size,int receiver_fifo_size)95 TwoWayMessagePipe(int sender_fifo_size, int receiver_fifo_size) 96 : m_receiver_messages(receiver_fifo_size), 97 m_sender_messages(sender_fifo_size) { 98 } 99 100 // Messages waiting to be delivered to the receiver. 101 rigtorp::SPSCQueue<SenderMessageType> m_receiver_messages; 102 // Messages waiting to be delivered to the sender. 103 rigtorp::SPSCQueue<ReceiverMessageType> m_sender_messages; 104 105 // This #define is because the macro gets confused by the template 106 // parameters. 107 #define COMMA , 108 DISALLOW_COPY_AND_ASSIGN(TwoWayMessagePipe<SenderMessageType COMMA ReceiverMessageType>); 109 #undef COMMA 110 }; 111