Skip Menu |

This queue is for tickets about the Sys-Virt CPAN distribution.

Report information
The Basics
Id: 118813
Status: rejected
Priority: 0/
Queue: Sys-Virt

People
Owner: dan [...] berrange.com
Requestors: frankie [...] etsetb.upc.edu
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 1.2.16
Fixed in: (no value)



Subject: Connection dies when forking and no callback
Hi, first thank you for the module, it is great. I was trying to fork in a script with a connection to a KVM server. After the forked code exits, the script dies when I try to access the VM again. I checked the docs and I saw about the close_callback. So I started coding a callback to reconnect. To my surprise I don't have to write any code in there. Only having one registered makes the script not to die. I am not sure that was the expected behaviour but I guess there must be a bug somwhere. The system is Ubuntu Xenial with Sys::Virt 1.2.16. Here is a test. Let me know if there is something else I can try.
Subject: test_fork.t
#!/usr/bin/perl use warnings; use strict; use Sys::Virt; use Test::More tests => 2; my $vm = Sys::Virt->new( address => "qemu:///system" ); ################################################# sub _reconnect { } sub test_fork { diag("testing fork"); my $pid = fork(); # son exit if !$pid; #parent wait(); $vm->list_all_domains ; # it is ok(1) because we just test it gets here ok(1); } #################################################3 # with the callback it forks $vm->register_close_callback(\&_reconnect); test_fork(); #only commenting the next line makes test 2 ok $vm->unregister_close_callback(); test_fork();
On Thu Nov 17 11:01:39 2016, FRANKIE wrote: Show quoted text
> Hi, first thank you for the module, it is great. > > I was trying to fork in a script with a connection to a KVM server. > After the forked code exits, the script dies when I try to access the > VM again. > > I checked the docs and I saw about the close_callback. So I started > coding a callback to reconnect. To my surprise I don't have to write > any code in there. Only having one registered makes the script not to > die. > > I am not sure that was the expected behaviour but I guess there must > be a bug somwhere. The system is Ubuntu Xenial with Sys::Virt 1.2.16.
Using fork() but not exec() in a process is a very difficult thing to do right even in plain C, let alone in Perl. You have a single UNIX socket connection to the libvirtd daemon, associated with the '$vm' connection variable. When you fork, you get a copy-on-write memory mapping, so changes to $vm in the child don't affect the parent and vica-verca. Except, that this isn't entirely true because you have a single network socket. So when '$vm' goes out of scope in one process, it'll trigger libvirt to send an RPC message to close the network connection. Libvirtd will thus drop the client, and this will affect *both* parent and child processes since they were both using the same network connection. When you're registering a close callback you're triggering acquisition of another reference on the connection, so as long as the callback is present, $vm will never be garbage collected. Thus when the child exits, it isn't causing the network socket to be closed, and thus the parent is still ok. This is largely a matter luck. If you were to actually explicitly call any libvirt API calls in the child and parent you'll almost certainly get correct data on the network socket, causing it to be closed by the server too. The only real reliable thing here is to *not* have a connection to libvirt open when you fork. Failing that you need to figure out some way to prevent perl garbage collecting the libvirt connection in the child - traditionally in C you would use '_exit' instead of exit to prevent normal cleanup happening - so perhaps try POSIX::_exit instead of exit in the child. If you were to 'exec' another process in the child that'll probably avoid perls' garbage collector running too. There's just nothing we can do about this from the libvirt side I'm afraid
I tried doing a $vm = undef before the fork. Then I connect in the child and in the parent and it works fine without the callback. Thank you very much, Dan.