Fix deadlock with Driver::write

Use a spin lock to recheck the queue size until it has room to push.
pull/25/head
Kyle Schwarz 2020-08-14 16:57:52 -04:00
parent afda617894
commit 4cd897badd
6 changed files with 2 additions and 13 deletions

View File

@ -45,9 +45,9 @@ bool Driver::write(const std::vector<uint8_t>& bytes) {
} }
if(writeBlocks) { if(writeBlocks) {
std::unique_lock<std::mutex> lk(writeMutex);
if(writeQueue.size_approx() > writeQueueSize) if(writeQueue.size_approx() > writeQueueSize)
writeCV.wait(lk); while(writeQueue.size_approx() > (writeQueueSize * 3 / 4))
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} else { } else {
if(writeQueue.size_approx() > writeQueueSize) { if(writeQueue.size_approx() > writeQueueSize) {
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error); report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);

View File

@ -22,10 +22,6 @@ public:
virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0); virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
virtual bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0); virtual bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0);
virtual bool write(const std::vector<uint8_t>& bytes); virtual bool write(const std::vector<uint8_t>& bytes);
inline void onWrite() {
if(writeQueue.size_approx() < (writeQueueSize * 3/4))
writeCV.notify_one();
}
device_eventhandler_t report; device_eventhandler_t report;
@ -47,8 +43,6 @@ protected:
virtual void writeTask() = 0; virtual void writeTask() = 0;
moodycamel::BlockingConcurrentQueue<uint8_t> readQueue; moodycamel::BlockingConcurrentQueue<uint8_t> readQueue;
moodycamel::BlockingConcurrentQueue<WriteOperation> writeQueue; moodycamel::BlockingConcurrentQueue<WriteOperation> writeQueue;
std::mutex writeMutex;
std::condition_variable writeCV;
std::thread readThread, writeThread; std::thread readThread, writeThread;
std::atomic<bool> closing{false}; std::atomic<bool> closing{false};
}; };

View File

@ -199,6 +199,5 @@ void FTDI::writeTask() {
continue; continue;
ftdi.write(writeOp.bytes.data(), (int)writeOp.bytes.size()); ftdi.write(writeOp.bytes.data(), (int)writeOp.bytes.size());
onWrite();
} }
} }

View File

@ -134,6 +134,5 @@ void STM32::writeTask() {
ssize_t actualWritten = ::write(fd, writeOp.bytes.data(), writeSize); ssize_t actualWritten = ::write(fd, writeOp.bytes.data(), writeSize);
if(actualWritten != writeSize) if(actualWritten != writeSize)
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error); report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
onWrite();
} }
} }

View File

@ -297,7 +297,6 @@ void PCAP::writeTask() {
auto bs = sendPacket.getBytestream(); auto bs = sendPacket.getBytestream();
if(!closing) if(!closing)
pcap.sendpacket(interface.fp, bs.data(), (int)bs.size()); pcap.sendpacket(interface.fp, bs.data(), (int)bs.size());
onWrite();
// TODO Handle packet send errors // TODO Handle packet send errors
} }
} }

View File

@ -402,8 +402,6 @@ void VCP::writeTask() {
if(WriteFile(handle, writeOp.bytes.data(), (DWORD)writeOp.bytes.size(), nullptr, &overlappedWrite)) if(WriteFile(handle, writeOp.bytes.data(), (DWORD)writeOp.bytes.size(), nullptr, &overlappedWrite))
continue; continue;
onWrite();
auto winerr = GetLastError(); auto winerr = GetLastError();
if(winerr == ERROR_IO_PENDING) { if(winerr == ERROR_IO_PENDING) {
state = WAIT; state = WAIT;