diff --git a/include/ircd/fs/fs.h b/include/ircd/fs/fs.h index f96bc234e..c94f51334 100644 --- a/include/ircd/fs/fs.h +++ b/include/ircd/fs/fs.h @@ -55,6 +55,7 @@ namespace ircd::fs #include "dev.h" #include "fd.h" #include "aio.h" +#include "wait.h" #include "read.h" #include "write.h" #include "sync.h" diff --git a/include/ircd/fs/op.h b/include/ircd/fs/op.h index d021466ca..faec793ee 100644 --- a/include/ircd/fs/op.h +++ b/include/ircd/fs/op.h @@ -33,4 +33,5 @@ enum class ircd::fs::op READ = 1, WRITE = 2, SYNC = 3, + WAIT = 4, }; diff --git a/include/ircd/fs/wait.h b/include/ircd/fs/wait.h new file mode 100644 index 000000000..4e53982a1 --- /dev/null +++ b/include/ircd/fs/wait.h @@ -0,0 +1,46 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_FS_WAIT_H + +namespace ircd::fs +{ + enum class ready :uint8_t; + struct wait_opts extern const wait_opts_default; + + string_view reflect(const ready &); + + void wait(const fd &, const wait_opts &); +} + +enum class ircd::fs::ready +:uint8_t +{ + ANY, ///< Wait for anything. + READ, ///< Ready for read(). + WRITE, ///< Ready for write(). + ERROR, ///< Has error. +}; + +/// Options for a write operation +struct ircd::fs::wait_opts +:opts +{ + enum ready ready; + + wait_opts(const enum ready &ready = ready::ANY); +}; + +inline +ircd::fs::wait_opts::wait_opts(const enum ready &ready) +:opts{0, op::WAIT} +,ready{ready} +{} diff --git a/ircd/fs.cc b/ircd/fs.cc index 7d53eff55..8d6bb9b69 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -1034,6 +1034,95 @@ ircd::fs::flags(const write_opts &opts) return ret; } +/////////////////////////////////////////////////////////////////////////////// +// +// fs/wait.h +// + +namespace ircd::fs +{ + static asio::posix::stream_descriptor::wait_type translate(const ready &); +} + +decltype(ircd::fs::wait_opts_default) +ircd::fs::wait_opts_default; + +void +ircd::fs::wait(const fd &fd, + const wait_opts &opts) +{ + assert(opts.op == op::WAIT); + + const auto &wait_type + { + translate(opts.ready) + }; + + boost::asio::posix::stream_descriptor sd + { + ios::get(), int(fd) + }; + + const unwind release{[&sd] + { + sd.release(); + }}; + + const auto interruption{[&sd] + (ctx::ctx *const &interruptor) + { + sd.cancel(); + }}; + + boost::system::error_code ec; continuation + { + continuation::asio_predicate, interruption, [&wait_type, &sd, &ec] + (auto &yield) + { + sd.async_wait(wait_type, yield[ec]); + } + }; + + if(unlikely(ec)) + throw_system_error(ec); +} + +boost::asio::posix::stream_descriptor::wait_type +ircd::fs::translate(const ready &ready) +{ + using wait_type = boost::asio::posix::stream_descriptor::wait_type; + + switch(ready) + { + case ready::ANY: + return wait_type::wait_read | wait_type::wait_write | wait_type::wait_error; + + case ready::READ: + return wait_type::wait_read; + + case ready::WRITE: + return wait_type::wait_write; + + case ready::ERROR: + default: + return wait_type::wait_error; + } +} + +ircd::string_view +ircd::fs::reflect(const ready &ready) +{ + switch(ready) + { + case ready::ANY: return "ANY"; + case ready::READ: return "READ"; + case ready::WRITE: return "WRITE"; + case ready::ERROR: return "ERROR"; + } + + return "?????"; +} + /////////////////////////////////////////////////////////////////////////////// // // fs/aio.h @@ -1425,6 +1514,7 @@ ircd::fs::reflect(const op &op) case op::READ: return "READ"; case op::WRITE: return "WRITE"; case op::SYNC: return "SYNC"; + case op::WAIT: return "WAIT"; } return "????";