2017-05-11 13:40:02 +03:00
#!/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.$$-" ;
# 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 } ;
}
# 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" ;
2024-11-14 18:07:34 +03:00
my $ other = 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' ) ;
return ;
2017-05-11 13:40:02 +03:00
} ;
2024-11-14 18:07:34 +03:00
my $ main = 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 ( ) ;
} ;
PVE::Tools:: run_fork ( $ other , { afterfork = > $ main } ) ;
2017-05-11 13:40:02 +03:00
close ( $ fmain ) ;
}
2024-11-14 18:07:32 +03:00
eval {
# 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)
forktest1 ( 0 ) ;
forktest1 ( 1 ) ;
} ;
my $ err = $@ ;
system ( "rm $name*" ) ;
die $ err if $ err ;