aboutsummaryrefslogtreecommitdiff
path: root/libbutl/fdstream.mxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-04-15 16:08:33 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-04-15 16:09:23 +0300
commitc371e6eaea1a4b6ce3bcd9b778cd5636b3304ea4 (patch)
treef12370b7fc83968c44f017dc280d2db3637a2120 /libbutl/fdstream.mxx
parentea26421a8e02c17a6b59ba4565a115cbefb91370 (diff)
Add fdread() and fdselect()
Diffstat (limited to 'libbutl/fdstream.mxx')
-rw-r--r--libbutl/fdstream.mxx93
1 files changed, 78 insertions, 15 deletions
diff --git a/libbutl/fdstream.mxx b/libbutl/fdstream.mxx
index e608a07..894f85b 100644
--- a/libbutl/fdstream.mxx
+++ b/libbutl/fdstream.mxx
@@ -9,12 +9,14 @@
#include <cassert>
#ifndef __cpp_lib_modules
+#include <ios> // streamsize
#include <vector>
#include <string>
#include <istream>
#include <ostream>
-#include <utility> // move()
+#include <utility> // move(), pair
#include <cstdint> // uint16_t, uint64_t
+#include <cstddef> // size_t
#include <iterator>
#endif
@@ -29,9 +31,11 @@ import std.io;
#endif
import butl.path;
import butl.filesystem; // permissions
+import butl.small_vector;
#else
#include <libbutl/path.mxx>
#include <libbutl/filesystem.mxx>
+#include <libbutl/small-vector.mxx>
#endif
#include <libbutl/export.hxx>
@@ -44,7 +48,12 @@ LIBBUTL_MODEXPORT namespace butl
// The descriptor can be negative. Such a descriptor is treated as unopened
// and is not closed.
//
- struct nullfd_t {constexpr explicit nullfd_t (int) {}};
+ struct nullfd_t
+ {
+ constexpr explicit nullfd_t (int) {}
+ constexpr operator int () const {return -1;}
+ };
+
#if defined(__cpp_modules) && defined(__clang__) //@@ MOD Clang duplicate sym.
inline
#endif
@@ -113,7 +122,7 @@ LIBBUTL_MODEXPORT namespace butl
// for reasoning and consider using non-standard tellg() and seekg() in
// fdbuf, instead)
// - non-blocking file descriptor is supported only by showmanyc() function
- // and only on POSIX
+ // and only for pipes on Windows, in contrast to POSIX systems
// - throws ios::failure in case of open(), read(), write(), close(),
// seek[gp](), or tell[gp]() errors
// - exception mask has at least badbit
@@ -154,6 +163,15 @@ LIBBUTL_MODEXPORT namespace butl
int
fd () const {return fd_.get ();}
+ // Set the file descriptor blocking mode returning the previous mode on
+ // success and throwing ios::failure otherwise (see fdmode() for details).
+ //
+ // Note that besides calling fdmode(fd()), this function also updating its
+ // internal state according to the new mode.
+ //
+ bool
+ blocking (bool);
+
public:
using base = std::basic_streambuf<char>;
@@ -253,10 +271,11 @@ LIBBUTL_MODEXPORT namespace butl
// The blocking/non_blocking flags determine whether the IO operation should
// block or return control if currently there is no data to read or no room
// to write. Only the istream::readsome() function supports the semantics of
- // non-blocking operations. We also only support this on POSIX (Windows does
- // not provide means for the non-blocking reading from a file descriptor so
- // these flags are noop there). IO stream operations other than readsome()
- // are illegal for non_blocking mode and result in the badbit being set.
+ // non-blocking operations. In contrast to POSIX systems, we only support
+ // this for pipes on Windows, always assuming the blocking mode for other
+ // file descriptors. IO stream operations other than readsome() are illegal
+ // in the non-blocking mode and result in the badbit being set (note that
+ // it is not the more appropriate failbit for implementation reasons).
//
enum class fdstream_mode: std::uint16_t
{
@@ -656,17 +675,20 @@ LIBBUTL_MODEXPORT namespace butl
LIBBUTL_SYMEXPORT auto_fd
fddup (int fd);
- // Set the translation mode for the file descriptor. Throw invalid_argument
- // for an invalid combination of flags. Return the previous mode on success,
- // throw ios::failure otherwise.
+ // Set the translation and/or blocking modes for the file descriptor. Throw
+ // invalid_argument for an invalid combination of flags. Return the previous
+ // mode on success, throw ios::failure otherwise.
//
- // The text and binary flags are mutually exclusive on Windows. Due to
- // implementation details at least one of them should be specified. On POSIX
+ // The text and binary flags are mutually exclusive on Windows. On POSIX
// system the two modes are the same and so no check is performed.
//
- // The blocking and non-blocking flags are mutually exclusive on POSIX
- // system. Non-blocking mode is not supported on Windows and so the blocking
- // mode is assumed regardless of the flags.
+ // The blocking and non-blocking flags are mutually exclusive. In contrast
+ // to POSIX systems, on Windows the non-blocking mode is only supported for
+ // pipes, with the blocking mode assumed for other file descriptors
+ // regardless of the flags.
+ //
+ // Note that on Wine currently pipes always behave as blocking regardless of
+ // the mode set.
//
LIBBUTL_SYMEXPORT fdstream_mode
fdmode (int, fdstream_mode);
@@ -781,6 +803,47 @@ LIBBUTL_MODEXPORT namespace butl
//
LIBBUTL_SYMEXPORT bool
fdterm (int);
+
+ // Wait until one or more file descriptors becomes ready for reading or
+ // writing. Return the pair of numbers of descriptors that are ready. Throw
+ // std::invalid_argument if anything is wrong with arguments (both sets are
+ // empty, invalid fd, etc). Throw ios::failure on the underlying OS error.
+ //
+ // Note that the function clears all the previously-ready entries on each
+ // call. Entries with nullfd are ignored.
+ //
+ // On Windows only pipes and only their read ends are supported.
+ //
+ struct fdselect_state
+ {
+ int fd;
+ bool ready;
+
+ // Note: intentionally non-explicit to allow implicit initialization when
+ // pushing to fdselect_set.
+ //
+ fdselect_state (int fd): fd (fd), ready (false) {}
+ };
+
+ using fdselect_set = small_vector<fdselect_state, 4>;
+
+ LIBBUTL_SYMEXPORT std::pair<std::size_t, std::size_t>
+ fdselect (fdselect_set& read, fdselect_set& write);
+
+ // As above but wait up to the specified timeout returning a pair of zeroes
+ // if none of the descriptors became ready.
+ //
+ // LIBBUTL_SYMEXPORT std::pair<std::size_t, std::size_t>
+ // fdselect (fdselect_set&, fdselect_set&, const duration& timeout);
+
+ // POSIX read() function wrapper. In particular, it supports the semantics
+ // of non-blocking read for pipes on Windows.
+ //
+ // Note that on Wine currently pipes always behave as blocking regardless of
+ // the mode.
+ //
+ LIBBUTL_SYMEXPORT std::streamsize
+ fdread (int, void*, std::size_t);
}
#include <libbutl/fdstream.ixx>