--- AnyEvent-MP/MP.pm 2009/09/11 15:02:17 1.88 +++ AnyEvent-MP/MP.pm 2009/12/30 15:49:05 1.109 @@ -1,6 +1,6 @@ =head1 NAME -AnyEvent::MP - multi-processing/message-passing framework +AnyEvent::MP - erlang-style multi-processing/message-passing framework =head1 SYNOPSIS @@ -32,10 +32,22 @@ # 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 $port, $cb->(@msg) # callback is invoked on death - mon $port, $otherport # kill otherport on abnormal death - mon $port, $otherport, @msg # send message on death + 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 @@ -118,7 +130,7 @@ =item seeds - C Seeds are transport endpoint(s) (usually a hostname/IP address and a -TCP port) of nodes thta should be used as seed nodes. +TCP port) of nodes that should be used as seed nodes. The nodes listening on those endpoints are expected to be long-running, and at least one of those should always be available. When nodes run out @@ -145,12 +157,12 @@ use base "Exporter"; -our $VERSION = $AnyEvent::MP::Kernel::VERSION; +our $VERSION = 1.26; our @EXPORT = qw( NODE $NODE *SELF node_of after configure - snd rcv mon mon_guard kil reg psub spawn cal + snd rcv mon mon_guard kil psub peval spawn cal port ); @@ -181,6 +193,9 @@ to know is its own name, and optionally it should know the addresses of some other nodes in the network to discover other nodes. +The key/value pairs are basically the same ones as documented for the +F command line utility (sans the set/del prefix). + This function configures a node - it must be called exactly once (or never) before calling other AnyEvent::MP functions. @@ -373,7 +388,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 +411,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 +421,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 +453,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 { @@ -525,7 +580,7 @@ Inter-host-connection timeouts and monitoring depend on the transport used. The only transport currently implemented is TCP, and AnyEvent::MP relies on TCP to detect node-downs (this can take 10-15 minutes on a -non-idle connection, and usually around two hours for idle conenctions). +non-idle connection, and usually around two hours for idle connections). This means that monitoring is good for program errors and cleaning up stuff eventually, but they are no replacement for a timeout when you need @@ -567,7 +622,7 @@ $node->monitor ($port, $cb); defined wantarray - and AnyEvent::Util::guard { $node->unmonitor ($port, $cb) } + and ($cb += 0, AnyEvent::Util::guard { $node->unmonitor ($port, $cb) }) } =item $guard = mon_guard $port, $ref, $ref... @@ -600,12 +655,12 @@ Kill the specified port with the given C<@reason>. -If no C<@reason> is specified, then the port is killed "normally" (ports -monitoring other ports will not necessarily die because a port dies -"normally"). +If no C<@reason> is specified, then the port is killed "normally" - +monitor callback will be invoked, but the kil will not cause linked ports +(C form) to get killed. -Otherwise, linked ports get killed with the same reason (second form of -C, see above). +If a C<@reason> is specified, then linked ports (C +form) get killed with the same reason. Runtime errors while evaluating C callbacks or inside C blocks will be reported as reason C<< die => $@ >>. @@ -729,8 +784,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 @@ -776,10 +831,10 @@ 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: @@ -789,7 +844,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 +880,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 @@ -928,6 +984,8 @@ L - network maintainance and port groups, to find your applications. +L - establish data connections between nodes. + L - simple service to display log messages from all nodes.