AnyEvent-FDpasser
view release on metacpan or search on metacpan
AnyEvent documentation).
Creating a passer object before forking is fine since doing this doesn't
install any AnyEvent watchers. Also, using the filesystem with "AF_UNIX"
sockets (or more portably, "fdpasser_server", "fdpasser_accept", and
"fdpasser_connect") obviates the need to worry about forking.
Control channels
A useful design is to have a "control channel" associated with each
passer that sends over data related to file descriptors being passed. As
long as the control channel is a synchronised and ordered queue of
messages, each message can indicate how many descriptors it is sending
along on the FDpasser channel.
With both the BSD and SysV APIs it is possible to use the passer
filehandle to transfer control data but this module does not support
this in order to keep the API simple. However, instead you can use a
separate socket connection as your control channel. How to synchronize
passers and control channels? One way is to connect to a passer server
and pass the control channel socket in as the first file descriptor.
Portability
In order to use the SysV interface, set the "FDPASSER_SYSV" environment
variable when running "Makefile.PL":
$ FDPASSER_SYSV=1 perl Makefile.PL
Currently the default is to always use the BSD interface. It will
and "ioctl" system calls used to implement descriptor passing can fail
unexpectedly. Failing to create a descriptor is especially bad when
transfering descriptors since the outcome is not well specified. Linux
doesn't even mention this possible failure mode in the recvmsg() man
page. BSD manuals indicate that EMSGSIZE will be returned and any
descriptors in transit will be closed. If a descriptor is closed it can
never be delivered to the application, even if the full descriptor table
problem clears up.
So what should we do? We could silently ignore it when a descriptor
fails to transfer, but then we run the risk of desynchronising the
descriptor stream. Another possibility is indicating to the application
that this descriptor has failed to transfer and is now lost forever.
Unfortunately this complicates the error handling an application must
do, especially if the descriptor is linked to other descriptors which
must then be received and (if they make it) closed. Finally, we could
just give up, call the on_error callback, destory the passer object and
punt the problem back to the application.
None of the above "solutions" are very appealing so this module uses a
trick known as the "close-dup slot reservation" trick. Actually I just
descriptor, receive the descriptor from the sending process, and then
attempt to dup another descriptor. Because we just cleared a descriptor
table entry, there should always be a free descriptor to create.
If duping fails, we stop trying to receive any further descriptors and
instead retry at regular intervals (while not interrupting the event
loop). Hopefully eventually the full descriptor table issue will clear
up and we will be able to resume receiving descriptors.
Note that a descriptor could be created between closing and receiving if
your program uses asynchronous signal handlers or threads that create
descriptors, so don't do that. Signals that are handled synchronously
(like normal AnyEvent signal watchers) are fine.
This trick is similar to a trick described in Marc Lehmann's libev POD
document, section "special problem of accept()ing when you can't,"
although the purpose of employing the trick in this module is somewhat
different.
TESTS AND SYSTEM ASSUMPTIONS
All the following tests should work with BSD4.4, BSD4.3, and SysV
interfaces (where available).
=head2 Forking
This module itself never calls C<fork()>, but many use-cases of this module involve the application program forking. All the usual things you must worry about when forking an AnyEvent application also apply to this module. In particular, you should e...
Creating a passer object before forking is fine since doing this doesn't install any AnyEvent watchers. Also, using the filesystem with C<AF_UNIX> sockets (or more portably, C<fdpasser_server>, C<fdpasser_accept>, and C<fdpasser_connect>) obviates th...
=head2 Control channels
A useful design is to have a "control channel" associated with each passer that sends over data related to file descriptors being passed. As long as the control channel is a synchronised and ordered queue of messages, each message can indicate how ma...
With both the BSD and SysV APIs it is possible to use the passer filehandle to transfer control data but this module does not support this in order to keep the API simple. However, instead you can use a separate socket connection as your control chan...
=head2 Portability
In order to use the SysV interface, set the C<FDPASSER_SYSV> environment variable when running C<Makefile.PL>:
$ FDPASSER_SYSV=1 perl Makefile.PL
Currently the default is to always use the BSD interface. It will attempt to figure out which interface is appropriate (BSD4.4 or BSD4.3). Currently Solaris uses 4.3 and everything else uses 4.4. Patches and/or portability reports are welcome.
=head1 FULL DESCRIPTOR TABLES
Any system call that creates new descriptors in your process can fail because your process has exceed its NOFILE resource limit. Also, it can fail because the system has run out of resources and can't handle new files or (more likely on modern system...
In order to pass a file descriptor between processes, a new descriptor needs to be allocated in the receiving process. Therefore, the C<recvmsg> and C<ioctl> system calls used to implement descriptor passing can fail unexpectedly. Failing to create a...
So what should we do? We could silently ignore it when a descriptor fails to transfer, but then we run the risk of desynchronising the descriptor stream. Another possibility is indicating to the application that this descriptor has failed to transfer...
None of the above "solutions" are very appealing so this module uses a trick known as the "close-dup slot reservation" trick. Actually I just made that name up now but it sounds pretty cool don't you think? The idea is that when the passer object is ...
When it comes time to receive a descriptor, we close the sentinel descriptor, receive the descriptor from the sending process, and then attempt to dup another descriptor. Because we just cleared a descriptor table entry, there should always be a free...
If duping fails, we stop trying to receive any further descriptors and instead retry at regular intervals (while not interrupting the event loop). Hopefully eventually the full descriptor table issue will clear up and we will be able to resume receiv...
Note that a descriptor could be created between closing and receiving if your program uses asynchronous signal handlers or threads that create descriptors, so don't do that. Signals that are handled synchronously (like normal AnyEvent signal watchers...
This trick is similar to a trick described in Marc Lehmann's libev POD document, section "special problem of accept()ing when you can't," although the purpose of employing the trick in this module is somewhat different.
=head1 TESTS AND SYSTEM ASSUMPTIONS
All the following tests should work with BSD4.4, BSD4.3, and SysV interfaces (where available).
lib/AnyEvent/FDpasser.pm view on Meta::CPAN
my $rv = recv_fd(fileno($self->{fh}));
if ($rv == -1) {
if ($!{EAGAIN} || $!{EWOULDBLOCK} || $!{EINTR}) {
## Spurious ready notification or signal: put the cb back on the queue
unshift @{$self->{ibuf}}, $cb;
} elsif ($!{EMSGSIZE} || $!{EMFILE} || $!{ENFILE}) {
## File descriptor table is full. This should be very unlikely given the close+duping
## technique used to detect this. In this case the descriptor stream may be
## desynchronised and we must shutdown the passer.
my $err = $!;
carp "AnyEvent::FDpasser - file descriptor table full, closing passer: $!";
$self->error($err);
} else {
## Unknown error
$self->error($!);
}
lib/AnyEvent/FDpasser.pm view on Meta::CPAN
=head2 Forking
This module itself never calls C<fork()>, but many use-cases of this module involve the application program forking. All the usual things you must worry about when forking an AnyEvent application also apply to this module. In particular, you should e...
Creating a passer object before forking is fine since doing this doesn't install any AnyEvent watchers. Also, using the filesystem with C<AF_UNIX> sockets (or more portably, C<fdpasser_server>, C<fdpasser_accept>, and C<fdpasser_connect>) obviates th...
=head2 Control channels
A useful design is to have a "control channel" associated with each passer that sends over data related to file descriptors being passed. As long as the control channel is a synchronised and ordered queue of messages, each message can indicate how ma...
With both the BSD and SysV APIs it is possible to use the passer filehandle to transfer control data but this module does not support this in order to keep the API simple. However, instead you can use a separate socket connection as your control chan...
=head2 Portability
In order to use the SysV interface, set the C<FDPASSER_SYSV> environment variable when running C<Makefile.PL>:
$ FDPASSER_SYSV=1 perl Makefile.PL
Currently the default is to always use the BSD interface. It will attempt to figure out which interface is appropriate (BSD4.4 or BSD4.3). Currently Solaris uses 4.3 and everything else uses 4.4. Patches and/or portability reports are welcome.
=head1 FULL DESCRIPTOR TABLES
Any system call that creates new descriptors in your process can fail because your process has exceed its NOFILE resource limit. Also, it can fail because the system has run out of resources and can't handle new files or (more likely on modern system...
In order to pass a file descriptor between processes, a new descriptor needs to be allocated in the receiving process. Therefore, the C<recvmsg> and C<ioctl> system calls used to implement descriptor passing can fail unexpectedly. Failing to create a...
So what should we do? We could silently ignore it when a descriptor fails to transfer, but then we run the risk of desynchronising the descriptor stream. Another possibility is indicating to the application that this descriptor has failed to transfer...
None of the above "solutions" are very appealing so this module uses a trick known as the "close-dup slot reservation" trick. Actually I just made that name up now but it sounds pretty cool don't you think? The idea is that when the passer object is ...
When it comes time to receive a descriptor, we close the sentinel descriptor, receive the descriptor from the sending process, and then attempt to dup another descriptor. Because we just cleared a descriptor table entry, there should always be a free...
If duping fails, we stop trying to receive any further descriptors and instead retry at regular intervals (while not interrupting the event loop). Hopefully eventually the full descriptor table issue will clear up and we will be able to resume receiv...
Note that a descriptor could be created between closing and receiving if your program uses asynchronous signal handlers or threads that create descriptors, so don't do that. Signals that are handled synchronously (like normal AnyEvent signal watchers...
This trick is similar to a trick described in Marc Lehmann's libev POD document, section "special problem of accept()ing when you can't," although the purpose of employing the trick in this module is somewhat different.
=head1 TESTS AND SYSTEM ASSUMPTIONS
All the following tests should work with BSD4.4, BSD4.3, and SysV interfaces (where available).
( run in 0.294 second using v1.01-cache-2.11-cpan-0d8aa00de5b )