From 42a0387e886ddbf60b0e2cb977758e2ca74954ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 12 Mar 2015 15:35:13 +0100 Subject: Update Design Principles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Language cleaned up by the technical writers xsipewe and tmanevik from Combitech. Proofreading and corrections by Björn Gustavsson. --- .../doc/design_principles/gen_server_concepts.xml | 160 +++++++++++---------- 1 file changed, 83 insertions(+), 77 deletions(-) (limited to 'system/doc/design_principles/gen_server_concepts.xml') diff --git a/system/doc/design_principles/gen_server_concepts.xml b/system/doc/design_principles/gen_server_concepts.xml index d24d87aa03..d721845c6d 100644 --- a/system/doc/design_principles/gen_server_concepts.xml +++ b/system/doc/design_principles/gen_server_concepts.xml @@ -21,7 +21,7 @@ - Gen_Server Behaviour + gen_server Behaviour @@ -29,16 +29,16 @@ gen_server_concepts.xml -

This chapter should be read in conjunction with - gen_server(3), - where all interface functions and callback - functions are described in detail.

+

This section is to be read with the + gen_server(3) + manual page in stdblib, where all interface functions and + callback functions are described in detail.

Client-Server Principles

The client-server model is characterized by a central server and an arbitrary number of clients. The client-server model is - generally used for resource management operations, where several + used for resource management operations, where several different clients want to share a common resource. The server is responsible for managing this resource.

@@ -49,9 +49,10 @@
Example -

An example of a simple server written in plain Erlang was - given in Overview. - The server can be re-implemented using gen_server, +

An example of a simple server written in plain Erlang is + provided in + Overview. + The server can be reimplemented using gen_server, resulting in this callback module:

@@ -86,61 +87,60 @@ handle_cast({free, Ch}, Chs) ->
Starting a Gen_Server -

In the example in the previous section, the gen_server is started - by calling ch3:start_link():

+

In the example in the previous section, gen_server is + started by calling ch3:start_link():

start_link() -> gen_server:start_link({local, ch3}, ch3, [], []) => {ok, Pid} -

start_link calls the function - gen_server:start_link/4. This function spawns and links to - a new process, a gen_server.

+

start_link calls function gen_server:start_link/4. + This function spawns and links to a new process, a + gen_server.

-

The first argument {local, ch3} specifies the name. In - this case, the gen_server will be locally registered as - ch3.

-

If the name is omitted, the gen_server is not registered. - Instead its pid must be used. The name could also be given - as {global, Name}, in which case the gen_server is +

The first argument, {local, ch3}, specifies the name. + The gen_server is then locally registered as ch3.

+

If the name is omitted, the gen_server is not registered. + Instead its pid must be used. The name can also be given + as {global, Name}, in which case the gen_server is registered using global:register_name/2.

The second argument, ch3, is the name of the callback - module, that is the module where the callback functions are + module, that is, the module where the callback functions are located.

-

In this case, the interface functions (start_link, - alloc and free) are located in the same module - as the callback functions (init, handle_call and +

The interface functions (start_link, alloc, + and free) are then located in the same module + as the callback functions (init, handle_call, and handle_cast). This is normally good programming practice, to have the code corresponding to one process contained in one module.

-

The third argument, [], is a term which is passed as-is to - the callback function init. Here, init does not +

The third argument, [], is a term that is passed as is + to the callback function init. Here, init does not need any indata and ignores the argument.

-

The fourth argument, [], is a list of options. See - gen_server(3) for available options.

+

The fourth argument, [], is a list of options. See the + gen_server(3) manual page for available options.

-

If name registration succeeds, the new gen_server process calls - the callback function ch3:init([]). init is expected - to return {ok, State}, where State is the internal - state of the gen_server. In this case, the state is the available - channels.

+

If name registration succeeds, the new gen_server process + calls the callback function ch3:init([]). init is + expected to return {ok, State}, where State is the + internal state of the gen_server. In this case, the state + is the available channels.

init(_Args) -> {ok, channels()}. -

Note that gen_server:start_link is synchronous. It does - not return until the gen_server has been initialized and is ready +

gen_server:start_link is synchronous. It does not return + until the gen_server has been initialized and is ready to receive requests.

-

gen_server:start_link must be used if the gen_server is - part of a supervision tree, i.e. is started by a supervisor. - There is another function gen_server:start to start a - stand-alone gen_server, i.e. a gen_server which is not part of a - supervision tree.

+

gen_server:start_link must be used if the gen_server + is part of a supervision tree, that is, started by a supervisor. + There is another function, gen_server:start, to start a + standalone gen_server, that is, a gen_server that + is not part of a supervision tree.

@@ -150,14 +150,17 @@ init(_Args) -> alloc() -> gen_server:call(ch3, alloc). -

ch3 is the name of the gen_server and must agree with - the name used to start it. alloc is the actual request.

-

The request is made into a message and sent to the gen_server. - When the request is received, the gen_server calls - handle_call(Request, From, State) which is expected to - return a tuple {reply, Reply, State1}. Reply is - the reply which should be sent back to the client, and - State1 is a new value for the state of the gen_server.

+

ch3 is the name of the gen_server and must agree + with the name used to start it. alloc is the actual + request.

+

The request is made into a message and sent to the + gen_server. When the request is received, the + gen_server calls + handle_call(Request, From, State), which is expected to + return a tuple {reply,Reply,State1}. Reply is + the reply that is to be sent back to the client, and + State1 is a new value for the state of the + gen_server.

handle_call(alloc, _From, Chs) -> {Ch, Chs2} = alloc(Chs), @@ -166,8 +169,8 @@ handle_call(alloc, _From, Chs) -> the new state is the set of remaining available channels Chs2.

Thus, the call ch3:alloc() returns the allocated channel - Ch and the gen_server then waits for new requests, now - with an updated list of available channels.

+ Ch and the gen_server then waits for new requests, + now with an updated list of available channels.

@@ -177,20 +180,21 @@ handle_call(alloc, _From, Chs) -> free(Ch) -> gen_server:cast(ch3, {free, Ch}). -

ch3 is the name of the gen_server. {free, Ch} is - the actual request.

-

The request is made into a message and sent to the gen_server. +

ch3 is the name of the gen_server. + {free, Ch} is the actual request.

+

The request is made into a message and sent to the + gen_server. cast, and thus free, then returns ok.

-

When the request is received, the gen_server calls - handle_cast(Request, State) which is expected to - return a tuple {noreply, State1}. State1 is a new - value for the state of the gen_server.

+

When the request is received, the gen_server calls + handle_cast(Request, State), which is expected to + return a tuple {noreply,State1}. State1 is a new + value for the state of the gen_server.

handle_cast({free, Ch}, Chs) -> Chs2 = free(Ch, Chs), {noreply, Chs2}.

In this case, the new state is the updated list of available - channels Chs2. The gen_server is now ready for new + channels Chs2. The gen_server is now ready for new requests.

@@ -199,15 +203,17 @@ handle_cast({free, Ch}, Chs) ->
In a Supervision Tree -

If the gen_server is part of a supervision tree, no stop - function is needed. The gen_server will automatically be +

If the gen_server is part of a supervision tree, no stop + function is needed. The gen_server is automatically terminated by its supervisor. Exactly how this is done is - defined by a shutdown strategy set in the supervisor.

+ defined by a + shutdown strategy + set in the supervisor.

If it is necessary to clean up before termination, the shutdown - strategy must be a timeout value and the gen_server must be set - to trap exit signals in the init function. When ordered - to shutdown, the gen_server will then call the callback function - terminate(shutdown, State):

+ strategy must be a time-out value and the gen_server must + be set to trap exit signals in function init. When ordered + to shutdown, the gen_server then calls the callback + function terminate(shutdown, State):

init(Args) -> ..., @@ -223,9 +229,9 @@ terminate(shutdown, State) ->
- Stand-Alone Gen_Servers -

If the gen_server is not part of a supervision tree, a stop - function may be useful, for example:

+ Standalone Gen_Servers +

If the gen_server is not part of a supervision tree, a + stop function can be useful, for example:

... export([stop/0]). @@ -245,26 +251,26 @@ handle_cast({free, Ch}, State) -> terminate(normal, State) -> ok.

The callback function handling the stop request returns - a tuple {stop, normal, State1}, where normal + a tuple {stop,normal,State1}, where normal specifies that it is a normal termination and State1 is - a new value for the state of the gen_server. This will cause - the gen_server to call terminate(normal,State1) and then - terminate gracefully.

+ a new value for the state of the gen_server. This causes + the gen_server to call terminate(normal, State1) + and then it terminates gracefully.

Handling Other Messages -

If the gen_server should be able to receive other messages than - requests, the callback function handle_info(Info, State) +

If the gen_server is to be able to receive other messages + than requests, the callback function handle_info(Info, State) must be implemented to handle them. Examples of other messages - are exit messages, if the gen_server is linked to other processes - (than the supervisor) and trapping exit signals.

+ are exit messages, if the gen_server is linked to other + processes (than the supervisor) and trapping exit signals.

handle_info({'EXIT', Pid, Reason}, State) -> ..code to handle exits here.. {noreply, State1}. -

The code_change method also has to be implemented.

+

The code_change method must also be implemented.

code_change(OldVsn, State, Extra) -> ..code to convert state (and more) during code change -- cgit v1.2.3