1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(gen_server). 21 22%%% --------------------------------------------------- 23%%% 24%%% The idea behind THIS server is that the user module 25%%% provides (different) functions to handle different 26%%% kind of inputs. 27%%% If the Parent process terminates the Module:terminate/2 28%%% function is called. 29%%% 30%%% The user module should export: 31%%% 32%%% init(Args) 33%%% ==> {ok, State} 34%%% {ok, State, Timeout} 35%%% ignore 36%%% {stop, Reason} 37%%% 38%%% handle_call(Msg, {From, Tag}, State) 39%%% 40%%% ==> {reply, Reply, State} 41%%% {reply, Reply, State, Timeout} 42%%% {noreply, State} 43%%% {noreply, State, Timeout} 44%%% {stop, Reason, Reply, State} 45%%% Reason = normal | shutdown | Term terminate(State) is called 46%%% 47%%% handle_cast(Msg, State) 48%%% 49%%% ==> {noreply, State} 50%%% {noreply, State, Timeout} 51%%% {stop, Reason, State} 52%%% Reason = normal | shutdown | Term terminate(State) is called 53%%% 54%%% handle_info(Info, State) Info is e.g. {'EXIT', P, R}, {nodedown, N}, ... 55%%% 56%%% ==> {noreply, State} 57%%% {noreply, State, Timeout} 58%%% {stop, Reason, State} 59%%% Reason = normal | shutdown | Term, terminate(State) is called 60%%% 61%%% terminate(Reason, State) Let the user module clean up 62%%% always called when server terminates 63%%% 64%%% ==> ok 65%%% 66%%% 67%%% The work flow (of the server) can be described as follows: 68%%% 69%%% User module Generic 70%%% ----------- ------- 71%%% start -----> start 72%%% init <----- . 73%%% 74%%% loop 75%%% handle_call <----- . 76%%% -----> reply 77%%% 78%%% handle_cast <----- . 79%%% 80%%% handle_info <----- . 81%%% 82%%% terminate <----- . 83%%% 84%%% -----> reply 85%%% 86%%% 87%%% --------------------------------------------------- 88 89%% API 90-export([start/3, start/4, 91 start_link/3, start_link/4, 92 stop/1, stop/3, 93 call/2, call/3, 94 cast/2, reply/2, 95 abcast/2, abcast/3, 96 multi_call/2, multi_call/3, multi_call/4, 97 enter_loop/3, enter_loop/4, enter_loop/5, wake_hib/6]). 98 99%% System exports 100-export([system_continue/3, 101 system_terminate/4, 102 system_code_change/4, 103 system_get_state/1, 104 system_replace_state/2, 105 format_status/2]). 106 107%% logger callback 108-export([format_log/1]). 109 110%% Internal exports 111-export([init_it/6]). 112 113-include("logger.hrl"). 114 115-define( 116 STACKTRACE(), 117 element(2, erlang:process_info(self(), current_stacktrace))). 118 119%%%========================================================================= 120%%% API 121%%%========================================================================= 122 123-callback init(Args :: term()) -> 124 {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate | {continue, term()}} | 125 {stop, Reason :: term()} | ignore. 126-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, 127 State :: term()) -> 128 {reply, Reply :: term(), NewState :: term()} | 129 {reply, Reply :: term(), NewState :: term(), timeout() | hibernate | {continue, term()}} | 130 {noreply, NewState :: term()} | 131 {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | 132 {stop, Reason :: term(), Reply :: term(), NewState :: term()} | 133 {stop, Reason :: term(), NewState :: term()}. 134-callback handle_cast(Request :: term(), State :: term()) -> 135 {noreply, NewState :: term()} | 136 {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | 137 {stop, Reason :: term(), NewState :: term()}. 138-callback handle_info(Info :: timeout | term(), State :: term()) -> 139 {noreply, NewState :: term()} | 140 {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | 141 {stop, Reason :: term(), NewState :: term()}. 142-callback handle_continue(Info :: term(), State :: term()) -> 143 {noreply, NewState :: term()} | 144 {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | 145 {stop, Reason :: term(), NewState :: term()}. 146-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | 147 term()), 148 State :: term()) -> 149 term(). 150-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), 151 Extra :: term()) -> 152 {ok, NewState :: term()} | {error, Reason :: term()}. 153-callback format_status(Opt, StatusData) -> Status when 154 Opt :: 'normal' | 'terminate', 155 StatusData :: [PDict | State], 156 PDict :: [{Key :: term(), Value :: term()}], 157 State :: term(), 158 Status :: term(). 159 160-optional_callbacks( 161 [handle_info/2, handle_continue/2, terminate/2, code_change/3, format_status/2]). 162 163%%% ----------------------------------------------------------------- 164%%% Starts a generic server. 165%%% start(Mod, Args, Options) 166%%% start(Name, Mod, Args, Options) 167%%% start_link(Mod, Args, Options) 168%%% start_link(Name, Mod, Args, Options) where: 169%%% Name ::= {local, atom()} | {global, term()} | {via, atom(), term()} 170%%% Mod ::= atom(), callback module implementing the 'real' server 171%%% Args ::= term(), init arguments (to Mod:init/1) 172%%% Options ::= [{timeout, Timeout} | {debug, [Flag]}] 173%%% Flag ::= trace | log | {logfile, File} | statistics | debug 174%%% (debug == log && statistics) 175%%% Returns: {ok, Pid} | 176%%% {error, {already_started, Pid}} | 177%%% {error, Reason} 178%%% ----------------------------------------------------------------- 179start(Mod, Args, Options) -> 180 gen:start(?MODULE, nolink, Mod, Args, Options). 181 182start(Name, Mod, Args, Options) -> 183 gen:start(?MODULE, nolink, Name, Mod, Args, Options). 184 185start_link(Mod, Args, Options) -> 186 gen:start(?MODULE, link, Mod, Args, Options). 187 188start_link(Name, Mod, Args, Options) -> 189 gen:start(?MODULE, link, Name, Mod, Args, Options). 190 191 192%% ----------------------------------------------------------------- 193%% Stop a generic server and wait for it to terminate. 194%% If the server is located at another node, that node will 195%% be monitored. 196%% ----------------------------------------------------------------- 197stop(Name) -> 198 gen:stop(Name). 199 200stop(Name, Reason, Timeout) -> 201 gen:stop(Name, Reason, Timeout). 202 203%% ----------------------------------------------------------------- 204%% Make a call to a generic server. 205%% If the server is located at another node, that node will 206%% be monitored. 207%% If the client is trapping exits and is linked server termination 208%% is handled here (? Shall we do that here (or rely on timeouts) ?). 209%% ----------------------------------------------------------------- 210call(Name, Request) -> 211 case catch gen:call(Name, '$gen_call', Request) of 212 {ok,Res} -> 213 Res; 214 {'EXIT',Reason} -> 215 exit({Reason, {?MODULE, call, [Name, Request]}}) 216 end. 217 218call(Name, Request, Timeout) -> 219 case catch gen:call(Name, '$gen_call', Request, Timeout) of 220 {ok,Res} -> 221 Res; 222 {'EXIT',Reason} -> 223 exit({Reason, {?MODULE, call, [Name, Request, Timeout]}}) 224 end. 225 226%% ----------------------------------------------------------------- 227%% Make a cast to a generic server. 228%% ----------------------------------------------------------------- 229cast({global,Name}, Request) -> 230 catch global:send(Name, cast_msg(Request)), 231 ok; 232cast({via, Mod, Name}, Request) -> 233 catch Mod:send(Name, cast_msg(Request)), 234 ok; 235cast({Name,Node}=Dest, Request) when is_atom(Name), is_atom(Node) -> 236 do_cast(Dest, Request); 237cast(Dest, Request) when is_atom(Dest) -> 238 do_cast(Dest, Request); 239cast(Dest, Request) when is_pid(Dest) -> 240 do_cast(Dest, Request). 241 242do_cast(Dest, Request) -> 243 do_send(Dest, cast_msg(Request)), 244 ok. 245 246cast_msg(Request) -> {'$gen_cast',Request}. 247 248%% ----------------------------------------------------------------- 249%% Send a reply to the client. 250%% ----------------------------------------------------------------- 251reply({To, Tag}, Reply) -> 252 catch To ! {Tag, Reply}. 253 254%% ----------------------------------------------------------------- 255%% Asynchronous broadcast, returns nothing, it's just send 'n' pray 256%%----------------------------------------------------------------- 257abcast(Name, Request) when is_atom(Name) -> 258 do_abcast([node() | nodes()], Name, cast_msg(Request)). 259 260abcast(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) -> 261 do_abcast(Nodes, Name, cast_msg(Request)). 262 263do_abcast([Node|Nodes], Name, Msg) when is_atom(Node) -> 264 do_send({Name,Node},Msg), 265 do_abcast(Nodes, Name, Msg); 266do_abcast([], _,_) -> abcast. 267 268%%% ----------------------------------------------------------------- 269%%% Make a call to servers at several nodes. 270%%% Returns: {[Replies],[BadNodes]} 271%%% A Timeout can be given 272%%% 273%%% A middleman process is used in case late answers arrives after 274%%% the timeout. If they would be allowed to glog the callers message 275%%% queue, it would probably become confused. Late answers will 276%%% now arrive to the terminated middleman and so be discarded. 277%%% ----------------------------------------------------------------- 278multi_call(Name, Req) 279 when is_atom(Name) -> 280 do_multi_call([node() | nodes()], Name, Req, infinity). 281 282multi_call(Nodes, Name, Req) 283 when is_list(Nodes), is_atom(Name) -> 284 do_multi_call(Nodes, Name, Req, infinity). 285 286multi_call(Nodes, Name, Req, infinity) -> 287 do_multi_call(Nodes, Name, Req, infinity); 288multi_call(Nodes, Name, Req, Timeout) 289 when is_list(Nodes), is_atom(Name), is_integer(Timeout), Timeout >= 0 -> 290 do_multi_call(Nodes, Name, Req, Timeout). 291 292 293%%----------------------------------------------------------------- 294%% enter_loop(Mod, Options, State, <ServerName>, <TimeOut>) ->_ 295%% 296%% Description: Makes an existing process into a gen_server. 297%% The calling process will enter the gen_server receive 298%% loop and become a gen_server process. 299%% The process *must* have been started using one of the 300%% start functions in proc_lib, see proc_lib(3). 301%% The user is responsible for any initialization of the 302%% process, including registering a name for it. 303%%----------------------------------------------------------------- 304enter_loop(Mod, Options, State) -> 305 enter_loop(Mod, Options, State, self(), infinity). 306 307enter_loop(Mod, Options, State, ServerName = {Scope, _}) 308 when Scope == local; Scope == global -> 309 enter_loop(Mod, Options, State, ServerName, infinity); 310 311enter_loop(Mod, Options, State, ServerName = {via, _, _}) -> 312 enter_loop(Mod, Options, State, ServerName, infinity); 313 314enter_loop(Mod, Options, State, Timeout) -> 315 enter_loop(Mod, Options, State, self(), Timeout). 316 317enter_loop(Mod, Options, State, ServerName, Timeout) -> 318 Name = gen:get_proc_name(ServerName), 319 Parent = gen:get_parent(), 320 Debug = gen:debug_options(Name, Options), 321 HibernateAfterTimeout = gen:hibernate_after(Options), 322 loop(Parent, Name, State, Mod, Timeout, HibernateAfterTimeout, Debug). 323 324%%%======================================================================== 325%%% Gen-callback functions 326%%%======================================================================== 327 328%%% --------------------------------------------------- 329%%% Initiate the new process. 330%%% Register the name using the Rfunc function 331%%% Calls the Mod:init/Args function. 332%%% Finally an acknowledge is sent to Parent and the main 333%%% loop is entered. 334%%% --------------------------------------------------- 335init_it(Starter, self, Name, Mod, Args, Options) -> 336 init_it(Starter, self(), Name, Mod, Args, Options); 337init_it(Starter, Parent, Name0, Mod, Args, Options) -> 338 Name = gen:name(Name0), 339 Debug = gen:debug_options(Name, Options), 340 HibernateAfterTimeout = gen:hibernate_after(Options), 341 342 case init_it(Mod, Args) of 343 {ok, {ok, State}} -> 344 proc_lib:init_ack(Starter, {ok, self()}), 345 loop(Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug); 346 {ok, {ok, State, Timeout}} -> 347 proc_lib:init_ack(Starter, {ok, self()}), 348 loop(Parent, Name, State, Mod, Timeout, HibernateAfterTimeout, Debug); 349 {ok, {stop, Reason}} -> 350 %% For consistency, we must make sure that the 351 %% registered name (if any) is unregistered before 352 %% the parent process is notified about the failure. 353 %% (Otherwise, the parent process could get 354 %% an 'already_started' error if it immediately 355 %% tried starting the process again.) 356 gen:unregister_name(Name0), 357 proc_lib:init_ack(Starter, {error, Reason}), 358 exit(Reason); 359 {ok, ignore} -> 360 gen:unregister_name(Name0), 361 proc_lib:init_ack(Starter, ignore), 362 exit(normal); 363 {ok, Else} -> 364 Error = {bad_return_value, Else}, 365 proc_lib:init_ack(Starter, {error, Error}), 366 exit(Error); 367 {'EXIT', Class, Reason, Stacktrace} -> 368 gen:unregister_name(Name0), 369 proc_lib:init_ack(Starter, {error, terminate_reason(Class, Reason, Stacktrace)}), 370 erlang:raise(Class, Reason, Stacktrace) 371 end. 372init_it(Mod, Args) -> 373 try 374 {ok, Mod:init(Args)} 375 catch 376 throw:R -> {ok, R}; 377 Class:R:S -> {'EXIT', Class, R, S} 378 end. 379 380%%%======================================================================== 381%%% Internal functions 382%%%======================================================================== 383%%% --------------------------------------------------- 384%%% The MAIN loop. 385%%% --------------------------------------------------- 386 387loop(Parent, Name, State, Mod, {continue, Continue} = Msg, HibernateAfterTimeout, Debug) -> 388 Reply = try_dispatch(Mod, handle_continue, Continue, State), 389 case Debug of 390 [] -> 391 handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, 392 HibernateAfterTimeout, State); 393 _ -> 394 Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, Msg), 395 handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, 396 HibernateAfterTimeout, State, Debug1) 397 end; 398 399loop(Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug) -> 400 proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, HibernateAfterTimeout, Debug]); 401 402loop(Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug) -> 403 receive 404 Msg -> 405 decode_msg(Msg, Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug, false) 406 after HibernateAfterTimeout -> 407 loop(Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug) 408 end; 409 410loop(Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug) -> 411 Msg = receive 412 Input -> 413 Input 414 after Time -> 415 timeout 416 end, 417 decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, false). 418 419wake_hib(Parent, Name, State, Mod, HibernateAfterTimeout, Debug) -> 420 Msg = receive 421 Input -> 422 Input 423 end, 424 decode_msg(Msg, Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug, true). 425 426decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, Hib) -> 427 case Msg of 428 {system, From, Req} -> 429 sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, 430 [Name, State, Mod, Time, HibernateAfterTimeout], Hib); 431 {'EXIT', Parent, Reason} -> 432 terminate(Reason, ?STACKTRACE(), Name, undefined, Msg, Mod, State, Debug); 433 _Msg when Debug =:= [] -> 434 handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout); 435 _Msg -> 436 Debug1 = sys:handle_debug(Debug, fun print_event/3, 437 Name, {in, Msg}), 438 handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout, Debug1) 439 end. 440 441%%% --------------------------------------------------- 442%%% Send/receive functions 443%%% --------------------------------------------------- 444do_send(Dest, Msg) -> 445 try erlang:send(Dest, Msg) 446 catch 447 error:_ -> ok 448 end, 449 ok. 450 451do_multi_call(Nodes, Name, Req, infinity) -> 452 Tag = make_ref(), 453 Monitors = send_nodes(Nodes, Name, Tag, Req), 454 rec_nodes(Tag, Monitors, Name, undefined); 455do_multi_call(Nodes, Name, Req, Timeout) -> 456 Tag = make_ref(), 457 Caller = self(), 458 Receiver = 459 spawn( 460 fun() -> 461 %% Middleman process. Should be unsensitive to regular 462 %% exit signals. The sychronization is needed in case 463 %% the receiver would exit before the caller started 464 %% the monitor. 465 process_flag(trap_exit, true), 466 Mref = erlang:monitor(process, Caller), 467 receive 468 {Caller,Tag} -> 469 Monitors = send_nodes(Nodes, Name, Tag, Req), 470 TimerId = erlang:start_timer(Timeout, self(), ok), 471 Result = rec_nodes(Tag, Monitors, Name, TimerId), 472 exit({self(),Tag,Result}); 473 {'DOWN',Mref,_,_,_} -> 474 %% Caller died before sending us the go-ahead. 475 %% Give up silently. 476 exit(normal) 477 end 478 end), 479 Mref = erlang:monitor(process, Receiver), 480 Receiver ! {self(),Tag}, 481 receive 482 {'DOWN',Mref,_,_,{Receiver,Tag,Result}} -> 483 Result; 484 {'DOWN',Mref,_,_,Reason} -> 485 %% The middleman code failed. Or someone did 486 %% exit(_, kill) on the middleman process => Reason==killed 487 exit(Reason) 488 end. 489 490send_nodes(Nodes, Name, Tag, Req) -> 491 send_nodes(Nodes, Name, Tag, Req, []). 492 493send_nodes([Node|Tail], Name, Tag, Req, Monitors) 494 when is_atom(Node) -> 495 Monitor = start_monitor(Node, Name), 496 %% Handle non-existing names in rec_nodes. 497 catch {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Req}, 498 send_nodes(Tail, Name, Tag, Req, [Monitor | Monitors]); 499send_nodes([_Node|Tail], Name, Tag, Req, Monitors) -> 500 %% Skip non-atom Node 501 send_nodes(Tail, Name, Tag, Req, Monitors); 502send_nodes([], _Name, _Tag, _Req, Monitors) -> 503 Monitors. 504 505%% Against old nodes: 506%% If no reply has been delivered within 2 secs. (per node) check that 507%% the server really exists and wait for ever for the answer. 508%% 509%% Against contemporary nodes: 510%% Wait for reply, server 'DOWN', or timeout from TimerId. 511 512rec_nodes(Tag, Nodes, Name, TimerId) -> 513 rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId). 514 515rec_nodes(Tag, [{N,R}|Tail], Name, Badnodes, Replies, Time, TimerId ) -> 516 receive 517 {'DOWN', R, _, _, _} -> 518 rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, Time, TimerId); 519 {{Tag, N}, Reply} -> %% Tag is bound !!! 520 erlang:demonitor(R, [flush]), 521 rec_nodes(Tag, Tail, Name, Badnodes, 522 [{N,Reply}|Replies], Time, TimerId); 523 {timeout, TimerId, _} -> 524 erlang:demonitor(R, [flush]), 525 %% Collect all replies that already have arrived 526 rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies) 527 end; 528rec_nodes(Tag, [N|Tail], Name, Badnodes, Replies, Time, TimerId) -> 529 %% R6 node 530 receive 531 {nodedown, N} -> 532 monitor_node(N, false), 533 rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, 2000, TimerId); 534 {{Tag, N}, Reply} -> %% Tag is bound !!! 535 receive {nodedown, N} -> ok after 0 -> ok end, 536 monitor_node(N, false), 537 rec_nodes(Tag, Tail, Name, Badnodes, 538 [{N,Reply}|Replies], 2000, TimerId); 539 {timeout, TimerId, _} -> 540 receive {nodedown, N} -> ok after 0 -> ok end, 541 monitor_node(N, false), 542 %% Collect all replies that already have arrived 543 rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) 544 after Time -> 545 case rpc:call(N, erlang, whereis, [Name]) of 546 Pid when is_pid(Pid) -> % It exists try again. 547 rec_nodes(Tag, [N|Tail], Name, Badnodes, 548 Replies, infinity, TimerId); 549 _ -> % badnode 550 receive {nodedown, N} -> ok after 0 -> ok end, 551 monitor_node(N, false), 552 rec_nodes(Tag, Tail, Name, [N|Badnodes], 553 Replies, 2000, TimerId) 554 end 555 end; 556rec_nodes(_, [], _, Badnodes, Replies, _, TimerId) -> 557 case catch erlang:cancel_timer(TimerId) of 558 false -> % It has already sent it's message 559 receive 560 {timeout, TimerId, _} -> ok 561 after 0 -> 562 ok 563 end; 564 _ -> % Timer was cancelled, or TimerId was 'undefined' 565 ok 566 end, 567 {Replies, Badnodes}. 568 569%% Collect all replies that already have arrived 570rec_nodes_rest(Tag, [{N,R}|Tail], Name, Badnodes, Replies) -> 571 receive 572 {'DOWN', R, _, _, _} -> 573 rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies); 574 {{Tag, N}, Reply} -> %% Tag is bound !!! 575 erlang:demonitor(R, [flush]), 576 rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies]) 577 after 0 -> 578 erlang:demonitor(R, [flush]), 579 rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies) 580 end; 581rec_nodes_rest(Tag, [N|Tail], Name, Badnodes, Replies) -> 582 %% R6 node 583 receive 584 {nodedown, N} -> 585 monitor_node(N, false), 586 rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies); 587 {{Tag, N}, Reply} -> %% Tag is bound !!! 588 receive {nodedown, N} -> ok after 0 -> ok end, 589 monitor_node(N, false), 590 rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies]) 591 after 0 -> 592 receive {nodedown, N} -> ok after 0 -> ok end, 593 monitor_node(N, false), 594 rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies) 595 end; 596rec_nodes_rest(_Tag, [], _Name, Badnodes, Replies) -> 597 {Replies, Badnodes}. 598 599 600%%% --------------------------------------------------- 601%%% Monitor functions 602%%% --------------------------------------------------- 603 604start_monitor(Node, Name) when is_atom(Node), is_atom(Name) -> 605 if node() =:= nonode@nohost, Node =/= nonode@nohost -> 606 Ref = make_ref(), 607 self() ! {'DOWN', Ref, process, {Name, Node}, noconnection}, 608 {Node, Ref}; 609 true -> 610 case catch erlang:monitor(process, {Name, Node}) of 611 {'EXIT', _} -> 612 %% Remote node is R6 613 monitor_node(Node, true), 614 Node; 615 Ref when is_reference(Ref) -> 616 {Node, Ref} 617 end 618 end. 619 620%% --------------------------------------------------- 621%% Helper functions for try-catch of callbacks. 622%% Returns the return value of the callback, or 623%% {'EXIT', Class, Reason, Stack} (if an exception occurs) 624%% 625%% The Class, Reason and Stack are given to erlang:raise/3 626%% to make sure proc_lib receives the proper reasons and 627%% stacktraces. 628%% --------------------------------------------------- 629 630try_dispatch({'$gen_cast', Msg}, Mod, State) -> 631 try_dispatch(Mod, handle_cast, Msg, State); 632try_dispatch(Info, Mod, State) -> 633 try_dispatch(Mod, handle_info, Info, State). 634 635try_dispatch(Mod, Func, Msg, State) -> 636 try 637 {ok, Mod:Func(Msg, State)} 638 catch 639 throw:R -> 640 {ok, R}; 641 error:undef = R:Stacktrace when Func == handle_info -> 642 case erlang:function_exported(Mod, handle_info, 2) of 643 false -> 644 ?LOG_WARNING( 645 #{label=>{gen_server,no_handle_info}, 646 module=>Mod, 647 message=>Msg}, 648 #{domain=>[otp], 649 report_cb=>fun gen_server:format_log/1, 650 error_logger=>#{tag=>warning_msg}}), 651 {ok, {noreply, State}}; 652 true -> 653 {'EXIT', error, R, Stacktrace} 654 end; 655 Class:R:Stacktrace -> 656 {'EXIT', Class, R, Stacktrace} 657 end. 658 659try_handle_call(Mod, Msg, From, State) -> 660 try 661 {ok, Mod:handle_call(Msg, From, State)} 662 catch 663 throw:R -> 664 {ok, R}; 665 Class:R:Stacktrace -> 666 {'EXIT', Class, R, Stacktrace} 667 end. 668 669try_terminate(Mod, Reason, State) -> 670 case erlang:function_exported(Mod, terminate, 2) of 671 true -> 672 try 673 {ok, Mod:terminate(Reason, State)} 674 catch 675 throw:R -> 676 {ok, R}; 677 Class:R:Stacktrace -> 678 {'EXIT', Class, R, Stacktrace} 679 end; 680 false -> 681 {ok, ok} 682 end. 683 684 685%%% --------------------------------------------------- 686%%% Message handling functions 687%%% --------------------------------------------------- 688 689handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, HibernateAfterTimeout) -> 690 Result = try_handle_call(Mod, Msg, From, State), 691 case Result of 692 {ok, {reply, Reply, NState}} -> 693 reply(From, Reply), 694 loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, []); 695 {ok, {reply, Reply, NState, Time1}} -> 696 reply(From, Reply), 697 loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, []); 698 {ok, {noreply, NState}} -> 699 loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, []); 700 {ok, {noreply, NState, Time1}} -> 701 loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, []); 702 {ok, {stop, Reason, Reply, NState}} -> 703 try 704 terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, []) 705 after 706 reply(From, Reply) 707 end; 708 Other -> handle_common_reply(Other, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State) 709 end; 710handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout) -> 711 Reply = try_dispatch(Msg, Mod, State), 712 handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, HibernateAfterTimeout, State). 713 714handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, HibernateAfterTimeout, Debug) -> 715 Result = try_handle_call(Mod, Msg, From, State), 716 case Result of 717 {ok, {reply, Reply, NState}} -> 718 Debug1 = reply(Name, From, Reply, NState, Debug), 719 loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, Debug1); 720 {ok, {reply, Reply, NState, Time1}} -> 721 Debug1 = reply(Name, From, Reply, NState, Debug), 722 loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, Debug1); 723 {ok, {noreply, NState}} -> 724 Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, 725 {noreply, NState}), 726 loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, Debug1); 727 {ok, {noreply, NState, Time1}} -> 728 Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, 729 {noreply, NState}), 730 loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, Debug1); 731 {ok, {stop, Reason, Reply, NState}} -> 732 try 733 terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, Debug) 734 after 735 _ = reply(Name, From, Reply, NState, Debug) 736 end; 737 Other -> 738 handle_common_reply(Other, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State, Debug) 739 end; 740handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout, Debug) -> 741 Reply = try_dispatch(Msg, Mod, State), 742 handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, HibernateAfterTimeout, State, Debug). 743 744handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State) -> 745 case Reply of 746 {ok, {noreply, NState}} -> 747 loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, []); 748 {ok, {noreply, NState, Time1}} -> 749 loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, []); 750 {ok, {stop, Reason, NState}} -> 751 terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, []); 752 {'EXIT', Class, Reason, Stacktrace} -> 753 terminate(Class, Reason, Stacktrace, Name, From, Msg, Mod, State, []); 754 {ok, BadReply} -> 755 terminate({bad_return_value, BadReply}, ?STACKTRACE(), Name, From, Msg, Mod, State, []) 756 end. 757 758handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State, Debug) -> 759 case Reply of 760 {ok, {noreply, NState}} -> 761 Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, 762 {noreply, NState}), 763 loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, Debug1); 764 {ok, {noreply, NState, Time1}} -> 765 Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, 766 {noreply, NState}), 767 loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, Debug1); 768 {ok, {stop, Reason, NState}} -> 769 terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, Debug); 770 {'EXIT', Class, Reason, Stacktrace} -> 771 terminate(Class, Reason, Stacktrace, Name, From, Msg, Mod, State, Debug); 772 {ok, BadReply} -> 773 terminate({bad_return_value, BadReply}, ?STACKTRACE(), Name, From, Msg, Mod, State, Debug) 774 end. 775 776reply(Name, From, Reply, State, Debug) -> 777 reply(From, Reply), 778 sys:handle_debug(Debug, fun print_event/3, Name, 779 {out, Reply, From, State} ). 780 781 782%%----------------------------------------------------------------- 783%% Callback functions for system messages handling. 784%%----------------------------------------------------------------- 785system_continue(Parent, Debug, [Name, State, Mod, Time, HibernateAfterTimeout]) -> 786 loop(Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug). 787 788-spec system_terminate(_, _, _, [_]) -> no_return(). 789 790system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time, _HibernateAfterTimeout]) -> 791 terminate(Reason, ?STACKTRACE(), Name, undefined, [], Mod, State, Debug). 792 793system_code_change([Name, State, Mod, Time, HibernateAfterTimeout], _Module, OldVsn, Extra) -> 794 case catch Mod:code_change(OldVsn, State, Extra) of 795 {ok, NewState} -> {ok, [Name, NewState, Mod, Time, HibernateAfterTimeout]}; 796 Else -> Else 797 end. 798 799system_get_state([_Name, State, _Mod, _Time, _HibernateAfterTimeout]) -> 800 {ok, State}. 801 802system_replace_state(StateFun, [Name, State, Mod, Time, HibernateAfterTimeout]) -> 803 NState = StateFun(State), 804 {ok, NState, [Name, NState, Mod, Time, HibernateAfterTimeout]}. 805 806%%----------------------------------------------------------------- 807%% Format debug messages. Print them as the call-back module sees 808%% them, not as the real erlang messages. Use trace for that. 809%%----------------------------------------------------------------- 810print_event(Dev, {in, Msg}, Name) -> 811 case Msg of 812 {'$gen_call', {From, _Tag}, Call} -> 813 io:format(Dev, "*DBG* ~tp got call ~tp from ~tw~n", 814 [Name, Call, From]); 815 {'$gen_cast', Cast} -> 816 io:format(Dev, "*DBG* ~tp got cast ~tp~n", 817 [Name, Cast]); 818 _ -> 819 io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) 820 end; 821print_event(Dev, {out, Msg, {To,_Tag}, State}, Name) -> 822 io:format(Dev, "*DBG* ~tp sent ~tp to ~tw, new state ~tp~n", 823 [Name, Msg, To, State]); 824print_event(Dev, {noreply, State}, Name) -> 825 io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]); 826print_event(Dev, Event, Name) -> 827 io:format(Dev, "*DBG* ~tp dbg ~tp~n", [Name, Event]). 828 829 830%%% --------------------------------------------------- 831%%% Terminate the server. 832%%% 833%%% terminate/8 is triggered by {stop, Reason} or bad 834%%% return values. The stacktrace is generated via the 835%%% ?STACKTRACE() macro and the ReportReason must not 836%%% be wrapped in tuples. 837%%% 838%%% terminate/9 is triggered in case of error/exit in 839%%% the user callback. In this case the report reason 840%%% always includes the user stacktrace. 841%%% 842%%% The reason received in the terminate/2 callbacks 843%%% always includes the stacktrace for errors and never 844%%% for exits. 845%%% --------------------------------------------------- 846 847-spec terminate(_, _, _, _, _, _, _, _) -> no_return(). 848terminate(Reason, Stacktrace, Name, From, Msg, Mod, State, Debug) -> 849 terminate(exit, Reason, Stacktrace, Reason, Name, From, Msg, Mod, State, Debug). 850 851-spec terminate(_, _, _, _, _, _, _, _, _) -> no_return(). 852terminate(Class, Reason, Stacktrace, Name, From, Msg, Mod, State, Debug) -> 853 ReportReason = {Reason, Stacktrace}, 854 terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State, Debug). 855 856-spec terminate(_, _, _, _, _, _, _, _, _, _) -> no_return(). 857terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State, Debug) -> 858 Reply = try_terminate(Mod, terminate_reason(Class, Reason, Stacktrace), State), 859 case Reply of 860 {'EXIT', C, R, S} -> 861 error_info({R, S}, Name, From, Msg, Mod, State, Debug), 862 erlang:raise(C, R, S); 863 _ -> 864 case {Class, Reason} of 865 {exit, normal} -> ok; 866 {exit, shutdown} -> ok; 867 {exit, {shutdown,_}} -> ok; 868 _ -> 869 error_info(ReportReason, Name, From, Msg, Mod, State, Debug) 870 end 871 end, 872 case Stacktrace of 873 [] -> 874 erlang:Class(Reason); 875 _ -> 876 erlang:raise(Class, Reason, Stacktrace) 877 end. 878 879terminate_reason(error, Reason, Stacktrace) -> {Reason, Stacktrace}; 880terminate_reason(exit, Reason, _Stacktrace) -> Reason. 881 882error_info(_Reason, application_controller, _From, _Msg, _Mod, _State, _Debug) -> 883 %% OTP-5811 Don't send an error report if it's the system process 884 %% application_controller which is terminating - let init take care 885 %% of it instead 886 ok; 887error_info(Reason, Name, From, Msg, Mod, State, Debug) -> 888 Log = sys:get_log(Debug), 889 ?LOG_ERROR(#{label=>{gen_server,terminate}, 890 name=>Name, 891 last_message=>Msg, 892 state=>format_status(terminate, Mod, get(), State), 893 log=>format_log_state(Mod, Log), 894 reason=>Reason, 895 client_info=>client_stacktrace(From)}, 896 #{domain=>[otp], 897 report_cb=>fun gen_server:format_log/1, 898 error_logger=>#{tag=>error}}), 899 ok. 900 901client_stacktrace(undefined) -> 902 undefined; 903client_stacktrace({From,_Tag}) -> 904 client_stacktrace(From); 905client_stacktrace(From) when is_pid(From), node(From) =:= node() -> 906 case process_info(From, [current_stacktrace, registered_name]) of 907 undefined -> 908 {From,dead}; 909 [{current_stacktrace, Stacktrace}, {registered_name, []}] -> 910 {From,{From,Stacktrace}}; 911 [{current_stacktrace, Stacktrace}, {registered_name, Name}] -> 912 {From,{Name,Stacktrace}} 913 end; 914client_stacktrace(From) when is_pid(From) -> 915 {From,remote}. 916 917format_log(#{label:={gen_server,terminate}, 918 name:=Name, 919 last_message:=Msg, 920 state:=State, 921 log:=Log, 922 reason:=Reason, 923 client_info:=Client}) -> 924 Reason1 = 925 case Reason of 926 {undef,[{M,F,A,L}|MFAs]} -> 927 case code:is_loaded(M) of 928 false -> 929 {'module could not be loaded',[{M,F,A,L}|MFAs]}; 930 _ -> 931 case erlang:function_exported(M, F, length(A)) of 932 true -> 933 Reason; 934 false -> 935 {'function not exported',[{M,F,A,L}|MFAs]} 936 end 937 end; 938 _ -> 939 Reason 940 end, 941 {ClientFmt,ClientArgs} = format_client_log(Client), 942 [LimitedMsg,LimitedState,LimitedReason|LimitedLog] = 943 [error_logger:limit_term(D) || D <- [Msg,State,Reason1|Log]], 944 {"** Generic server ~tp terminating \n" 945 "** Last message in was ~tp~n" 946 "** When Server state == ~tp~n" 947 "** Reason for termination ==~n** ~tp~n" ++ 948 case LimitedLog of 949 [] -> []; 950 _ -> "** Log ==~n** ~tp~n" 951 end ++ ClientFmt, 952 [Name, LimitedMsg, LimitedState, LimitedReason] ++ 953 case LimitedLog of 954 [] -> []; 955 _ -> [LimitedLog] 956 end ++ ClientArgs}; 957format_log(#{label:={gen_server,no_handle_info}, 958 module:=Mod, 959 message:=Msg}) -> 960 {"** Undefined handle_info in ~p~n" 961 "** Unhandled message: ~tp~n", 962 [Mod, error_logger:limit_term(Msg)]}. 963 964format_client_log(undefined) -> 965 {"", []}; 966format_client_log({From,dead}) -> 967 {"** Client ~p is dead~n", [From]}; 968format_client_log({From,remote}) -> 969 {"** Client ~p is remote on node ~p~n", [From, node(From)]}; 970format_client_log({_From,{Name,Stacktrace}}) -> 971 {"** Client ~tp stacktrace~n" 972 "** ~tp~n", 973 [Name, error_logger:limit_term(Stacktrace)]}. 974 975%%----------------------------------------------------------------- 976%% Status information 977%%----------------------------------------------------------------- 978format_status(Opt, StatusData) -> 979 [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time, _HibernateAfterTimeout]] = StatusData, 980 Header = gen:format_status_header("Status for generic server", Name), 981 Log = sys:get_log(Debug), 982 Specific = case format_status(Opt, Mod, PDict, State) of 983 S when is_list(S) -> S; 984 S -> [S] 985 end, 986 [{header, Header}, 987 {data, [{"Status", SysState}, 988 {"Parent", Parent}, 989 {"Logged events", format_log_state(Mod, Log)}]} | 990 Specific]. 991 992format_log_state(Mod, Log) -> 993 [case Event of 994 {out,Msg,From,State} -> 995 {out,Msg,From,format_status(terminate, Mod, get(), State)}; 996 {noreply,State} -> 997 {noreply,format_status(terminate, Mod, get(), State)}; 998 _ -> Event 999 end || Event <- Log]. 1000 1001format_status(Opt, Mod, PDict, State) -> 1002 DefStatus = case Opt of 1003 terminate -> State; 1004 _ -> [{data, [{"State", State}]}] 1005 end, 1006 case erlang:function_exported(Mod, format_status, 2) of 1007 true -> 1008 case catch Mod:format_status(Opt, [PDict, State]) of 1009 {'EXIT', _} -> DefStatus; 1010 Else -> Else 1011 end; 1012 _ -> 1013 DefStatus 1014 end. 1015