--- AnyEvent-MP/MP.pm 2009/08/05 23:50:46 1.34 +++ AnyEvent-MP/MP.pm 2009/08/07 16:47:23 1.37 @@ -25,6 +25,11 @@ rcv $port, [child_died => $pid] => sub { ... rcv $port, [_any_, _any_, 3] => sub { .. $_[2] is 3 + # monitoring + mon $port, $cb->(@msg) # callback is invoked on death + mon $port, $otherport # kill otherport on abnormal death + mon $port, $otherport, @msg # send message on death + =head1 DESCRIPTION This module (-family) implements a simple message passing framework. @@ -299,8 +304,10 @@ =item reg $port, $name -Registers the given port under the name C<$name>. If the name already -exists it is replaced. +=item reg $name + +Registers the given port (or C<$SELF><<< if missing) under the name +C<$name>. If the name already exists it is replaced. A port can only be registered under one well known name. @@ -309,9 +316,9 @@ =cut sub reg(@) { - my ($port, $name) = @_; + my $port = @_ > 1 ? shift : $SELF || Carp::croak 'reg: called with one argument only, but $SELF not set,'; - $REG{$name} = $port; + $REG{$_[0]} = $port; } =item rcv $port, $callback->(@msg) @@ -326,7 +333,7 @@ =item rcv $port, [$smartmatch...] => $callback->(@msg), ... Register callbacks to be called on matching messages on the given full -port (after converting it to one if required). +port (after converting it to one if required) and return the port. The callback has to return a true value when its work is done, after which is will be removed, or a false value in which case it will stay @@ -349,6 +356,22 @@ element is a string identifying the message. The one-string-only match is also the most efficient match (by far). +Example: create a port and bind receivers on it in one go. + + my $port = rcv port, + msg1 => sub { ...; 0 }, + msg2 => sub { ...; 0 }, + ; + +Example: create a port, bind receivers and send it in a message elsewhere +in one go: + + snd $otherport, reply => + rcv port, + msg1 => sub { ...; 0 }, + ... + ; + =cut sub rcv($@) { @@ -464,22 +487,37 @@ =item $guard = mon $port, $cb->(@reason) -=item $guard = mon $port, $otherport +=item $guard = mon $port, $rcvport -=item $guard = mon $port, $otherport, @msg +=item $guard = mon $port -Monitor the given port and do something when the port is killed. +=item $guard = mon $port, $rcvport, @msg -In the first form, the callback is simply called with any number -of C<@reason> elements (no @reason means that the port was deleted +Monitor the given port and do something when the port is killed, and +optionally return a guard that can be used to stop monitoring again. + +In the first form (callback), the callback is simply called with any +number of C<@reason> elements (no @reason means that the port was deleted "normally"). Note also that I<< the callback B never die >>, so use C if unsure. -In the second form, the other port will be C'ed with C<@reason>, iff -a @reason was specified, i.e. on "normal" kils nothing happens, while -under all other conditions, the other port is killed with the same reason. - -In the last form, a message of the form C<@msg, @reason> will be C. +In the second form (another port given), the other port (C<$rcvport) +will be C'ed with C<@reason>, iff a @reason was specified, i.e. on +"normal" kils nothing happens, while under all other conditions, the other +port is killed with the same reason. + +The third form (kill self) is the same as the second form, except that +C<$rvport> defaults to C<$SELF>. + +In the last form (message), a message of the form C<@msg, @reason> will be +C. + +As a rule of thumb, monitoring requests should always monitor a port from +a local port (or callback). The reason is that kill messages might get +lost, just like any other message. Another less obvious reason is that +even monitoring requests can get lost (for exmaple, when the connection +to the other node goes down permanently). When monitoring a port locally +these problems do not exist. Example: call a given callback when C<$port> is killed. @@ -487,9 +525,9 @@ Example: kill ourselves when C<$port> is killed abnormally. - mon $port, $self; + mon $port; -Example: send us a restart message another C<$port> is killed. +Example: send us a restart message when another C<$port> is killed. mon $port, $self => "restart"; @@ -500,12 +538,12 @@ my $node = $NODE{$noderef} || add_node $noderef; - my $cb = shift; + my $cb = @_ ? $_[0] : $SELF || Carp::croak 'mon: called with one argument only, but $SELF not set,'; unless (ref $cb) { if (@_) { # send a kill info message - my (@msg) = ($cb, @_); + my (@msg) = @_; $cb = sub { snd @msg, @_ }; } else { # simply kill other port @@ -541,19 +579,11 @@ sub mon_guard { my ($port, @refs) = @_; + #TODO: mon-less form? + mon $port, sub { 0 && @refs } } -=item lnk $port1, $port2 - -Link two ports. This is simply a shorthand for: - - mon $port1, $port2; - mon $port2, $port1; - -It means that if either one is killed abnormally, the other one gets -killed as well. - =item kil $port[, @reason] Kill the specified port with the given C<@reason>. @@ -620,15 +650,15 @@ =head1 AnyEvent::MP vs. Distributed Erlang -AnyEvent::MP got lots of its ideas from distributed erlang (erlang node -== aemp node, erlang process == aemp port), so many of the documents and -programming techniques employed by erlang apply to AnyEvent::MP. Here is a +AnyEvent::MP got lots of its ideas from distributed Erlang (Erlang node +== aemp node, Erlang process == aemp port), so many of the documents and +programming techniques employed by Erlang apply to AnyEvent::MP. Here is a sample: - http://www.erlang.se/doc/programming_rules.shtml - http://erlang.org/doc/getting_started/part_frame.html # chapters 3 and 4 - http://erlang.org/download/erlang-book-part1.pdf # chapters 5 and 6 - http://erlang.org/download/armstrong_thesis_2003.pdf # chapters 4 and 5 + http://www.Erlang.se/doc/programming_rules.shtml + http://Erlang.org/doc/getting_started/part_frame.html # chapters 3 and 4 + http://Erlang.org/download/Erlang-book-part1.pdf # chapters 5 and 6 + http://Erlang.org/download/armstrong_thesis_2003.pdf # chapters 4 and 5 Despite the similarities, there are also some important differences: @@ -649,11 +679,11 @@ needs a queue. AEMP is event based, queuing messages would serve no useful purpose. -(But see L for a more erlang-like process model on top of AEMP). +(But see L for a more Erlang-like process model on top of AEMP). =item * Erlang sends are synchronous, AEMP sends are asynchronous. -Sending messages in erlang is synchronous and blocks the process. AEMP +Sending messages in Erlang is synchronous and blocks the process. AEMP sends are immediate, connection establishment is handled in the background. @@ -666,10 +696,10 @@ AEMP guarantees correct ordering, and the guarantee that there are no holes in the message sequence. -=item * In erlang, processes can be declared dead and later be found to be +=item * In Erlang, processes can be declared dead and later be found to be alive. -In erlang it can happen that a monitored process is declared dead and +In Erlang it can happen that a monitored process is declared dead and linked processes get killed, but later it turns out that the process is still alive - and can receive messages. @@ -679,7 +709,7 @@ =item * Erlang can send messages to the wrong port, AEMP does not. -In erlang it is quite possible that a node that restarts reuses a process +In Erlang it is quite possible that a node that restarts reuses a process ID known to other nodes for a completely different process, causing messages destined for that process to end up in an unrelated process. @@ -695,7 +725,7 @@ =item * The AEMP protocol is optimised for both text-based and binary communications. -The AEMP protocol, unlike the erlang protocol, supports both +The AEMP protocol, unlike the Erlang protocol, supports both language-independent text-only protocols (good for debugging) and binary, language-specific serialisers (e.g. Storable). @@ -703,6 +733,28 @@ with a minimum of work while gracefully degrading fucntionality to make the protocol simple. +=item * AEMP has more flexible monitoring options than Erlang. + +In Erlang, you can chose to receive I exit signals as messages +or I, there is no in-between, so monitoring single processes is +difficult to implement. Monitoring in AEMP is more flexible than in +Erlang, as one can choose between automatic kill, exit message or callback +on a per-process basis. + +=item * Erlang tries to hide remote/local connections, AEMP does not. + +Monitoring in Erlang is not an indicator of process death/crashes, +as linking is (except linking is unreliable in Erlang). + +In AEMP, you don't "look up" registered port names or send to named ports +that might or might not be persistent. Instead, you normally spawn a port +on the remote node. The init function monitors the you, and you monitor +the remote port. Since both monitors are local to the node, they are much +more reliable. + +This also saves round-trips and avoids sending messages to the wrong port +(hard to do in Erlang). + =back =head1 SEE ALSO