aboutsummaryrefslogtreecommitdiffstats
path: root/erts/preloaded/src/erlang.erl
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2015-02-13 00:25:57 +0100
committerRickard Green <[email protected]>2015-03-20 15:28:52 +0100
commit6b1921d767de5cd1a980234f83b36dbfa13d9fc7 (patch)
tree0b7a016c2b41f30f1adf81559e5fc6a4567099ea /erts/preloaded/src/erlang.erl
parentfa7b2c00cbf9212c4a3551980939b92fc6606510 (diff)
downloadotp-6b1921d767de5cd1a980234f83b36dbfa13d9fc7.tar.gz
otp-6b1921d767de5cd1a980234f83b36dbfa13d9fc7.tar.bz2
otp-6b1921d767de5cd1a980234f83b36dbfa13d9fc7.zip
Erlang based BIF timer implementation for scalability
Diffstat (limited to 'erts/preloaded/src/erlang.erl')
-rw-r--r--erts/preloaded/src/erlang.erl191
1 files changed, 181 insertions, 10 deletions
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 79eb60f362..83010b17d2 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -89,7 +89,7 @@
-export([binary_to_list/3, binary_to_term/1, binary_to_term/2]).
-export([bit_size/1, bitsize/1, bitstring_to_list/1]).
-export([bump_reductions/1, byte_size/1, call_on_load_function/1]).
--export([cancel_timer/1, check_old_code/1, check_process_code/2,
+-export([cancel_timer/1, cancel_timer/2, check_old_code/1, check_process_code/2,
check_process_code/3, crc32/1]).
-export([crc32/2, crc32_combine/3, date/0, decode_packet/3]).
-export([delete_element/2]).
@@ -128,7 +128,7 @@
-export([time_offset/0, time_offset/1, timestamp/0]).
-export([process_display/2]).
-export([process_flag/3, process_info/1, processes/0, purge_module/1]).
--export([put/2, raise/3, read_timer/1, ref_to_list/1, register/2]).
+-export([put/2, raise/3, read_timer/1, read_timer/2, ref_to_list/1, register/2]).
-export([registered/0, resume_process/1, round/1, self/0, send_after/3]).
-export([seq_trace/2, seq_trace_print/1, seq_trace_print/2, setnode/2]).
-export([setnode/3, size/1, spawn/3, spawn_link/3, split_binary/2]).
@@ -427,8 +427,77 @@ call_on_load_function(_P1) ->
-spec erlang:cancel_timer(TimerRef) -> Time | false when
TimerRef :: reference(),
Time :: non_neg_integer().
-cancel_timer(_TimerRef) ->
- erlang:nif_error(undefined).
+cancel_timer(TimerRef) ->
+ try
+ case erts_internal:access_bif_timer(TimerRef) of
+ undefined ->
+ false;
+ {BTR, TSrv} ->
+ Req = erlang:make_ref(),
+ TSrv ! {cancel_timeout, BTR, erlang:self(),
+ true, Req, TimerRef},
+ receive
+ {cancel_timer, Req, Result} ->
+ Result
+ end
+ end
+ catch
+ _:_ -> erlang:error(badarg, [TimerRef])
+ end.
+
+%% cancel_timer/2
+-spec erlang:cancel_timer(TimerRef, Options) -> Time | false | ok when
+ TimerRef :: reference(),
+ Option :: {async, boolean()} | {info, boolean()},
+ Options :: [Option],
+ Time :: non_neg_integer().
+cancel_timer(TimerRef, Options) ->
+ try
+ {Async, Info} = get_cancel_timer_options(Options, false, true),
+ case erts_internal:access_bif_timer(TimerRef) of
+ undefined ->
+ case {Async, Info} of
+ {true, true} ->
+ erlang:self() ! {cancel_timer, TimerRef, false}, ok;
+ {false, true} ->
+ false;
+ _ ->
+ ok
+ end;
+ {BTR, TSrv} ->
+ case Async of
+ true ->
+ TSrv ! {cancel_timeout, BTR, erlang:self(),
+ Info, TimerRef, TimerRef},
+ ok;
+ false ->
+ Req = erlang:make_ref(),
+ TSrv ! {cancel_timeout, BTR, erlang:self(),
+ true, Req, TimerRef},
+ receive
+ {cancel_timer, Req, Result} ->
+ case Info of
+ true -> Result;
+ false -> ok
+ end
+ end
+ end
+ end
+ catch
+ _:_ -> erlang:error(badarg, [TimerRef, Options])
+ end.
+
+get_cancel_timer_options([], Async, Info) ->
+ {Async, Info};
+get_cancel_timer_options([{async, Bool} | Opts],
+ _Async, Info) when Bool == true;
+ Bool == false ->
+ get_cancel_timer_options(Opts, Bool, Info);
+get_cancel_timer_options([{info, Bool} | Opts],
+ Async, _Info) when Bool == true;
+ Bool == false ->
+ get_cancel_timer_options(Opts, Async, Bool).
+
%% check_old_code/1
-spec check_old_code(Module) -> boolean() when
@@ -1462,8 +1531,53 @@ raise(_Class, _Reason, _Stacktrace) ->
%% read_timer/1
-spec erlang:read_timer(TimerRef) -> non_neg_integer() | false when
TimerRef :: reference().
-read_timer(_TimerRef) ->
- erlang:nif_error(undefined).
+
+read_timer(TimerRef) ->
+ read_timer(TimerRef, []).
+
+%% read_timer/2
+-spec erlang:read_timer(TimerRef, Options) -> non_neg_integer() | false | ok when
+ TimerRef :: reference(),
+ Option :: {async, boolean()},
+ Options :: [Option].
+
+read_timer(TimerRef, Options) ->
+ try
+ Async = get_read_timer_options(Options, false),
+ case erts_internal:access_bif_timer(TimerRef) of
+ undefined ->
+ case Async of
+ true ->
+ erlang:self() ! {read_timer, TimerRef, false},
+ ok;
+ false ->
+ false
+ end;
+ {BTR, TSrv} ->
+ case Async of
+ true ->
+ TSrv ! {read_timeout, BTR, erlang:self(),
+ TimerRef, TimerRef},
+ ok;
+ false ->
+ Req = erlang:make_ref(),
+ TSrv ! {read_timeout, BTR, erlang:self(),
+ Req, TimerRef},
+ receive
+ {read_timer, Req, Result} ->
+ Result
+ end
+ end
+ end
+ catch
+ _:_ -> erlang:error(badarg, [TimerRef])
+ end.
+
+get_read_timer_options([], Async) ->
+ Async;
+get_read_timer_options([{async, Bool} | Opts],
+ _Async) when Bool == true; Bool == false ->
+ get_read_timer_options(Opts, Bool).
%% ref_to_list/1
-spec erlang:ref_to_list(Ref) -> string() when
@@ -1509,8 +1623,36 @@ self() ->
Dest :: pid() | atom(),
Msg :: term(),
TimerRef :: reference().
-send_after(_Time, _Dest, _Msg) ->
- erlang:nif_error(undefined).
+
+send_after(0, Dest, Msg) ->
+ try
+ true = ((erlang:is_pid(Dest)
+ andalso erlang:node(Dest) == erlang:node())
+ orelse (erlang:is_atom(Dest)
+ andalso Dest /= undefined)),
+ try Dest ! Msg catch _:_ -> ok end,
+ erlang:make_ref()
+ catch
+ _:_ ->
+ erlang:error(badarg, [0, Dest, Msg])
+ end;
+send_after(Time, Dest, Msg) ->
+ Now = erlang:monotonic_time(),
+ try
+ true = ((erlang:is_pid(Dest)
+ andalso erlang:node(Dest) == erlang:node())
+ orelse (erlang:is_atom(Dest)
+ andalso Dest /= undefined)),
+ true = Time > 0,
+ true = Time < (1 bsl 32), % Maybe lift this restriction...
+ TO = Now + (erts_internal:time_unit()*Time) div 1000,
+ {BTR, TSrv, TRef} = erts_internal:create_bif_timer(),
+ TSrv ! {set_timeout, BTR, Dest, TO, TRef, Msg},
+ TRef
+ catch
+ _:_ ->
+ erlang:error(badarg, [Time, Dest, Msg])
+ end.
%% seq_trace/2
-spec erlang:seq_trace(P1, P2) -> seq_trace_info_returns() | {term(), term(), term(), term(), term()} when
@@ -1583,8 +1725,37 @@ split_binary(_Bin, _Pos) ->
Dest :: pid() | atom(),
Msg :: term(),
TimerRef :: reference().
-start_timer(_Time, _Dest, _Msg) ->
- erlang:nif_error(undefined).
+start_timer(0, Dest, Msg) ->
+ try
+ true = ((erlang:is_pid(Dest)
+ andalso erlang:node(Dest) == erlang:node())
+ orelse (erlang:is_atom(Dest)
+ andalso Dest /= undefined)),
+ TimerRef = erlang:make_ref(),
+ try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end,
+ TimerRef
+ catch
+ _:_ ->
+ erlang:error(badarg, [0, Dest, Msg])
+ end;
+start_timer(Time, Dest, Msg) ->
+ Now = erlang:monotonic_time(),
+ try
+ true = ((erlang:is_pid(Dest)
+ andalso erlang:node(Dest) == erlang:node())
+ orelse (erlang:is_atom(Dest)
+ andalso Dest /= undefined)),
+ true = Time > 0,
+ true = Time < (1 bsl 32), % Maybe lift this restriction...
+ TO = Now + (erts_internal:time_unit()*Time) div 1000,
+ {BTR, TSrv, TimerRef} = erts_internal:create_bif_timer(),
+ TSrv ! {set_timeout, BTR, Dest, TO, TimerRef,
+ {timeout, TimerRef, Msg}},
+ TimerRef
+ catch
+ _:_ ->
+ erlang:error(badarg, [Time, Dest, Msg])
+ end.
%% suspend_process/2
-spec erlang:suspend_process(Suspendee, OptList) -> boolean() when