Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
2781-Write-type-specifications-for-gen_server.p...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2781-Write-type-specifications-for-gen_server.patch of Package erlang
From e9dfd9d54e398b414f40cf65c4b37ba5b648858d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen <raimo@erlang.org> Date: Fri, 11 Feb 2022 18:15:34 +0100 Subject: [PATCH 1/8] Write type specifications for gen_server --- lib/stdlib/src/gen.erl | 29 +++-- lib/stdlib/src/gen_event.erl | 7 +- lib/stdlib/src/gen_server.erl | 230 +++++++++++++++++++++++++++++++--- lib/stdlib/src/gen_statem.erl | 44 ++++--- lib/stdlib/src/proc_lib.erl | 32 +++-- 5 files changed, 290 insertions(+), 52 deletions(-) diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index ef04e74c5c..1ebd4ac868 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -43,25 +43,36 @@ %%----------------------------------------------------------------- +-export_type( + [reply_tag/0, + request_id/0]). + -type linkage() :: 'monitor' | 'link' | 'nolink'. -type emgr_name() :: {'local', atom()} | {'global', term()} | {'via', Module :: module(), Name :: term()}. --type start_ret() :: {'ok', pid()} | {'ok', {pid(), reference()}} | 'ignore' | {'error', term()}. +-type start_ret() :: {'ok', pid()} + | {'ok', {pid(), reference()}} + | 'ignore' + | {'error', term()}. --type debug_flag() :: 'trace' | 'log' | 'statistics' | 'debug' - | {'logfile', string()}. -type option() :: {'timeout', timeout()} - | {'debug', [debug_flag()]} + | {'debug', [sys:debug_option()]} | {'hibernate_after', timeout()} | {'spawn_opt', [proc_lib:spawn_option()]}. --type options() :: [option()]. -type server_ref() :: pid() | atom() | {atom(), node()} | {global, term()} | {via, module(), term()}. --type request_id() :: term(). +-opaque reply_tag() :: % As accepted by reply/2 + reference() + | nonempty_improper_list('alias', reference()) + | nonempty_improper_list( + nonempty_improper_list('alias', reference()), term()). + +-opaque request_id() :: reference(). + %%----------------------------------------------------------------- %% Starts a generic process. @@ -79,7 +90,7 @@ %% The 'already_started' is returned only if Name is given %%----------------------------------------------------------------- --spec start(module(), linkage(), emgr_name(), module(), term(), options()) -> +-spec start(module(), linkage(), emgr_name(), module(), term(), [option()]) -> start_ret(). start(GenMod, LinkP, Name, Mod, Args, Options) -> @@ -90,7 +101,7 @@ start(GenMod, LinkP, Name, Mod, Args, Options) -> {error, {already_started, Pid}} end. --spec start(module(), linkage(), module(), term(), options()) -> start_ret(). +-spec start(module(), linkage(), module(), term(), [option()]) -> start_ret(). start(GenMod, LinkP, Mod, Args, Options) -> do_spawn(GenMod, LinkP, Mod, Args, Options). diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl index 4ac44d9b1f..afb63c5b28 100644 --- a/lib/stdlib/src/gen_event.erl +++ b/lib/stdlib/src/gen_event.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -58,7 +58,7 @@ -export([format_log/1, format_log/2]). -export_type([handler/0, handler_args/0, add_handler_ret/0, - del_handler_ret/0]). + del_handler_ret/0, request_id/0]). -record(handler, {module :: atom(), id = false, @@ -147,7 +147,8 @@ | {'via', atom(), term()} | pid(). -type start_ret() :: {'ok', pid()} | {'error', term()}. -type start_mon_ret() :: {'ok', {pid(),reference()}} | {'error', term()}. --type request_id() :: term(). + +-opaque request_id() :: gen:request_id(). %%--------------------------------------------------------------------------- diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index 41de37f1cf..fcf62535c0 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -120,20 +120,23 @@ -include("logger.hrl"). +-export_type( + [from/0, + reply_tag/0, + request_id/0]). + +-export_type( + [server_name/0, + server_ref/0, + start_opt/0, + enter_loop_opt/0, + start_ret/0, + start_mon_ret/0]). + -define( STACKTRACE(), element(2, erlang:process_info(self(), current_stacktrace))). - --type server_ref() :: - pid() - | (LocalName :: atom()) - | {Name :: atom(), Node :: atom()} - | {'global', GlobalName :: term()} - | {'via', RegMod :: module(), ViaName :: term()}. - --type request_id() :: term(). - %%%========================================================================= %%% API %%%========================================================================= @@ -141,7 +144,7 @@ -callback init(Args :: term()) -> {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate | {continue, term()}} | {stop, Reason :: term()} | ignore. --callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, +-callback handle_call(Request :: term(), From :: from(), State :: term()) -> {reply, Reply :: term(), NewState :: term()} | {reply, Reply :: term(), NewState :: term(), timeout() | hibernate | {continue, term()}} | @@ -185,6 +188,13 @@ [handle_info/2, handle_continue/2, terminate/2, code_change/3, format_status/1, format_status/2]). + + +-type from() :: {Client :: pid(), Tag :: reply_tag()}. +-opaque reply_tag() :: gen:reply_tag(). + +-opaque request_id() :: gen:request_id(). + %%% ----------------------------------------------------------------- %%% Starts a generic server. %%% start(Mod, Args, Options) @@ -201,21 +211,100 @@ %%% {error, {already_started, Pid}} | %%% {error, Reason} %%% ----------------------------------------------------------------- + +-type server_name() :: % Duplicate of gen:emgr_name() + {'local', atom()} + | {'global', GlobalName :: term()} + | {'via', RegMod :: module(), Name :: term()}. + +-type server_ref() :: % What gen:call/3,4 and gen:stop/1,3 accepts + pid() + | (LocalName :: atom()) + | {Name :: atom(), Node :: atom()} + | {'global', GlobalName :: term()} + | {'via', RegMod :: module(), ViaName :: term()}. + +-type start_opt() :: % Duplicate of gen:option() + {'timeout', timeout()} + | {'spawn_opt', [proc_lib:spawn_option()]} + | enter_loop_opt(). +%% +-type enter_loop_opt() :: % Some gen:option()s works for enter_loop/* + {'hibernate_after', HibernateAfterTimeout :: timeout()} + | {'debug', Dbgs :: [sys:debug_option()]}. + +-type start_ret() :: % gen:start_ret() without monitor return + {'ok', pid()} + | 'ignore' + | {'error', term()}. + +-type start_mon_ret() :: % gen:start_ret() with only monitor return + {'ok', {pid(),reference()}} + | 'ignore' + | {'error', term()}. + +%%% --------------------------------------------------- + +-spec start( + Mod :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% start(Mod, Args, Options) -> gen:start(?MODULE, nolink, Mod, Args, Options). +-spec start( + Name :: server_name(), + Mod :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% start(Name, Mod, Args, Options) -> gen:start(?MODULE, nolink, Name, Mod, Args, Options). +-spec start_link( + Mod :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% start_link(Mod, Args, Options) -> gen:start(?MODULE, link, Mod, Args, Options). +-spec start_link( + Name :: server_name(), + Mod :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% start_link(Name, Mod, Args, Options) -> gen:start(?MODULE, link, Name, Mod, Args, Options). +-spec start_monitor( + Mod :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_mon_ret(). +%% start_monitor(Mod, Args, Options) -> gen:start(?MODULE, monitor, Mod, Args, Options). +-spec start_monitor( + Name :: server_name(), + Mod :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_mon_ret(). +%% start_monitor(Name, Mod, Args, Options) -> gen:start(?MODULE, monitor, Name, Mod, Args, Options). @@ -225,9 +314,20 @@ start_monitor(Name, Mod, Args, Options) -> %% If the server is located at another node, that node will %% be monitored. %% ----------------------------------------------------------------- + +-spec stop( + Name :: server_ref() + ) -> ok. +%% stop(Name) -> gen:stop(Name). +-spec stop( + Name :: server_ref(), + Reason :: term(), + Timeout :: timeout() + ) -> ok. +%% stop(Name, Reason, Timeout) -> gen:stop(Name, Reason, Timeout). @@ -238,6 +338,13 @@ stop(Name, Reason, Timeout) -> %% If the client is trapping exits and is linked server termination %% is handled here (? Shall we do that here (or rely on timeouts) ?). %% ----------------------------------------------------------------- + +-spec call( + Name :: server_ref(), + Request :: term() + ) -> + Reply :: term(). +%% call(Name, Request) -> case catch gen:call(Name, '$gen_call', Request) of {ok,Res} -> @@ -246,6 +353,13 @@ call(Name, Request) -> exit({Reason, {?MODULE, call, [Name, Request]}}) end. +-spec call( + Name :: server_ref(), + Request :: term(), + Timeout :: timeout() + ) -> + Reply :: term(). +%% call(Name, Request, Timeout) -> case catch gen:call(Name, '$gen_call', Request, Timeout) of {ok,Res} -> @@ -281,6 +395,13 @@ check_response(Msg, RequestId) -> %% ----------------------------------------------------------------- %% Make a cast to a generic server. %% ----------------------------------------------------------------- + +-spec cast( + Name :: server_ref(), + Request :: term() + ) -> + ok. +%% cast({global,Name}, Request) -> catch global:send(Name, cast_msg(Request)), ok; @@ -303,15 +424,36 @@ cast_msg(Request) -> {'$gen_cast',Request}. %% ----------------------------------------------------------------- %% Send a reply to the client. %% ----------------------------------------------------------------- + +-spec reply( + From :: from(), + Reply :: term() + ) -> + ok. +%% reply(From, Reply) -> gen:reply(From, Reply). %% ----------------------------------------------------------------- %% Asynchronous broadcast, returns nothing, it's just send 'n' pray %%----------------------------------------------------------------- + +-spec abcast( + Name :: server_ref(), + Request :: term() + ) -> + abcast. +%% abcast(Name, Request) when is_atom(Name) -> do_abcast([node() | nodes()], Name, cast_msg(Request)). +-spec abcast( + Nodes :: [node()], + Name :: server_ref(), + Request :: term() + ) -> + abcast. +%% abcast(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) -> do_abcast(Nodes, Name, cast_msg(Request)). @@ -330,14 +472,42 @@ do_abcast([], _,_) -> abcast. %%% queue, it would probably become confused. Late answers will %%% now arrive to the terminated middleman and so be discarded. %%% ----------------------------------------------------------------- + +-spec multi_call( + Name :: atom(), + Req :: term() + ) -> + {Replies :: [{node(), Reply :: term()}], + BadNodes :: [node()] + }. +%% multi_call(Name, Req) when is_atom(Name) -> do_multi_call([node() | nodes()], Name, Req, infinity). +-spec multi_call( + Nodes :: [node()], + Name :: atom(), + Req :: term() + ) -> + {Replies :: [{node(), Reply :: term()}], + BadNodes :: [node()] + }. +%% multi_call(Nodes, Name, Req) when is_list(Nodes), is_atom(Name) -> do_multi_call(Nodes, Name, Req, infinity). +-spec multi_call( + Nodes :: [node()], + Name :: atom(), + Req :: term(), + Timeout :: timeout() + ) -> + {Replies :: [{node(), Reply :: term()}], + BadNodes :: [node()] + }. +%% multi_call(Nodes, Name, Req, infinity) -> do_multi_call(Nodes, Name, Req, infinity); multi_call(Nodes, Name, Req, Timeout) @@ -356,19 +526,51 @@ multi_call(Nodes, Name, Req, Timeout) %% The user is responsible for any initialization of the %% process, including registering a name for it. %%----------------------------------------------------------------- + +-spec enter_loop( + Mod :: module(), + Options :: [enter_loop_opt()], + State :: term() + ) -> + no_return(). +%% enter_loop(Mod, Options, State) -> enter_loop(Mod, Options, State, self(), infinity). +-spec enter_loop( + Mod :: module(), + Options :: [enter_loop_opt()], + State :: term(), + ServerName :: server_name() + ) -> + no_return(); + ( + Mod :: module(), + Options :: [enter_loop_opt()], + State :: term(), + Timeout :: timeout() + ) -> + no_return(). +%% enter_loop(Mod, Options, State, ServerName = {Scope, _}) when Scope == local; Scope == global -> enter_loop(Mod, Options, State, ServerName, infinity); - +%% enter_loop(Mod, Options, State, ServerName = {via, _, _}) -> enter_loop(Mod, Options, State, ServerName, infinity); - +%% enter_loop(Mod, Options, State, Timeout) -> enter_loop(Mod, Options, State, self(), Timeout). +-spec enter_loop( + Mod :: module(), + Options :: [enter_loop_opt()], + State :: term(), + ServerName :: server_name() | pid(), + Timeout :: timeout() + ) -> + no_return(). +%% enter_loop(Mod, Options, State, ServerName, Timeout) -> Name = gen:get_proc_name(ServerName), Parent = gen:get_parent(), diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index 49d12db049..63b60e99e9 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -61,6 +61,7 @@ -export_type( [event_type/0, from/0, + reply_tag/0, callback_mode_result/0, init_result/1, init_result/2, @@ -70,7 +71,8 @@ event_handler_result/2, reply_action/0, enter_action/0, - action/0 + action/0, + request_id/0 ]). %% Old types, not advertised -export_type( @@ -85,15 +87,17 @@ [server_name/0, server_ref/0, start_opt/0, + enter_loop_opt/0, start_ret/0, - enter_loop_opt/0]). + start_mon_ret/0]). %%%========================================================================== %%% Interface functions. %%%========================================================================== -type from() :: - {To :: pid(), Tag :: term()}. % Reply-to specifier for call + {To :: pid(), Tag :: reply_tag()}. % Reply-to specifier for call +-opaque reply_tag() :: gen:reply_tag(). -type state() :: state_name() | % For StateName/3 callback functions @@ -278,7 +282,7 @@ Replies :: [reply_action()] | reply_action(), NewData :: DataType}. --type request_id() :: term(). +-opaque request_id() :: gen:request_id(). %% The state machine init function. It is called only once and %% the server is not running until this function has returned @@ -486,31 +490,37 @@ timeout_event_type(Type) -> %%%========================================================================== %%% API --type server_name() :: - {'global', GlobalName :: term()} - | {'via', RegMod :: module(), Name :: term()} - | {'local', atom()}. --type server_ref() :: +-type server_name() :: % Duplicate of gen:emgr_name() + {'local', atom()} + | {'global', GlobalName :: term()} + | {'via', RegMod :: module(), Name :: term()}. + +-type server_ref() :: % What gen:call/3,4 and gen:stop/1,3 accepts pid() | (LocalName :: atom()) | {Name :: atom(), Node :: atom()} | {'global', GlobalName :: term()} | {'via', RegMod :: module(), ViaName :: term()}. --type start_opt() :: + +-type start_opt() :: % Duplicate of gen:option() {'timeout', Time :: timeout()} - | {'spawn_opt', [proc_lib:start_spawn_option()]} + | {'spawn_opt', [proc_lib:spawn_option()]} | enter_loop_opt(). --type start_ret() :: +%% +-type enter_loop_opt() :: % Some gen:option()s works for enter_loop/* + {'hibernate_after', HibernateAfterTimeout :: timeout()} + | {'debug', Dbgs :: [sys:debug_option()]}. + +-type start_ret() :: % gen:start_ret() without monitor return {'ok', pid()} | 'ignore' | {'error', term()}. --type start_mon_ret() :: + +-type start_mon_ret() :: % gen:start_ret() with only monitor return {'ok', {pid(),reference()}} | 'ignore' | {'error', term()}. --type enter_loop_opt() :: - {'hibernate_after', HibernateAfterTimeout :: timeout()} - | {'debug', Dbgs :: [sys:debug_option()]}. + diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl index 4867f49313..a95d75b9f6 100644 --- a/lib/stdlib/src/proc_lib.erl +++ b/lib/stdlib/src/proc_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -46,13 +46,33 @@ %%----------------------------------------------------------------------------- +%% This shall be spawn_option() -- monitor options and must be kept in sync +%% (with erlang:spawn_opt_options()) +%% -type start_spawn_option() :: 'link' | {'priority', erlang:priority_level()} - | {'max_heap_size', erlang:max_heap_size()} + | {'fullsweep_after', non_neg_integer()} | {'min_heap_size', non_neg_integer()} | {'min_bin_vheap_size', non_neg_integer()} - | {'fullsweep_after', non_neg_integer()} + | {'max_heap_size', erlang:max_heap_size()} | {'message_queue_data', erlang:message_queue_data() }. +%% and this macro is used to verify that there are no monitor options +%% which also needs to be kept in sync all kinds of monitor options +%% in erlang:spawn_opt_options(). +%% +-define(VERIFY_NO_MONITOR_OPT(M, F, A, T, Opts), + Monitor = monitor, + case lists:member(Monitor, Opts) of + true -> + erlang:error(badarg, [M,F,A,T,Opts]); + false -> + case lists:keyfind(Monitor, 1, Opts) of + false -> + ok; + {Monitor, _} -> + erlang:error(badarg, [M,F,A,T,Opts]) + end + end). -type spawn_option() :: erlang:spawn_opt_option(). @@ -62,12 +82,6 @@ %%----------------------------------------------------------------------------- --define(VERIFY_NO_MONITOR_OPT(M, F, A, T, Opts), - case lists:member(monitor, Opts) of - true -> erlang:error(badarg, [M,F,A,T,Opts]); - false -> ok - end). - %%----------------------------------------------------------------------------- -spec spawn(Fun) -> pid() when -- 2.34.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor