--- AnyEvent-MP/MP.pm 2009/10/02 13:29:49 1.97 +++ AnyEvent-MP/MP.pm 2009/11/06 17:47:20 1.104 @@ -32,11 +32,23 @@ # create a port on another node my $port = spawn $node, $initfunc, @initdata; + # destroy a prot again + kil $port; # "normal" kill + kil $port, my_error => "everything is broken"; # error kill + # monitoring mon $localport, $cb->(@msg) # callback is invoked on death mon $localport, $otherport # kill otherport on abnormal death mon $localport, $otherport, @msg # send message on death + # temporarily execute code in port context + peval $port, sub { die "kill the port!" }; + + # execute callbacks in $SELF port context + my $timer = AE::timer 1, 0, psub { + die "kill the port, delayed"; + }; + =head1 CURRENT STATUS bin/aemp - stable. @@ -145,12 +157,12 @@ use base "Exporter"; -our $VERSION = 1.2; +our $VERSION = 1.23; our @EXPORT = qw( NODE $NODE *SELF node_of after configure - snd rcv mon mon_guard kil psub spawn cal + snd rcv mon mon_guard kil psub peval spawn cal port ); @@ -373,7 +385,7 @@ ; Example: temporarily register a rcv callback for a tag matching some port -(e.g. for a rpc reply) and unregister it after a message was received. +(e.g. for an rpc reply) and unregister it after a message was received. rcv $port, $otherport => sub { my @reply = @_; @@ -396,7 +408,7 @@ "AnyEvent::MP::Port" eq ref $self or Carp::croak "$port: rcv can only be called on message matching ports, caught"; - $self->[2] = shift; + $self->[0] = shift; } else { my $cb = shift; $PORT{$portid} = sub { @@ -406,7 +418,7 @@ } } elsif (defined $_[0]) { my $self = $PORT_DATA{$portid} ||= do { - my $self = bless [$PORT{$port} || sub { }, { }, $port], "AnyEvent::MP::Port"; + my $self = bless [$PORT{$portid} || sub { }, { }, $port], "AnyEvent::MP::Port"; $PORT{$portid} = sub { local $SELF = $port; @@ -438,12 +450,52 @@ $port } +=item peval $port, $coderef[, @args] + +Evaluates the given C<$codref> within the contetx of C<$port>, that is, +when the code throews an exception the C<$port> will be killed. + +Any remaining args will be passed to the callback. Any return values will +be returned to the caller. + +This is useful when you temporarily want to execute code in the context of +a port. + +Example: create a port and run some initialisation code in it's context. + + my $port = port { ... }; + + peval $port, sub { + init + or die "unable to init"; + }; + +=cut + +sub peval($$) { + local $SELF = shift; + my $cb = shift; + + if (wantarray) { + my @res = eval { &$cb }; + _self_die if $@; + @res + } else { + my $res = eval { &$cb }; + _self_die if $@; + $res + } +} + =item $closure = psub { BLOCK } Remembers C<$SELF> and creates a closure out of the BLOCK. When the closure is executed, sets up the environment in the same way as in C callbacks, i.e. runtime errors will cause the port to get Ced. +The effect is basically as if it returned C<< sub { peval $SELF, sub { +BLOCK } } >>. + This is useful when you register callbacks from C callbacks: rcv delayed_reply => sub { @@ -729,8 +781,8 @@ then the callback will be called without any arguments after the time-out elapsed and the port is Ced. -If no time-out is given, then the local port will monitor the remote port -instead, so it eventually gets cleaned-up. +If no time-out is given (or it is C), then the local port will +monitor the remote port instead, so it eventually gets cleaned-up. Currently this function returns the temporary port, but this "feature" might go in future versions unless you can make a convincing case that @@ -789,7 +841,8 @@ Erlang relies on special naming and DNS to work everywhere in the same way. AEMP relies on each node somehow knowing its own address(es) (e.g. by -configuration or DNS), but will otherwise discover other odes itself. +configuration or DNS), and possibly the addresses of some seed nodes, but +will otherwise discover other nodes (and their IDs) itself. =item * Erlang has a "remote ports are like local ports" philosophy, AEMP uses "local ports are like remote ports". @@ -824,9 +877,9 @@ =item * Erlang suffers from silent message loss, AEMP does not. -Erlang makes few guarantees on messages delivery - messages can get lost -without any of the processes realising it (i.e. you send messages a, b, -and c, and the other side only receives messages a and c). +Erlang implements few guarantees on messages delivery - messages can get +lost without any of the processes realising it (i.e. you send messages a, +b, and c, and the other side only receives messages a and c). AEMP guarantees correct ordering, and the guarantee that after one message is lost, all following ones sent to the same port are lost as well, until