summaryrefslogtreecommitdiffstats
path: root/build2
diff options
context:
space:
mode:
Diffstat (limited to 'build2')
-rw-r--r--build2/scheduler.cxx26
-rw-r--r--build2/scheduler.hxx7
-rw-r--r--build2/test/script/builtin.cxx84
-rw-r--r--build2/test/script/runner.cxx4
4 files changed, 117 insertions, 4 deletions
diff --git a/build2/scheduler.cxx b/build2/scheduler.cxx
index 2438d0bb..053532ef 100644
--- a/build2/scheduler.cxx
+++ b/build2/scheduler.cxx
@@ -11,6 +11,14 @@
# endif
#endif
+#ifndef _WIN32
+# include <thread> // this_thread::sleep_for()
+#else
+# include <libbutl/win32-utility.hxx>
+
+# include <chrono>
+#endif
+
#include <cerrno>
#include <exception> // std::terminate()
@@ -175,6 +183,24 @@ namespace build2
throw_generic_error (ECANCELED);
}
+ void scheduler::
+ sleep (const duration& d)
+ {
+ deactivate ();
+
+ // MINGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep().
+ //
+#ifndef _WIN32
+ this_thread::sleep_for (d);
+#else
+ using namespace chrono;
+
+ Sleep (static_cast<DWORD> (duration_cast<milliseconds> (d).count ()));
+#endif
+
+ activate ();
+ }
+
size_t scheduler::
suspend (size_t start_count, const atomic_count& task_count)
{
diff --git a/build2/scheduler.hxx b/build2/scheduler.hxx
index 388fa61a..cd3693be 100644
--- a/build2/scheduler.hxx
+++ b/build2/scheduler.hxx
@@ -140,6 +140,13 @@ namespace build2
void
activate (bool collision = false);
+ // Sleep for the specified duration, deactivating the thread before going
+ // to sleep and re-activating it after waking up (which means this
+ // function may sleep potentially significantly longer than requested).
+ //
+ void
+ sleep (const duration&);
+
// Startup and shutdown.
//
public:
diff --git a/build2/test/script/builtin.cxx b/build2/test/script/builtin.cxx
index cf8f20d2..657d8d42 100644
--- a/build2/test/script/builtin.cxx
+++ b/build2/test/script/builtin.cxx
@@ -4,15 +4,19 @@
#include <build2/test/script/builtin.hxx>
+#include <chrono>
#include <locale>
#include <ostream>
#include <sstream>
+#include <cstdlib> // strtoull()
#include <libbutl/regex.mxx>
#include <libbutl/path-io.mxx> // use default operator<< implementation
#include <libbutl/fdstream.mxx> // fdopen_mode, fdstream_mode
#include <libbutl/filesystem.mxx>
+#include <build2/context.hxx> // sched
+
#include <build2/test/script/script.hxx>
// Strictly speaking a builtin which reads/writes from/to standard streams
@@ -1498,7 +1502,7 @@ namespace build2
}
if (i != e)
- error () << "unexpected argument";
+ error () << "unexpected argument '" << *i << "'";
// If we edit file in place make sure that the file path is specified
// and obtain a temporary file path. We will be writing to the
@@ -1634,6 +1638,81 @@ namespace build2
return 1;
}
+ // sleep <seconds>
+ //
+ // Note: can be executed synchronously.
+ //
+ static uint8_t
+ sleep (scope&,
+ const strings& args,
+ auto_fd in, auto_fd out, auto_fd err) noexcept
+ try
+ {
+ uint8_t r (1);
+ ofdstream cerr (move (err));
+
+ auto error = [&cerr] (bool fail = true)
+ {
+ return error_record (cerr, fail, "sleep");
+ };
+
+ try
+ {
+ in.close ();
+ out.close ();
+
+ if (args.empty ())
+ error () << "missing time interval";
+
+ if (args.size () > 1)
+ error () << "unexpected argument '" << args[1] << "'";
+
+ uint64_t n;
+
+ for (;;) // Breakout loop.
+ {
+ const string& a (args[0]);
+
+ // Note: strtoull() allows these.
+ //
+ if (!a.empty () && a[0] != '-' && a[0] != '+')
+ {
+ char* e (nullptr);
+ n = strtoull (a.c_str (), &e, 10); // Can't throw.
+
+ if (errno != ERANGE && e == a.c_str () + a.size ())
+ break;
+ }
+
+ error () << "invalid time interval '" << a << "'";
+ }
+
+ // If/when required we could probably support the precise sleep mode
+ // (e.g., via an option).
+ //
+ sched.sleep (chrono::seconds (n));
+
+ r = 0;
+ }
+ // Can be thrown while closing in, out or writing to cerr.
+ //
+ catch (const io_error& e)
+ {
+ error (false) << e;
+ }
+ catch (const failed&)
+ {
+ // Diagnostics has already been issued.
+ }
+
+ cerr.close ();
+ return r;
+ }
+ catch (const std::exception&)
+ {
+ return 1;
+ }
+
// test -f|-d <path>
//
// Note: can be executed synchronously.
@@ -1666,7 +1745,7 @@ namespace build2
error () << "invalid option";
if (args.size () > 2)
- error () << "unexpected argument";
+ error () << "unexpected argument '" << args[2] << "'";
path p (parse_path (args[1], sp.wd_path));
@@ -1890,6 +1969,7 @@ namespace build2
{"rm", &sync_impl<&rm>},
{"rmdir", &sync_impl<&rmdir>},
{"sed", &async_impl<&sed>},
+ {"sleep", &sync_impl<&sleep>},
{"test", &sync_impl<&test>},
{"touch", &sync_impl<&touch>},
{"true", &true_}
diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx
index 2f4b0a28..c8810316 100644
--- a/build2/test/script/runner.cxx
+++ b/build2/test/script/runner.cxx
@@ -978,7 +978,7 @@ namespace build2
const string& s (*i++);
if (i != e)
- fail (ll) << "unexpected argument";
+ fail (ll) << "unexpected argument '" << *i << "'";
error (ll) << s;
throw exit_scope (false);
@@ -1040,7 +1040,7 @@ namespace build2
const string& vname (i == e ? a : *i++);
if (i != e)
- fail (ll) << "unexpected argument";
+ fail (ll) << "unexpected argument '" << *i << "'";
if (ats != nullptr && ats->empty ())
fail (ll) << "empty variable attributes";