sends don't block, right?

Shawn Pearce spearce@REDACTED
Wed Feb 25 15:25:20 CET 2004


And all of these are good rules, and my poorly written example to
find out worst-case behavior really breaks them.  :-)

My real code of course follows these.  Only I usually reply back to
the caller in a gen_server when the call is invalid/unsupported.  This
way the caller gets {error, {badcall, Call}} rather than a server
crashing.  I mean, what if a programmer does something stupid in a client
like:

	Server = ...,
	OtherServer = ...,

	case server_api:lock(OtherServer) of
	ok ->
		case other_server_api:lock(Server) of
		ok ->
	...

?  Do we really want both servers to crash because a client application
mixed up the pids?  Usually not.  But usually the caller will crash due
to a badmatch:

	ok = server_api:lock(OtherServer),
	ok = other_server_api:lock(Server)

and wham!  The client dies, as it has the error, and the server stays up,
as it is otherwise healthy.


I was worried about the parent blocking because lets say that the serial
port has stopped being able to transmit data out the serial line.  The
OS buffer will fill up, and then the port driver buffer will fill, and
then the OS pipe buffer (between the node and the port driver) will
fill, and then the node's output biffer will fill.. and any process
using port_command/2 will block (port busy).

But I can't use a timeout with port_command/2.

But I can by doing this:

	user:
		Server ! {send, Data},
		Server ! {recv, self(), 8},
		receive
		{reply, Data} ->
			Data
		after 30 * 1000 ->
			exit(timeout)
		end

	server:
		loop(P) ->
			receive
			{send, D} ->
				port_command(P, D),
				loop(P);
			{recv, From, L) ->
				port_command(P, ...),
				receive
				{P, ..., Data} ->
					From ! {reply, Data}
				end,
				loop(P)
			end.

and be certain that the user will not block until the receive call,
where it can handle the timeout.  Oh sure, the server will be frozen
in the port_command when handling {send, D}, but the client will just
buffer up {recv, F, L} in the server message queue, block in the receive,
wakeup from the timeout, crash (as the port is all screwed up now)
and because I always link the user and the server (spawn_link is my
friend) the port will get killed.

I was just worried if the client decided to send say 10 chunks of
data, and then block in recv that the buffering wasn't going to be
an issue.  From what I've been told, I'm perfectly safe in that.  This
is a serial port after all, it can barely do 256,000 bits per second.
:-)

Francesco Cesarini <francesco@REDACTED> wrote:
> There are design rules 
> (http://www.erlang.se/doc/programming_rules.shtml) to always flush 
> unknown messages, logging the error. I usually go a step further and 
> suggest people make their gen_server code crash through a badmatch if 
> they receive unknown calls and casts, as they are bugs and should not be 
> sent. For handle info, always add a debug printout, as the story is 
> slightly different. Messages for ports closing, nodes going down, 
> possibly expired time-outs, or as I recently discovered, results from 
> asynchronous RPCs, and other junk might appear.
> 
> Shawn - If you are worried about a blocking parent, you could solve your 
> problem with asynchronous call-backs and time-outs.

-- 
Shawn.

  Death.  Destruction.  Disease.  Horror.  That's what war is all about.
  That's what makes it a thing to be avoided.
  		-- Kirk, "A Taste of Armageddon", stardate 3193.0



More information about the erlang-questions mailing list