diff --git a/include/proxy-wasm/context.h b/include/proxy-wasm/context.h index c373cf32..2487e30a 100644 --- a/include/proxy-wasm/context.h +++ b/include/proxy-wasm/context.h @@ -245,6 +245,19 @@ class ContextBase : public RootInterface, #else unimplemented(); return 0; +#endif + } + uint64_t getMonotonicTimeNanoseconds() override { +#if !defined(_MSC_VER) + struct timespec tpe; + clock_gettime(CLOCK_MONOTONIC, &tpe); + uint64_t t = tpe.tv_sec; + t *= 1000000000; + t += tpe.tv_nsec; + return t; +#else + unimplemented(); + return 0; #endif } std::string_view getConfiguration() override { diff --git a/include/proxy-wasm/context_interface.h b/include/proxy-wasm/context_interface.h index 1a6f738d..841dd0e1 100644 --- a/include/proxy-wasm/context_interface.h +++ b/include/proxy-wasm/context_interface.h @@ -557,6 +557,9 @@ struct GeneralInterface { // Provides the current time in nanoseconds since the Unix epoch. virtual uint64_t getCurrentTimeNanoseconds() = 0; + // Provides the monotonic time in nanoseconds. + virtual uint64_t getMonotonicTimeNanoseconds() = 0; + // Returns plugin configuration. virtual std::string_view getConfiguration() = 0; diff --git a/src/exports.cc b/src/exports.cc index 97bbab06..9a6431ce 100644 --- a/src/exports.cc +++ b/src/exports.cc @@ -833,12 +833,19 @@ Word wasi_unstable_args_sizes_get(void *raw_context, Word argc_ptr, Word argv_bu Word wasi_unstable_clock_time_get(void *raw_context, Word clock_id, uint64_t precision, Word result_time_uint64_ptr) { - if (clock_id != 0 /* realtime */) { + uint64_t result = 0; + auto context = WASM_CONTEXT(raw_context); + switch (clock_id) { + case 0 /* realtime */: + result = context->getCurrentTimeNanoseconds(); + break; + case 1 /* monotonic */: + result = context->getMonotonicTimeNanoseconds(); + break; + default: + // process_cputime_id and thread_cputime_id are not supported yet. return 58; // __WASI_ENOTSUP } - - auto context = WASM_CONTEXT(raw_context); - uint64_t result = context->getCurrentTimeNanoseconds(); if (!context->wasm()->setDatatype(result_time_uint64_ptr, result)) { return 21; // __WASI_EFAULT } diff --git a/test/BUILD b/test/BUILD index 0fad5ceb..60ff362a 100644 --- a/test/BUILD +++ b/test/BUILD @@ -37,6 +37,7 @@ cc_test( srcs = ["exports_test.cc"], copts = COPTS, data = [ + "//test/test_data:clock.wasm", "//test/test_data:env.wasm", ], linkopts = LINKOPTS, diff --git a/test/exports_test.cc b/test/exports_test.cc index 74e23c08..c35ea02d 100644 --- a/test/exports_test.cc +++ b/test/exports_test.cc @@ -91,5 +91,28 @@ TEST_P(TestVM, WithoutEnvironment) { EXPECT_EQ(context.log_msg(), ""); } +TEST_P(TestVM, Clock) { + initialize("clock.wasm"); + auto wasm_base = WasmBase(std::move(vm_), "vm_id", "", "", {}, {}); + ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, false)); + + TestContext context(&wasm_base); + current_context_ = &context; + + wasm_base.registerCallbacks(); + + ASSERT_TRUE(wasm_base.wasm_vm()->link("")); + + WasmCallVoid<0> run; + wasm_base.wasm_vm()->getFunction("run", &run); + ASSERT_TRUE(run); + run(current_context_); + + // Check logs. + auto msg = context.log_msg(); + EXPECT_NE(std::string::npos, msg.find("monotonic: ")) << msg; + EXPECT_NE(std::string::npos, msg.find("realtime: ")) << msg; +} + } // namespace } // namespace proxy_wasm diff --git a/test/test_data/BUILD b/test/test_data/BUILD index 715ed92e..3d99c103 100644 --- a/test/test_data/BUILD +++ b/test/test_data/BUILD @@ -22,3 +22,9 @@ wasm_rust_binary( srcs = ["env.rs"], wasi = True, ) + +wasm_rust_binary( + name = "clock.wasm", + srcs = ["clock.rs"], + wasi = True, +) diff --git a/test/test_data/clock.rs b/test/test_data/clock.rs new file mode 100644 index 00000000..480a2b1b --- /dev/null +++ b/test/test_data/clock.rs @@ -0,0 +1,21 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::time::{Instant, SystemTime}; + +#[no_mangle] +pub extern "C" fn run() { + println!("monotonic: {:?}", Instant::now()); + println!("realtime: {:?}", SystemTime::now()); +}