Skip to content

Instantly share code, notes, and snippets.

@mietek
Created October 1, 2010 11:00
Show Gist options
  • Save mietek/606057 to your computer and use it in GitHub Desktop.
Save mietek/606057 to your computer and use it in GitHub Desktop.
-module(code_change_test).
% How to use:
%
% 1. Compile with first st record definition uncommented
%
% 2. Start several processes:
% 1> {ok, Pid1} = code_change_test:start().
% init
% {ok,<0.34.0>}
% 2> {ok, Pid2} = code_change_test:start().
% init
% {ok,<0.36.0>}
%
% 3. Compile with second st record definition uncommented
% Do not use c() as it also purges and loads the code
%
% 4. Simulate time-consuming processing:
% 3> Pid1 ! {sleep, 10000}
%
% 5. Change all processes:
% 4> code_change_test:change_all([Pid1, Pid2], code_change_test, add_b, "b", 15000).
% code_change {add_b,{st,"a"},"b"}
% added b! {st,"a","b"}
% code_change {add_b,{st,"a"},"b"}
% added b! {st,"a","b"}
% false
%
% 6. Verify the change took place:
% 5> Pid1 ! hello.
% handle_info {hello,{st,"a","b"}}
% hello
% 6> Pid2 ! hello.
% handle_info {hello,{st,"a","b"}}
% hello
-export([change_all/5]).
-export([start/0]).
-behaviour(gen_server).
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
code_change/3,
terminate/2]).
-record(st, {a :: string()}).
% -record(st, {a :: string(),
% b :: string()}).
% Triggering code_change properly for more than 1 process
-spec change_all([pid()], atom(), term(), term(), integer()) -> boolean().
change_all(Pids, Mod, OldVsn, Extra, Timeout) ->
[sys:suspend(Pid, Timeout) || Pid <- Pids],
c:l(Mod),
[sys:change_code(Pid, Mod, OldVsn, Extra) || Pid <- Pids],
[sys:resume(Pid) || Pid <- Pids],
code:purge(Mod).
-spec start() -> {ok, pid()} | {error, term()}.
start() ->
gen_server:start(?MODULE, [], []).
-spec init([]) -> {ok, #st{}}.
init([]) ->
io:format("init~n", []),
St = #st{a = "a"},
{ok, St}.
-spec handle_call(term(), term(), #st{}) -> term().
handle_call(Msg, From, #st{} = St) ->
io:format("handle_call ~p~n", [{Msg, From, St}]),
{reply, ok, St}.
-spec handle_cast(term(), #st{}) -> term().
handle_cast(Msg, #st{} = St) ->
io:format("handle_cast ~p~n", [{Msg, St}]),
{noreply, St}.
-spec handle_info(term(), #st{}) -> term().
handle_info(Info, #st{} = St) ->
io:format("handle_info ~p~n", [{Info, St}]),
case Info of
{sleep, Time} ->
io:format(" sleeping...~n", []),
timer:sleep(Time);
_ ->
ok
end,
{noreply, St}.
-spec code_change(term(), #st{}, term()) -> {ok, #st{}}.
code_change(add_b, OldSt, Extra) ->
io:format("code_change ~p~n", [{add_b, OldSt, Extra}]),
NewSt = list_to_tuple(tuple_to_list(OldSt) ++ [Extra]),
io:format(" added b! ~p~n", [NewSt]),
{ok, NewSt}.
-spec terminate(term(), #st{}) -> term().
terminate(Reason, #st{} = St) ->
io:format("terminate ~p~n", [{Reason, St}]),
ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment