[clock] Introduce zx_clock_get_new to eventually supplant zx_clock_get

zx_clock_get is problematic in that it cannot report an error,
specifically when an invalid clock id is provided. We will migrate
users to zx_clock_get_new, and then rename zx_clock_get_new to
zx_clock_get.

ZX-2187

Change-Id: Ic5546c286431c4937263e3183bc7f76566f194b8
diff --git a/docs/syscalls/clock_get.md b/docs/syscalls/clock_get.md
index 2a5e1c9..bd87787 100644
--- a/docs/syscalls/clock_get.md
+++ b/docs/syscalls/clock_get.md
@@ -9,7 +9,8 @@
 ```
 #include <zircon/syscalls.h>
 
-zx_time_t zx_clock_get(uint32_t clock_id)
+zx_time_t zx_clock_get(uint32_t clock_id);
+zx_status_t zx_clock_get(uint32_t clock_id, zx_time_t* out_time);
 ```
 
 ## DESCRIPTION
@@ -17,6 +18,9 @@
 **zx_clock_get**() returns the current time of *clock_id*, or 0 if *clock_id* is
 invalid.
 
+**zx_clock_get_new** returns the current time of *clock_id* via
+  *out_time*, and returns whether *clock_id* was valid.
+
 ## SUPPORTED CLOCK IDS
 
 *ZX_CLOCK_MONOTONIC* number of nanoseconds since the system was powered on.
@@ -29,6 +33,10 @@
 
 On success, **zx_clock_get**() returns the current time according to the given clock ID.
 
+On success, **zx_clock_get_new**() returns *ZX_OK*.
+
 ## ERRORS
 
 On error, **zx_clock_get**() currently returns 0.
+
+**ZX_ERR_INVALID_ARGS**  *clock_id* is not a valid clock id, or *out_time* is an invalid pointer.
diff --git a/kernel/syscalls/zircon.cpp b/kernel/syscalls/zircon.cpp
index 44abe03..ceb62f6 100644
--- a/kernel/syscalls/zircon.cpp
+++ b/kernel/syscalls/zircon.cpp
@@ -62,7 +62,7 @@
 // update pvclock too.
 fbl::atomic<int64_t> utc_offset;
 
-uint64_t sys_clock_get(uint32_t clock_id) {
+zx_time_t sys_clock_get(uint32_t clock_id) {
     switch (clock_id) {
     case ZX_CLOCK_MONOTONIC:
         return current_time();
@@ -76,6 +76,25 @@
     }
 }
 
+zx_status_t sys_clock_get_new(uint32_t clock_id, user_out_ptr<zx_time_t> out_time) {
+    zx_time_t time;
+    switch (clock_id) {
+    case ZX_CLOCK_MONOTONIC:
+        time = current_time();
+        break;
+    case ZX_CLOCK_UTC:
+        time = current_time() + utc_offset.load();
+        break;
+    case ZX_CLOCK_THREAD:
+        time = ThreadDispatcher::GetCurrent()->runtime_ns();
+        break;
+    default:
+        return ZX_ERR_INVALID_ARGS;
+    }
+
+    return out_time.copy_to_user(time);
+}
+
 zx_status_t sys_clock_adjust(zx_handle_t hrsrc, uint32_t clock_id, int64_t offset) {
     // TODO(ZX-971): finer grained validation
     zx_status_t status;
diff --git a/system/public/zircon/syscalls.abigen b/system/public/zircon/syscalls.abigen
index 3268afb..4f8f47b 100644
--- a/system/public/zircon/syscalls.abigen
+++ b/system/public/zircon/syscalls.abigen
@@ -53,6 +53,10 @@
     (clock_id: uint32_t)
     returns (zx_time_t);
 
+syscall clock_get_new
+    (clock_id: uint32_t)
+    returns (zx_status_t, out: zx_time_t);
+
 syscall nanosleep blocking
     (deadline: zx_time_t)
     returns (zx_status_t);