mirror of
git://git.proxmox.com/git/pve-common.git
synced 2024-12-22 21:33:47 +03:00
3feb2c7661
Not needed anymore. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
162 lines
3.2 KiB
Perl
Executable File
162 lines
3.2 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
|
|
use lib '../src';
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Socket;
|
|
use POSIX (); # don't import assert()
|
|
|
|
use PVE::Tools 'lock_file_full';
|
|
|
|
my $name = "test.lockfile.$$-";
|
|
|
|
END {
|
|
system("rm $name*");
|
|
};
|
|
|
|
# Utilities:
|
|
|
|
sub forked($$) {
|
|
my ($code1, $code2) = @_;
|
|
|
|
pipe(my $except_r, my $except_w) or die "pipe: $!\n";
|
|
|
|
my $pid = fork();
|
|
die "fork failed: $!\n" if !defined($pid);
|
|
|
|
if ($pid == 0) {
|
|
close($except_r);
|
|
eval { $code1->() };
|
|
if ($@) {
|
|
print {$except_w} $@;
|
|
$except_w->flush();
|
|
POSIX::_exit(1);
|
|
}
|
|
POSIX::_exit(0);
|
|
}
|
|
close($except_w);
|
|
|
|
eval { $code2->() };
|
|
my $err = $@;
|
|
if ($err) {
|
|
kill(15, $pid);
|
|
} else {
|
|
my $err = do { local $/ = undef; <$except_r> };
|
|
}
|
|
die "interrupted\n" if waitpid($pid, 0) != $pid;
|
|
die $err if $err;
|
|
|
|
# Check exit code:
|
|
my $status = POSIX::WEXITSTATUS($?);
|
|
if ($? == -1) {
|
|
die "failed to execute\n";
|
|
} elsif (POSIX::WIFSIGNALED($?)) {
|
|
my $sig = POSIX::WTERMSIG($?);
|
|
die "got signal $sig\n";
|
|
} elsif ($status != 0) {
|
|
die "exit code $status\n";
|
|
}
|
|
}
|
|
|
|
# Book-keeping:
|
|
|
|
my %_ran;
|
|
sub new {
|
|
%_ran = ();
|
|
}
|
|
sub ran {
|
|
my ($what) = @_;
|
|
$_ran{$what} = 1;
|
|
}
|
|
sub assert {
|
|
my ($what) = @_;
|
|
die "code didn't run: $what\n" if !$_ran{$what};
|
|
}
|
|
sub assert_not {
|
|
my ($what) = @_;
|
|
die "code shouldn't have run: $what\n" if $_ran{$what};
|
|
}
|
|
|
|
# Regular lock:
|
|
new();
|
|
lock_file_full($name, 10, 0, sub { ran('single lock') });
|
|
assert('single lock');
|
|
|
|
# Lock multiple times in a row:
|
|
new();
|
|
lock_file_full($name, 10, 0, sub { ran('lock A') });
|
|
assert('lock A');
|
|
lock_file_full($name, 10, 0, sub { ran('lock B') });
|
|
assert('lock B');
|
|
|
|
# Nested lock:
|
|
new();
|
|
lock_file_full($name, 10, 0, sub {
|
|
ran('lock A');
|
|
lock_file_full($name, 10, 0, sub { ran('lock B') });
|
|
assert('lock B');
|
|
ran('lock C');
|
|
});
|
|
assert('lock A');
|
|
assert('lock B');
|
|
assert('lock C');
|
|
|
|
# Independent locks:
|
|
new();
|
|
lock_file_full($name, 10, 0, sub {
|
|
ran('lock A');
|
|
# locks file "${name}2"
|
|
lock_file_full($name.2, 10, 0, sub { ran('lock B') });
|
|
assert('lock B');
|
|
ran('lock C');
|
|
});
|
|
assert('lock A');
|
|
assert('lock B');
|
|
assert('lock C');
|
|
|
|
# Does it actually lock? (shared=0)
|
|
# Can we get two simultaneous shared locks? (shared=1)
|
|
sub forktest1($) {
|
|
my ($shared) = @_;
|
|
new();
|
|
# socket pair for synchronization
|
|
socketpair(my $fmain, my $fother, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
|
|
or die "socketpair(): $!\n";
|
|
forked sub {
|
|
# other side
|
|
close($fmain);
|
|
my $line;
|
|
lock_file_full($name, 60, $shared, sub {
|
|
ran('other side');
|
|
# tell parent we've acquired the lock
|
|
print {$fother} "1\n";
|
|
$fother->flush();
|
|
# wait for parent to be done trying to lock
|
|
$line = <$fother>;
|
|
});
|
|
die $@ if $@;
|
|
die "parent failed\n" if !$line || $line ne "2\n";
|
|
assert('other side');
|
|
}, sub {
|
|
# main process
|
|
# Wait for our child to lock:
|
|
close($fother);
|
|
my $line = <$fmain>;
|
|
die "child failed to acquire a lock\n" if !$line || $line ne "1\n";
|
|
lock_file_full($name, 1, $shared, sub {
|
|
ran('local side');
|
|
});
|
|
if ($shared) {
|
|
assert('local side');
|
|
} else {
|
|
assert_not('local side');
|
|
}
|
|
print {$fmain} "2\n";
|
|
$fmain->flush();
|
|
};
|
|
close($fmain);
|
|
}
|
|
forktest1(0);
|
|
forktest1(1);
|