Skip to content

Commit e2a3b4a

Browse files
committed
Nif: Add erlang/os system_time/0 and monotonic_time/0
Add zero-arity NIF implementations for erlang:system_time/0, erlang:monotonic_time/0, and os:system_time/0,1, returning time in native units. erlang:system_time/0 and erlang:monotonic_time/0 delegate to their /1 counterparts with native os:system_time/0,1 reuse the erlang:system_time NIF directly to avoid code duplication Added Erlang stubs/exports in erlang.erl and os.erl Added Elixir wrappers: System.monotonic_time/0, System.system_time/0, System.os_time/0,1 Added tests for all new functions Signed-off-by: Peter M <petermm@gmail.com>
1 parent 77941f2 commit e2a3b4a

File tree

7 files changed

+146
-1
lines changed

7 files changed

+146
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7979
- Added ESP32 `-DATOMVM_ELIXIR_SUPPORT=on` configuration option
8080
- Added support for ESP32 development builds to include NVS partition data at build time
8181
- Added `nanosecond` and `native` time unit support to `erlang:system_time/1`, `erlang:monotonic_time/1`, and `calendar:system_time_to_universal_time/2`
82+
- Added `erlang:system_time/0`, `erlang:monotonic_time/0`, and `os:system_time/0,1` nifs
8283

8384
### Changed
8485

libs/estdlib/src/erlang.erl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
is_record/2,
4141
map_size/1,
4242
map_get/2,
43+
monotonic_time/0,
4344
monotonic_time/1,
4445
min/2,
4546
max/2,
@@ -104,6 +105,7 @@
104105
exit/1,
105106
exit/2,
106107
open_port/2,
108+
system_time/0,
107109
system_time/1,
108110
group_leader/0,
109111
group_leader/2,
@@ -568,6 +570,10 @@ memory(_Type) ->
568570
%% systems the value may vary among UNIX systems (e.g., Linux, macOS, FreeBSD).
569571
%% @end
570572
%%-----------------------------------------------------------------------------
573+
-spec monotonic_time() -> integer().
574+
monotonic_time() ->
575+
erlang:nif_error(undefined).
576+
571577
-spec monotonic_time(Unit :: time_unit()) -> integer().
572578
monotonic_time(_Unit) ->
573579
erlang:nif_error(undefined).
@@ -1250,6 +1256,15 @@ exit(_Process, _Reason) ->
12501256
open_port(_PortName, _Options) ->
12511257
erlang:nif_error(undefined).
12521258

1259+
%%-----------------------------------------------------------------------------
1260+
%% @returns An integer representing system time.
1261+
%% @doc Returns the current Erlang system time in native time unit.
1262+
%% @end
1263+
%%-----------------------------------------------------------------------------
1264+
-spec system_time() -> integer().
1265+
system_time() ->
1266+
erlang:nif_error(undefined).
1267+
12531268
%%-----------------------------------------------------------------------------
12541269
%% @param Unit Unit to return system time in
12551270
%% @returns An integer representing system time

libs/estdlib/src/os.erl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
%
2020
-module(os).
2121

22-
-export([getenv/1]).
22+
-export([getenv/1, system_time/0, system_time/1]).
2323

2424
%%-----------------------------------------------------------------------------
2525
%% @param Name name of the environment variable
@@ -30,3 +30,21 @@
3030
-spec getenv(Name :: nonempty_string()) -> nonempty_string() | false.
3131
getenv(_VarName) ->
3232
erlang:nif_error(undefined).
33+
34+
%%-----------------------------------------------------------------------------
35+
%% @returns An integer representing system time.
36+
%% @doc Returns the current OS system time in native time unit.
37+
%% @end
38+
%%-----------------------------------------------------------------------------
39+
-spec system_time() -> integer().
40+
system_time() ->
41+
erlang:nif_error(undefined).
42+
43+
%%-----------------------------------------------------------------------------
44+
%% @returns An integer representing system time.
45+
%% @doc Returns the current OS system time in the time unit.
46+
%% @end
47+
%%-----------------------------------------------------------------------------
48+
-spec system_time(TimeUnit :: erlang:time_unit()) -> integer().
49+
system_time(TimeUnit) ->
50+
erlang:nif_error(undefined).

libs/exavmlib/lib/System.ex

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ defmodule System do
2525
:second
2626
| :millisecond
2727
| :microsecond
28+
| :nanosecond
29+
30+
@doc """
31+
Returns the current monotonic time in the `:native` time unit.
32+
33+
This time is monotonically increasing and starts in an unspecified
34+
point in time. This is not strictly monotonically increasing. Multiple
35+
sequential calls of the function may return the same value.
36+
37+
Inlined by the compiler.
38+
"""
39+
@spec monotonic_time() :: integer
40+
def monotonic_time do
41+
:erlang.monotonic_time()
42+
end
2843

2944
@doc """
3045
Returns the current monotonic time in the given time unit.
@@ -37,6 +52,20 @@ defmodule System do
3752
:erlang.monotonic_time(unit)
3853
end
3954

55+
@doc """
56+
Returns the current system time in the `:native` time unit.
57+
58+
It is the VM view of the `os_time/0`. They may not match in
59+
case of time warps although the VM works towards aligning
60+
them. This time is not monotonic.
61+
62+
Inlined by the compiler.
63+
"""
64+
@spec system_time() :: integer
65+
def system_time do
66+
:erlang.system_time()
67+
end
68+
4069
@doc """
4170
Returns the current system time in the given time unit.
4271
@@ -48,4 +77,30 @@ defmodule System do
4877
def system_time(unit) do
4978
:erlang.system_time(unit)
5079
end
80+
81+
@doc """
82+
Returns the current operating system (OS) time.
83+
84+
The result is returned in the `:native` time unit.
85+
86+
This time may be adjusted forwards or backwards in time
87+
with no limitation and is not monotonic.
88+
89+
Inlined by the compiler.
90+
"""
91+
@spec os_time() :: integer
92+
def os_time do
93+
:os.system_time()
94+
end
95+
96+
@doc """
97+
Returns the current operating system (OS) time in the given time `unit`.
98+
99+
This time may be adjusted forwards or backwards in time
100+
with no limitation and is not monotonic.
101+
"""
102+
@spec os_time(time_unit | :native) :: integer
103+
def os_time(unit) do
104+
:os.system_time(unit)
105+
end
51106
end

src/libAtomVM/nifs.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ static term nif_erlang_float_to_list(Context *ctx, int argc, term argv[]);
187187
static term nif_erlang_list_to_binary_1(Context *ctx, int argc, term argv[]);
188188
static term nif_erlang_list_to_integer(Context *ctx, int argc, term argv[]);
189189
static term nif_erlang_list_to_float_1(Context *ctx, int argc, term argv[]);
190+
static term nif_erlang_monotonic_time_0(Context *ctx, int argc, term argv[]);
190191
static term nif_erlang_monotonic_time_1(Context *ctx, int argc, term argv[]);
191192
static term nif_erlang_iolist_size_1(Context *ctx, int argc, term argv[]);
192193
static term nif_erlang_iolist_to_binary_1(Context *ctx, int argc, term argv[]);
@@ -198,7 +199,9 @@ static term nif_erlang_setelement_3(Context *ctx, int argc, term argv[]);
198199
// static term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]);
199200
static term nif_erlang_spawn_fun_opt(Context *ctx, int argc, term argv[]);
200201
static term nif_erlang_whereis_1(Context *ctx, int argc, term argv[]);
202+
static term nif_erlang_system_time_0(Context *ctx, int argc, term argv[]);
201203
static term nif_erlang_system_time_1(Context *ctx, int argc, term argv[]);
204+
202205
static term nif_erlang_tuple_to_list_1(Context *ctx, int argc, term argv[]);
203206
static term nif_erlang_list_to_tuple_1(Context *ctx, int argc, term argv[]);
204207
static term nif_erlang_universaltime_0(Context *ctx, int argc, term argv[]);
@@ -533,11 +536,21 @@ static const struct Nif concat_nif = {
533536
.nif_ptr = nif_erlang_concat_2
534537
};
535538

539+
static const struct Nif monotonic_time_0_nif = {
540+
.base.type = NIFFunctionType,
541+
.nif_ptr = nif_erlang_monotonic_time_0
542+
};
543+
536544
static const struct Nif monotonic_time_nif = {
537545
.base.type = NIFFunctionType,
538546
.nif_ptr = nif_erlang_monotonic_time_1
539547
};
540548

549+
static const struct Nif system_time_0_nif = {
550+
.base.type = NIFFunctionType,
551+
.nif_ptr = nif_erlang_system_time_0
552+
};
553+
541554
static const struct Nif system_time_nif = {
542555
.base.type = NIFFunctionType,
543556
.nif_ptr = nif_erlang_system_time_1
@@ -1709,6 +1722,14 @@ term nif_erlang_make_ref_0(Context *ctx, int argc, term argv[])
17091722
return term_from_ref_ticks(ref_ticks, &ctx->heap);
17101723
}
17111724

1725+
static term nif_erlang_monotonic_time_0(Context *ctx, int argc, term argv[])
1726+
{
1727+
UNUSED(argc);
1728+
UNUSED(argv);
1729+
term native_argv[] = { NATIVE_ATOM };
1730+
return nif_erlang_monotonic_time_1(ctx, 1, native_argv);
1731+
}
1732+
17121733
term nif_erlang_monotonic_time_1(Context *ctx, int argc, term argv[])
17131734
{
17141735
UNUSED(ctx);
@@ -1734,6 +1755,14 @@ term nif_erlang_monotonic_time_1(Context *ctx, int argc, term argv[])
17341755
}
17351756
}
17361757

1758+
static term nif_erlang_system_time_0(Context *ctx, int argc, term argv[])
1759+
{
1760+
UNUSED(argc);
1761+
UNUSED(argv);
1762+
term native_argv[] = { NATIVE_ATOM };
1763+
return nif_erlang_system_time_1(ctx, 1, native_argv);
1764+
}
1765+
17371766
term nif_erlang_system_time_1(Context *ctx, int argc, term argv[])
17381767
{
17391768
UNUSED(ctx);

src/libAtomVM/nifs.gperf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ binary:match/2, &binary_match_nif
4545
binary:match/3, &binary_match_nif
4646
calendar:system_time_to_universal_time/2, &system_time_to_universal_time_nif
4747
os:getenv/1, &os_getenv_nif
48+
os:system_time/0, &system_time_0_nif
49+
os:system_time/1, &system_time_nif
4850
erlang:atom_to_binary/1, &atom_to_binary_nif
4951
erlang:atom_to_binary/2, &atom_to_binary_nif
5052
erlang:atom_to_list/1, &atom_to_list_nif
@@ -101,7 +103,9 @@ erlang:system_flag/2, &system_flag_nif
101103
erlang:whereis/1, &whereis_nif
102104
erlang:++/2, &concat_nif
103105
erlang:--/2, &erlang_lists_subtract_nif
106+
erlang:monotonic_time/0, &monotonic_time_0_nif
104107
erlang:monotonic_time/1, &monotonic_time_nif
108+
erlang:system_time/0, &system_time_0_nif
105109
erlang:system_time/1, &system_time_nif
106110
erlang:tuple_to_list/1, &tuple_to_list_nif
107111
erlang:universaltime/0, &universaltime_nif

tests/erlang_tests/test_system_time.erl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ start() ->
2929
ok = test_system_time(nanosecond, 1),
3030
ok = test_native_system_time(),
3131

32+
ok = test_erlang_monotonic_time_0(),
33+
ok = test_erlang_system_time_0(),
34+
ok = test_os_system_time(),
3235
ok = test_time_unit_ratios(),
3336

3437
ok = expect(fun() -> erlang:system_time(not_a_time_unit) end, badarg),
@@ -44,6 +47,26 @@ test_system_time(Unit, SleepMs) ->
4447
true = (After > Before),
4548
ok.
4649

50+
test_erlang_monotonic_time_0() ->
51+
T = erlang:monotonic_time(),
52+
true = is_integer(T),
53+
ok.
54+
55+
test_erlang_system_time_0() ->
56+
T = erlang:system_time(),
57+
true = is_integer(T) andalso T > 0,
58+
ok.
59+
60+
test_os_system_time() ->
61+
T0 = os:system_time(),
62+
true = is_integer(T0) andalso T0 > 0,
63+
ok = test_system_time_unit(os_system_time_second, fun() -> os:system_time(second) end),
64+
ok = test_system_time_unit(os_system_time_millisecond, fun() -> os:system_time(millisecond) end),
65+
ok = test_system_time_unit(os_system_time_microsecond, fun() -> os:system_time(microsecond) end),
66+
ok = test_system_time_unit(os_system_time_nanosecond, fun() -> os:system_time(nanosecond) end),
67+
ok = test_system_time_unit(os_system_time_native, fun() -> os:system_time(native) end),
68+
ok.
69+
4770
test_system_time_unit(_Name, Fun) ->
4871
T = Fun(),
4972
true = is_integer(T) andalso T > 0,

0 commit comments

Comments
 (0)