From 24c84e9423db42563de21da76efd4637ca2abcce Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sun, 10 Aug 2014 22:07:42 -0700 Subject: First pass at the SmartWriter. --- includes/SmartWriter.h | 20 ++++++ src/SmartWriter.cc | 129 ++++++++++++++++++++++++++++++++++++ win32/project/Balau.vcxproj | 2 + win32/project/Balau.vcxproj.filters | 6 ++ 4 files changed, 157 insertions(+) create mode 100644 includes/SmartWriter.h create mode 100644 src/SmartWriter.cc diff --git a/includes/SmartWriter.h b/includes/SmartWriter.h new file mode 100644 index 0000000..d8baf27 --- /dev/null +++ b/includes/SmartWriter.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +class SmartWriterTask; + +namespace Balau { + +class SmartWriter : public Filter { + public: + SmartWriter(IO h) : Filter(h) { AAssert(h->canWrite(), "SmartWriter can't write"); m_name.set("SmartWriter(%s)", h->getName()); } + virtual ssize_t write(const void * buf, size_t count) throw (GeneralException) override; + virtual const char * getName() override { return m_name.to_charp(); } + virtual void close() override; + private: + SmartWriterTask * m_writerTask = NULL; + String m_name; +}; + +} diff --git a/src/SmartWriter.cc b/src/SmartWriter.cc new file mode 100644 index 0000000..9a32330 --- /dev/null +++ b/src/SmartWriter.cc @@ -0,0 +1,129 @@ +#include +#include +#include + +namespace { + +struct WriteCell { + ~WriteCell() { delete buffer; } + const void * buffer = NULL; + const uint8_t * ptr; + size_t size; + bool stop = false; + bool close = false; +}; + +} + +class SmartWriterTask : public Balau::StacklessTask { + public: + SmartWriterTask(Balau::IO h) : m_h(h) { m_name.set("SmartWriterTask(%s)", h->getName()); } + void queueWrite(const void * buf, size_t count) { + WriteCell * cell = new WriteCell(); + uint8_t * copied = (uint8_t *) malloc(count); + memcpy(copied, buf, count); + cell->buffer = cell->ptr = copied; + cell->size = count; + m_queue.push(cell); + } + void stop(bool closeHandle) { + WriteCell * cell = new WriteCell(); + cell->stop = true; + cell->close = closeHandle; + m_queue.push(cell); + } + bool gotError() { return m_gotError; } + private: + virtual ~SmartWriterTask() { empty(); } + virtual const char * getName() const override { return m_name.to_charp(); } + void empty() { + delete m_current; + m_current = NULL; + while (!m_queue.isEmpty()) + delete m_queue.pop(); + } + virtual void Do() override { + waitFor(m_queue.getEvent()); + m_queue.getEvent()->resetMaybe(); + + bool gotQueue = !m_queue.isEmpty(); + + if (gotQueue && !m_current) { + m_current = m_queue.pop(); + gotQueue = !m_queue.isEmpty(); + } + + if (!gotQueue && !m_current) + taskSwitch(); + + if (m_current->stop) { + if (m_current->close) + m_h->close(); + delete m_current; + m_current = NULL; + return; + } + + ssize_t r = 0; + try { + r = m_h->write(m_current->ptr, m_current->size); + } + catch (Balau::EAgain & e) { + waitFor(e.getEvent()); + taskSwitch(); + } + + m_current->ptr += r; + m_current->size -= r; + + if (m_current->size == 0) { + delete m_current; + m_current = NULL; + } + + if (gotQueue || m_current) + yield(); + else + taskSwitch(); + } + Balau::IO m_h; + Balau::String m_name; + std::atomic m_gotError = false; + Balau::TQueue m_queue; + WriteCell * m_current = NULL; +}; + +void Balau::SmartWriter::close() { + if (m_writerTask) { + m_writerTask->stop(!isDetached()); + m_writerTask = NULL; + } else { + Filter::close(); + } +} + +ssize_t Balau::SmartWriter::write(const void * _buf, size_t count) throw (Balau::GeneralException) { + const uint8_t * buf = (const uint8_t *) _buf; + const ssize_t r = count; + while (count) { + if (m_writerTask) { + if (m_writerTask->gotError()) + return -1; + m_writerTask->queueWrite(buf, count); + } + + ssize_t r = 0; + try { + r = Filter::write(buf, count); + } + catch (EAgain &) { + m_writerTask = TaskMan::registerTask(new SmartWriterTask(getIO())); + } + if (r < 0) + return r; + count -= r; + buf += r; + } + + return r; +} diff --git a/win32/project/Balau.vcxproj b/win32/project/Balau.vcxproj index 44ef4ad..493bb72 100644 --- a/win32/project/Balau.vcxproj +++ b/win32/project/Balau.vcxproj @@ -233,6 +233,7 @@ + true @@ -294,6 +295,7 @@ + diff --git a/win32/project/Balau.vcxproj.filters b/win32/project/Balau.vcxproj.filters index cd115d4..06a4981 100644 --- a/win32/project/Balau.vcxproj.filters +++ b/win32/project/Balau.vcxproj.filters @@ -195,6 +195,9 @@ Third Party\getopt + + Source + @@ -365,6 +368,9 @@ Third Party\getopt + + Headers + -- cgit v1.2.3