diff options
-rw-r--r-- | build2/scheduler.cxx | 26 | ||||
-rw-r--r-- | build2/scheduler.hxx | 7 | ||||
-rw-r--r-- | build2/test/script/builtin.cxx | 84 | ||||
-rw-r--r-- | build2/test/script/runner.cxx | 4 | ||||
-rw-r--r-- | doc/testscript.cli | 11 | ||||
-rw-r--r-- | tests/test/script/builtin/sed.testscript | 2 | ||||
-rw-r--r-- | tests/test/script/builtin/sleep.testscript | 31 | ||||
-rw-r--r-- | tests/test/script/builtin/test.testscript | 4 | ||||
-rw-r--r-- | tests/test/script/runner/exit.testscript | 2 | ||||
-rw-r--r-- | tests/test/script/runner/set.testscript | 2 |
10 files changed, 165 insertions, 8 deletions
diff --git a/build2/scheduler.cxx b/build2/scheduler.cxx index 2438d0b..053532e 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 388fa61..cd3693b 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 cf8f20d..657d8d4 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 2f4b0a2..c881031 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 1ef6fc7..e84dffd 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 1665de2..e3c0965 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 0000000..c43418d --- /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 c17b3b0..650f9ef 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 897cf65..261b02d 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 a795963..28d6686 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 |