From: Maxim Mamontov Date: Wed, 8 Apr 2015 19:47:33 +0000 (+0300) Subject: Added blockio library. X-Git-Url: https://git.stg.codes/stg.git/commitdiff_plain/83c4a22d73f9801ced3c29e664e2c000535a0965?ds=inline Added blockio library. --- diff --git a/stglibs/common.lib/blockio.cpp b/stglibs/common.lib/blockio.cpp new file mode 100644 index 00000000..04fd1d81 --- /dev/null +++ b/stglibs/common.lib/blockio.cpp @@ -0,0 +1,102 @@ +#include "stg/blockio.h" + +namespace +{ + +void* adjust(void* base, size_t shift) +{ + char* ptr = static_cast(base); + return ptr + shift; +} + +} // namspace anonymous + +using STG::BlockReader; +using STG::BlockWriter; + +BlockReader::BlockReader(const IOVec& ioVec) + : m_dest(ioVec), + m_remainder(0) +{ + for (size_t i = 0; i < m_dest.size(); ++i) + m_remainder += m_dest[i].iov_len; +} + +bool BlockReader::read(int socket) +{ + if (m_remainder == 0) + return true; + + size_t offset = m_dest.size() - 1; + size_t toRead = m_remainder; + while (offset > 0) { + if (toRead < m_dest[offset].iov_len) + break; + toRead -= m_dest[offset].iov_len; + --offset; + } + + IOVec dest(m_dest.size() - offset); + for (size_t i = 0; i < dest.size(); ++i) { + if (i == 0) { + dest[0].iov_len = toRead; + dest[0].iov_base = adjust(m_dest[offset].iov_base, m_dest[offset].iov_len - toRead); + } else { + dest[i] = m_dest[offset + i]; + } + } + + ssize_t res = readv(socket, dest.data(), dest.size()); + if (res < 0) + return false; + if (res == 0) + return m_remainder == 0; + if (res < static_cast(m_remainder)) + m_remainder -= res; + else + m_remainder = 0; + return true; +} + +BlockWriter::BlockWriter(const IOVec& ioVec) + : m_source(ioVec), + m_remainder(0) +{ + for (size_t i = 0; i < m_source.size(); ++i) + m_remainder += m_source[i].iov_len; +} + +bool BlockWriter::write(int socket) +{ + if (m_remainder == 0) + return true; + + size_t offset = m_source.size() - 1; + size_t toWrite = m_remainder; + while (offset > 0) { + if (toWrite < m_source[offset].iov_len) + break; + toWrite -= m_source[offset].iov_len; + --offset; + } + + IOVec source(m_source.size() - offset); + for (size_t i = 0; i < source.size(); ++i) { + if (i == 0) { + source[0].iov_len = toWrite; + source[0].iov_base = adjust(m_source[offset].iov_base, m_source[offset].iov_len - toWrite); + } else { + source[i] = m_source[offset + i]; + } + } + ssize_t res = writev(socket, source.data(), source.size()); + if (res < 0) + return false; + if (res == 0) + return m_remainder == 0; + if (res < static_cast(m_remainder)) + m_remainder -= res; + else + m_remainder = 0; + return true; +} diff --git a/stglibs/common.lib/include/stg/blockio.h b/stglibs/common.lib/include/stg/blockio.h new file mode 100644 index 00000000..3879e39e --- /dev/null +++ b/stglibs/common.lib/include/stg/blockio.h @@ -0,0 +1,43 @@ +#ifndef __STG_STGLIBS_BLOCK_IO_H__ +#define __STG_STGLIBS_BLOCK_IO_H__ + +#include + +#include + +namespace STG +{ + +typedef std::vector IOVec; + +class BlockReader +{ + public: + BlockReader(const IOVec& ioVec); + + bool read(int socket); + bool done() const { return m_remainder == 0; } + size_t remainder() const { return m_remainder; } + + private: + IOVec m_dest; + size_t m_remainder; +}; + +class BlockWriter +{ + public: + BlockWriter(const IOVec& ioVec); + + bool write(int socket); + bool done() const { return m_remainder == 0; } + size_t remainder() const { return m_remainder; } + + private: + IOVec m_source; + size_t m_remainder; +}; + +} // namespace STG + +#endif