I try to use Linxu::Inotify2 - but not in a thread.
If I have threads inside the program then I get a crash with Inotifys read. If I do not use threads all is fine.
Here is a little sample that should show the problem.
use strict;
use warnings;
use threads;
use Linux::Inotify2;
my $X = 0; # terminate the thread: 0=nothing, 1=detach, 2=join
STDOUT->autoflush ();
my $ino = new Linux::Inotify2 ();
$ino->blocking (0);
$ino->watch (".", IN_MODIFY | IN_ATTRIB | IN_CREATE) or die "error";
my @ls = (); # for save threads if $X == 2
for (my $i=0;;$i++)
{
my $th = threads->create (sub { print "\nTH". shift; }, $i); # just to have threads; do nothing
if ($X == 1)
{
$th->detach (); # detach the thread
}
elsif ($X == 2)
{
push (@ls, $th); # save for joining after thread finished
}
my @events = $ino->read (); # *** CRASH if $X = 1 or 2
if ($X == 2)
{
foreach (@ls)
{
if ($_->is_joinable ())
{
$_->join ();
}
}
}
sleep (1);
}
If I set $X to 0 it will work. If I set it to 1 or 2 then I get a runtime-error.
Linux::Inotify2: read error while reading events at /usr/local/lib/x86_64-linux-gnu/perl/5.26.0/Linux/Inotify2.pm line 266.
Why is that?
EDIT
I simplified my sample to give a better view of the problem.
use strict;
use warnings;
use threads;
use Linux::Inotify2;
STDOUT->autoflush ();
my $ino = new Linux::Inotify2 ();
$ino->blocking (0);
$ino->watch (".", IN_CREATE | IN_DELETE) or die "error";
my $th = threads->create (sub { });
$th->join ();
print "\nINO: ".$ino->poll();
Remove the join it will be ok, keep it and the poll will fail.
The following example implements the idea of zdim who proposed to use an event loop with poll() instead of read(). It's developed on CentOS 7 with Perl 5.16.2 and Linux-Inotify2 v1.22.
The program spawns a thread that watches the /tmp directory. You can test it by touching and removing files: touch /tmp/1 /tmp/2 && rm /tmp/1 /tmp/2
#!/usr/bin/env perl
use warnings FATAL => 'all';
use strict;
use threads;
threads->new(\&_eventListener, '/tmp')->join();
sub _eventListener {
my ($path) = @_;
require Linux::Inotify2;
Linux::Inotify2->import(qw(IN_CREATE IN_DELETE IN_DELETE_SELF));
my $fsEventListener = Linux::Inotify2->new() or
die('Cannot register Linux::Inotify2, stopped');
$fsEventListener->watch(
$path,
IN_CREATE() | IN_DELETE() | IN_DELETE_SELF(),
\&_watchCallback
) or die("Watch creation failed. '$!'");
$fsEventListener->blocking(undef);
while(1) {
$fsEventListener->poll();
sleep 1;
}
return;
}
sub _watchCallback {
my ($e) = @_;
printf STDOUT "Receive event '0x%04x' for file '%s'\n", $e->mask(), $e->fullname();
return;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With