]> git.proxmox.com Git - pve-common.git/blame - test/lock_file.pl
cgroup: cpu quota: fix resetting period length for v1
[pve-common.git] / test / lock_file.pl
CommitLineData
d9f86d0d
WB
1#!/usr/bin/perl
2
3use lib '../src';
4use strict;
5use warnings;
6
7use Socket;
8use POSIX (); # don't import assert()
9
10use PVE::Tools 'lock_file_full';
11
12my $name = "test.lockfile.$$-";
13
14END {
15 system("rm $name*");
16};
17
18# Utilities:
19
20sub forked($$) {
21 my ($code1, $code2) = @_;
22
23 pipe(my $except_r, my $except_w) or die "pipe: $!\n";
24
25 my $pid = fork();
26 die "fork failed: $!\n" if !defined($pid);
27
28 if ($pid == 0) {
29 close($except_r);
30 eval { $code1->() };
31 if ($@) {
32 print {$except_w} $@;
33 $except_w->flush();
34 POSIX::_exit(1);
35 }
36 POSIX::_exit(0);
37 }
38 close($except_w);
39
40 eval { $code2->() };
41 my $err = $@;
42 if ($err) {
43 kill(15, $pid);
44 } else {
45 my $err = do { local $/ = undef; <$except_r> };
46 }
47 die "interrupted\n" if waitpid($pid, 0) != $pid;
48 die $err if $err;
49
50 # Check exit code:
51 my $status = POSIX::WEXITSTATUS($?);
52 if ($? == -1) {
53 die "failed to execute\n";
54 } elsif (POSIX::WIFSIGNALED($?)) {
55 my $sig = POSIX::WTERMSIG($?);
56 die "got signal $sig\n";
57 } elsif ($status != 0) {
58 die "exit code $status\n";
59 }
60}
61
62# Book-keeping:
63
64my %_ran;
65sub new {
66 %_ran = ();
67}
68sub ran {
69 my ($what) = @_;
70 $_ran{$what} = 1;
71}
72sub assert {
73 my ($what) = @_;
74 die "code didn't run: $what\n" if !$_ran{$what};
75}
76sub assert_not {
77 my ($what) = @_;
78 die "code shouldn't have run: $what\n" if $_ran{$what};
79}
80
81# Regular lock:
82new();
83lock_file_full($name, 10, 0, sub { ran('single lock') });
84assert('single lock');
85
86# Lock multiple times in a row:
87new();
88lock_file_full($name, 10, 0, sub { ran('lock A') });
89assert('lock A');
90lock_file_full($name, 10, 0, sub { ran('lock B') });
91assert('lock B');
92
93# Nested lock:
94new();
95lock_file_full($name, 10, 0, sub {
96 ran('lock A');
97 lock_file_full($name, 10, 0, sub { ran('lock B') });
98 assert('lock B');
99 ran('lock C');
100});
101assert('lock A');
102assert('lock B');
103assert('lock C');
104
105# Independent locks:
106new();
107lock_file_full($name, 10, 0, sub {
108 ran('lock A');
109 # locks file "${name}2"
110 lock_file_full($name.2, 10, 0, sub { ran('lock B') });
111 assert('lock B');
112 ran('lock C');
113});
114assert('lock A');
115assert('lock B');
116assert('lock C');
117
118# Does it actually lock? (shared=0)
119# Can we get two simultaneous shared locks? (shared=1)
120sub forktest1($) {
121 my ($shared) = @_;
122 new();
123 # socket pair for synchronization
124 socketpair(my $fmain, my $fother, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
125 or die "socketpair(): $!\n";
126 forked sub {
127 # other side
128 close($fmain);
129 my $line;
130 lock_file_full($name, 60, $shared, sub {
131 ran('other side');
132 # tell parent we've acquired the lock
133 print {$fother} "1\n";
134 $fother->flush();
135 # wait for parent to be done trying to lock
136 $line = <$fother>;
137 });
138 die $@ if $@;
139 die "parent failed\n" if !$line || $line ne "2\n";
140 assert('other side');
141 }, sub {
142 # main process
143 # Wait for our child to lock:
144 close($fother);
145 my $line = <$fmain>;
146 die "child failed to acquire a lock\n" if !$line || $line ne "1\n";
147 lock_file_full($name, 1, $shared, sub {
148 ran('local side');
149 });
150 if ($shared) {
151 assert('local side');
152 } else {
153 assert_not('local side');
154 }
155 print {$fmain} "2\n";
156 $fmain->flush();
157 };
158 close($fmain);
159}
160forktest1(0);
161forktest1(1);