plain_fsm - for beginners and purists

Shawn Pearce spearce@REDACTED
Fri Feb 13 16:06:01 CET 2004


This is exactly one idea I had thought about proposing, and I nearly
put it into my fsm behavior's code the other day.  The problem is
exactly what Ulf points out, you are removing the selective receive
functionality entirely.  There's two cases:

  1) in the current state, we want to pull all messages, and maybe
     give error reports to let the admins/developers know an
	 unsupported message was just received.

  2) in the current state, we only want to pull a few messages, and
     leave the rest in the queue.  These may be messages we will
	 react to once we leave this state.  Good example is a lock
	 manager, when it enters the "lock_held" state it won't want
	 to consume any incoming lock_request messages, just leave them
	 in the queue.

Now mix into those the fact that you may want to consume and handle
system messages when in either type of receive.  It may be very
important to handle the system messages in case 2, as you may be waiting
for an unlock_request message to come in, but it never will, because
the locking process has been suspended by the release handler (for a
pending code change).  Thus the lock manager never can process the
system suspend or code change messages, and the upgrade will have to
abort.

I really have to wonder, is it so hard to just make the developer do
something such as:

plain_fsm.hrl:
	-import({plain_fsm, [
		handle_system_message/2,
		handle_parent_exit/1,
		handle_unknown_message/1
	]).

user_module.erl:
	-include("plain_fsm.hrl").

	-export([code_change/3]).

	Parent = parent(),
	receive
	{system, From, Message} -> handle_system_message(From, Message);
	{'EXIT', Parent, Reason} -> handle_parent_exit(Reason);
	...
	Any -> handle_unknown_message(Any)
	end.

??  I guess the big problem is the simple fact that the developer
might forget to make one of the calls in a stable state, or mess up
the pattern and pass faulty messages to plain_fsm.

But what we are talking about here is the correct handling of OTP
system messages.  To most people, OTP is "erlang" anyway, if you are
in Erlang, you should try to use OTP when you can, because its done
a lot of the hard work for you.  So in reality, the "system" should
be able to automatically process system messages.  I think its just
as fundamental to the langauge as mnemosyne's query [...] end LC.

So what about adding an option to the receive statement that isn't
specific to plain_fsm, but is instead related to/owned by the sys
and proc_lib modules?

	recieve system
	a -> a(S),
	b -> b(S)
	end.

Unfortunately this most likely would need changes to the linter and
early stages of the parse tree construction as its definately not valid
Erlang.  But the point I'm trying to make is, perhaps this should be!

Ulf Wiger <ulf.wiger@REDACTED> wrote:
> On Fri, 13 Feb 2004 10:57:31 +0100, Vlad Dumitrescu 
> <vlad_dumitrescu@REDACTED> wrote:
> 
> >Okay, what about
> >
> >receive
> >    .... %% nomal clauses
> >    Msg ->
> >        plain_fsm:handle(State, Msg, 
> >Fun_that_handles_non_system_messages)
> >end;
> >
> >It's a little ugly, but maybe not too much.
> 
> Unfortunately this violates the selective receive semantics.
> You cannot do this without consuming the message, and you can't
> put it back where it was. Thus, you reorder the messages in the queue,
> and this can cause subtle bugs. If you don't recognize the message,
> you need to either throw it away or avoid touching it in the first
> place.

-- 
Shawn.

  You probably wouldn't worry about what people think of you if you could
  know how seldom they do.
  		-- Olin Miller.



More information about the erlang-questions mailing list