summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--doc/testscript.cli11
-rw-r--r--tests/test/script/builtin/sed.testscript2
-rw-r--r--tests/test/script/builtin/sleep.testscript31
-rw-r--r--tests/test/script/builtin/test.testscript4
-rw-r--r--tests/test/script/runner/exit.testscript2
-rw-r--r--tests/test/script/runner/set.testscript2
10 files changed, 165 insertions, 8 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";
diff --git a/doc/testscript.cli b/doc/testscript.cli
index 1ef6fc7d..e84dffd7 100644
--- a/doc/testscript.cli
+++ b/doc/testscript.cli
@@ -2657,6 +2657,17 @@ set [null] $foo <-
\
+\h#builtins-sleep|\c{sleep}|
+
+\
+sleep <seconds>
+\
+
+Suspend the current test or test group execution for at least the specified
+number of seconds. Note that in order to improve resource utilization, the
+implementation may sleep longer than requested, potentially significantly.
+
+
\h#builtins-test|\c{test}|
\
diff --git a/tests/test/script/builtin/sed.testscript b/tests/test/script/builtin/sed.testscript
index 1665de2b..e3c0965d 100644
--- a/tests/test/script/builtin/sed.testscript
+++ b/tests/test/script/builtin/sed.testscript
@@ -109,7 +109,7 @@
$c <"sed -e 's/a//' a b" && $b 2>>/EOE != 0
testscript:1:1: error: sed exit code 1 != 0
info: stderr: test/1/stderr
- sed: unexpected argument
+ sed: unexpected argument 'b'
info: test id: 1
EOE
}
diff --git a/tests/test/script/builtin/sleep.testscript b/tests/test/script/builtin/sleep.testscript
new file mode 100644
index 00000000..c43418d4
--- /dev/null
+++ b/tests/test/script/builtin/sleep.testscript
@@ -0,0 +1,31 @@
+# file : tests/test/script/builtin/sleep.testscript
+# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+.include ../common.testscript
+
+: success
+:
+$c <'sleep 1' && $b
+
+: no-time
+:
+: Test passing no time interval.
+:
+$c <'sleep 2>"sleep: missing time interval" != 0' && $b
+
+: invalid-time
+:
+: Test passing invalid time interval.
+:
+$c <<EOI && $b
+sleep 1a 2>"sleep: invalid time interval '1a'" != 0
+EOI
+
+: unexpected-arg
+:
+: Test passing extra argument.
+:
+$c <<EOI && $b
+sleep 1 1 2>"sleep: unexpected argument '1'" != 0
+EOI
diff --git a/tests/test/script/builtin/test.testscript b/tests/test/script/builtin/test.testscript
index c17b3b0b..650f9ef7 100644
--- a/tests/test/script/builtin/test.testscript
+++ b/tests/test/script/builtin/test.testscript
@@ -58,7 +58,9 @@ $c <'test -c a 2>"test: invalid option" == 2' && $b
:
: Test passing extra argument.
:
-$c <'test -f a b 2>"test: unexpected argument" == 2' && $b
+$c <<EOI && $b
+test -f a b 2>"test: unexpected argument 'b'" == 2
+EOI
: empty-path
:
diff --git a/tests/test/script/runner/exit.testscript b/tests/test/script/runner/exit.testscript
index 897cf655..261b02dd 100644
--- a/tests/test/script/runner/exit.testscript
+++ b/tests/test/script/runner/exit.testscript
@@ -77,7 +77,7 @@ empty_id = ''
: unexpected
:
$c <'exit "foo" "bar"' && $b 2>>EOE != 0
- testscript:1:1: error: unexpected argument
+ testscript:1:1: error: unexpected argument 'bar'
info: test id: 1
EOE
}
diff --git a/tests/test/script/runner/set.testscript b/tests/test/script/runner/set.testscript
index a7959636..28d66869 100644
--- a/tests/test/script/runner/set.testscript
+++ b/tests/test/script/runner/set.testscript
@@ -53,7 +53,7 @@
: unexpected
:
$c <'set foo bar baz' && $b 2>>EOE != 0
- testscript:1:1: error: unexpected argument
+ testscript:1:1: error: unexpected argument 'baz'
info: test id: 1
EOE