AbstractCodec use fair_queue

This commit is contained in:
Michael Davidsaver
2015-10-09 17:14:17 -04:00
parent db86e47659
commit 730d30fe54
4 changed files with 120 additions and 190 deletions

View File

@@ -22,6 +22,33 @@ namespace epics {
namespace pvAccess {
struct sender_break : public connection_closed_exception
{
sender_break() : connection_closed_exception("break") {}
};
struct TransportSenderDisconnect: public TransportSender {
void unlock() {}
void lock() {}
void send(ByteBuffer *buffer, TransportSendControl *control)
{
control->flush(true);
throw sender_break();
}
};
struct TransportSenderSignal: public TransportSender {
Event *evt;
TransportSenderSignal(Event& evt) :evt(&evt) {}
void unlock() {}
void lock() {}
void send(ByteBuffer *buffer, TransportSendControl *control)
{
evt->signal();
}
};
class PVAMessage {
public:
@@ -257,13 +284,6 @@ namespace epics {
}
void endBlockedProcessSendQueue() {
//TODO not thread safe
_blockingProcessQueue = false;
_sendQueue.wakeup();
}
void close() { _closedCount++; }
bool isOpen() { return _closedCount == 0; }
@@ -288,6 +308,10 @@ namespace epics {
void sendCompleted() { _sendCompletedCount++; }
void breakSender() {
enqueueSendRequest(std::tr1::shared_ptr<TransportSender>(new TransportSenderDisconnect()));
}
bool terminated() { return false; }
void cachedSerialize(
@@ -412,7 +436,7 @@ namespace epics {
public:
int runAllTest() {
testPlan(5882);
testPlan(5885);
testHeaderProcess();
testInvalidHeaderMagic();
testInvalidHeaderSegmentedInNormal();
@@ -2223,7 +2247,6 @@ namespace epics {
"%s: codec._closedCount == 1", CURRENT_FUNCTION);
}
class TransportSenderForTestEnqueueSendRequest:
public TransportSender {
public:
@@ -2290,7 +2313,10 @@ namespace epics {
// process
codec.enqueueSendRequest(sender);
codec.enqueueSendRequest(sender2);
codec.processSendQueue();
codec.breakSender();
try{
codec.processSendQueue();
}catch(sender_break&) {}
codec.transferToReadBuffer();
@@ -2430,11 +2456,16 @@ namespace epics {
//was processed
testOk(0 == codec._sendCompletedCount,
"%s: 0 == codec._sendCompletedCount", CURRENT_FUNCTION);
testOk1(!codec.sendQueueEmpty());
codec.processSendQueue();
codec.breakSender();
try{
codec.processSendQueue();
}catch(sender_break&) {}
testOk(1 == codec._sendCompletedCount,
"%s: 1 == codec._sendCompletedCount", CURRENT_FUNCTION);
testOk1(codec.sendQueueEmpty());
codec.transferToReadBuffer();
@@ -2483,6 +2514,13 @@ namespace epics {
"%s: 0 == codec.getSendBuffer()->getPosition()",
CURRENT_FUNCTION);
testOk1(codec.sendQueueEmpty());
testDiag("%u %u", (unsigned)codec._scheduleSendCount,
(unsigned)codec._sendCompletedCount);
testOk1(3 == codec._scheduleSendCount);
testOk1(1 == codec._sendCompletedCount);
// now queue is empty and thread is right
codec.enqueueSendRequest(sender2, PVA_MESSAGE_HEADER_SIZE);
@@ -2491,12 +2529,17 @@ namespace epics {
"%s: PVA_MESSAGE_HEADER_SIZE == "
"codec.getSendBuffer()->getPosition()",
CURRENT_FUNCTION);
testOk(3 == codec._scheduleSendCount,
"%s: 3 == codec._scheduleSendCount", CURRENT_FUNCTION);
testOk(1 == codec._sendCompletedCount,
"%s: 1 == codec._sendCompletedCount", CURRENT_FUNCTION);
codec.processWrite();
testDiag("%u %u", (unsigned)codec._scheduleSendCount,
(unsigned)codec._sendCompletedCount);
testOk1(4 == codec._scheduleSendCount);
testOk1(1 == codec._sendCompletedCount);
codec.breakSender();
try{
codec.processWrite();
}catch(sender_break&) {}
testOk(2 == codec._sendCompletedCount,
"%s: 2 == codec._sendCompletedCount", CURRENT_FUNCTION);
@@ -2575,7 +2618,10 @@ namespace epics {
// process
codec.enqueueSendRequest(sender);
codec.processSendQueue();
codec.breakSender();
try{
codec.processSendQueue();
}catch(sender_break&) {}
codec.transferToReadBuffer();
@@ -2664,7 +2710,7 @@ namespace epics {
// process
codec.enqueueSendRequest(sender);
codec.breakSender();
try
{
codec.processSendQueue();
@@ -2781,7 +2827,10 @@ namespace epics {
// process
codec.enqueueSendRequest(sender);
codec.processSendQueue();
codec.breakSender();
try{
codec.processSendQueue();
}catch(sender_break&) {}
codec.addToReadBuffer();
@@ -2906,7 +2955,10 @@ namespace epics {
codec.clearSendQueue();
codec.processSendQueue();
codec.breakSender();
try{
codec.processSendQueue();
}catch(sender_break&) {}
testOk(0 == codec.getSendBuffer()->getPosition(),
"%s: 0 == codec.getSendBuffer()->getPosition()",
@@ -3128,6 +3180,7 @@ namespace epics {
TransportSendControl* control)
{
_codec.putControlMessage((int8_t)0x01, 0x00112233);
_codec.flush(true);
}
private:
@@ -3135,16 +3188,20 @@ namespace epics {
};
class ValueHolder {
class ValueHolder : public Runnable {
public:
ValueHolder(
TestCodec &testCodec,
AtomicValue<bool> &processTreadExited):
_testCodec(testCodec),
_processTreadExited(processTreadExited) {}
ValueHolder(TestCodec &testCodec):
_testCodec(testCodec) {}
TestCodec &_testCodec;
AtomicValue<bool> & _processTreadExited;
Event waiter;
virtual void run() {
waiter.signal();
try{
_testCodec.processSendQueue();
}catch(sender_break&) {}
}
};
@@ -3155,56 +3212,40 @@ namespace epics {
TestCodec codec(DEFAULT_BUFFER_SIZE,
DEFAULT_BUFFER_SIZE, true);
_processTreadExited.getAndSet(false);
std::tr1::shared_ptr<TransportSender> sender =
std::tr1::shared_ptr<TransportSender>(
new TransportSenderForTestBlockingProcessQueueTest(codec));
ValueHolder valueHolder(codec, _processTreadExited);
ValueHolder valueHolder(codec);
Event done;
epicsThreadCreate(
"testBlockingProcessQueueTest-processThread",
epicsThreadPriorityMedium,
epicsThreadGetStackSize(
epicsThreadStackMedium),
CodecTest::blockingProcessQueueThread,
&valueHolder);
Thread thr(Thread::Config(&valueHolder)
.name("testBlockingProcessQueueTest-processThread"));
epicsThreadSleep(3);
testOk(_processTreadExited.get() == false,
"%s: _processTreadExited.get() == false",
CURRENT_FUNCTION);
valueHolder.waiter.wait();
// let's put something into it
codec.enqueueSendRequest(sender);
codec.enqueueSendRequest(std::tr1::shared_ptr<TransportSender>(new TransportSenderSignal(done)));
epicsThreadSleep(1);
testDiag("Waiting for work");
done.wait();
testOk((std::size_t)PVA_MESSAGE_HEADER_SIZE ==
codec._writeBuffer.getPosition(),
"%s: PVA_MESSAGE_HEADER_SIZE == "
"codec._writeBuffer.getPosition()",
CURRENT_FUNCTION);
"codec._writeBuffer.getPosition() (%u)",
CURRENT_FUNCTION,
(unsigned)codec._writeBuffer.getPosition());
codec.endBlockedProcessSendQueue();
codec.breakSender();
epicsThreadSleep(1);
testOk(_processTreadExited.get() == true,
"%s: _processTreadExited.get() == true", CURRENT_FUNCTION);
thr.exitWait();
}
private:
void static blockingProcessQueueThread(void *param) {
ValueHolder *valueHolder = static_cast<ValueHolder *>(param);
// this should block
valueHolder->_testCodec.processSendQueue();
valueHolder->_processTreadExited.getAndSet(true);
}
AtomicValue<bool> _processTreadExited;
};
}