Browse Source

Limit the leakiness of a timeout in gproc:await/2.

If we get a value before timeout happens, the timer is still there and
will fire at a later time. This means that the timeout will leak from
gproc into the process which called await/2 and that process might not
be ready to handle the problem.

This fix cancels the timer if the normal message is received. It does
not eliminate the leak though, since the timer might have fired just
before we get to receive the message and thus be in the msg queue of
the process. The cancel will then fail and the timeout will have
leaked. To give a receiver a hint, we have opted to make timeout into
gproc_timeout as an atom() in the hope this will suggest where to
look.
Jesper Louis Andersen 14 years ago
parent
commit
984fbddfe9
1 changed files with 6 additions and 2 deletions
  1. 6 2
      src/gproc.erl

+ 6 - 2
src/gproc.erl

@@ -305,15 +305,19 @@ request_wait({n,C,_} = Key, Timeout) when C==l; C==g ->
     TRef = case Timeout of
                infinity -> no_timer;
                T when is_integer(T), T > 0 ->
-                   erlang:start_timer(T, self(), timeout);
+                   erlang:start_timer(T, self(), gproc_timeout);
                _ ->
                    erlang:error(badarg, [Key, Timeout])
            end,
     WRef = call({await,Key,self()}, C),
     receive
         {gproc, WRef, registered, {_K, Pid, V}} ->
+	    case Timeout of
+		no_timer -> ignore;
+		TRef -> erlang:cancel_timer(TRef)
+	    end,
             {Pid, V};
-        {timeout, TRef, timeout} ->
+        {timeout, TRef, gproc_timeout} ->
             cancel_wait(Key, WRef),
             erlang:error(timeout, [Key, Timeout])
     end.