It's stuck in an infinite loop in non_blocking_adaptor<Device>::write(...)
:
std::streamsize result = 0;
while (result < n) {
std::streamsize amt =
iostreams::write(device_, s + result, n - result);
result += amt;
}
return result;
iostream::write(device_, ...
keeps returning 0 (so n stays n, amt and result stay 0).
It would appear to be a bug in Boost IOstreams. Perhaps it was introduced when preliminary support for non-blocking (synchronous) IO was added. According to the documentation, this should be a work in progress.
Particularly enlightening was: http://www.boost.org/doc/libs/1_55_0/libs/iostreams/doc/guide/asynchronous.html
Filters
Filters are allowed to propagate temporary failure notifications: if a downstream Device consumes or produces fewer characters than requested by a Filter, and if as a result the Filter is not able to satisfy a read or write request, the Filter may return a value indicating that input or output is temporarily unavailable. It is hoped that this ability will suffice to allow the current Filter concepts to be used with both aynchronous and non-blocking i/o. However, in order to be useful with blocking i/o as well, a Filter must never return a temporary failure notification unless it has received a such notification from a downstream Device. This requirement is summarized by stating that Filters must be blocking-preserving. See Blocking.
(bold mine) It does appear as if IOStreams violated this principle by transforming the E_NOSPC condition into a temporary failure notification.
boost::iostreams::copy
special-cases the case where source and destination Indirect devices. In this case, both are indirect. Now the special case wraps the sink in a non_blocking_adaptor
. I don't know why, and this seems to contradict the following general advice taken from the same documentation page:
Streams and Stream Buffers
Although the Boost.Iostreams Filter and Device concepts can accommodate non-blocking i/o, the C++ standard library stream and stream buffer interfaces cannot, since they lack a means to distinguish between temporary and permanent failures to satisfy a read or write request. As a result, non-blocking Devices do not work properly with the templates stream, stream_buffer, filtering_stream and filtering_streambuf.
I tried to replace the files with file_sink
and file_source
instead, but there was no change. :(
Here's my reduced test case which still reproduces the problem:
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
int main()
{
using namespace boost::iostreams;
file_source ifs("/dev/zero");
file_sink ofs("/dev/full");
filtering_streambuf<output> filters(ofs);
copy(ifs, filters);
}
Perhaps you should report this as a bug with the developers/mailing list.