From 618d56c7ac8bd8cd701344a0eaca8373a78dea95 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 23 Apr 2018 21:59:05 +0200
Subject: [PATCH] test/udev-test.pl: allow concurrent additions and removals
Allow testing cases where multiple devices are added and removed
simultaneously. Tests are started as synchronously as possible using a
semaphore, in order to test possible race conditions. If this isn't desired,
the test parameter "sleep_us" can be set to the number of microseconds to wait
between udev invocations.
(cherry picked from commit 09a4062d70b3a10d022e40066e2adf09df05bbbc)
Related: #1642728
---
test/udev-test.pl | 90 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 72 insertions(+), 18 deletions(-)
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 8b5a97ad61..db25ef13c1 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -18,6 +18,10 @@
use warnings;
use strict;
+use POSIX qw(WIFEXITED WEXITSTATUS);
+use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
+use IPC::Semaphore;
+use Time::HiRes qw(usleep);
my $udev_bin = "./test-udev";
my $valgrind = 0;
@@ -2210,6 +2214,8 @@ sub check_add {
sleep(1);
}
}
+
+ print "device \'$device->{devpath}\' expecting node/link \'$device->{exp_name}\'\n";
if ((-e "$udev_dev/$device->{exp_name}") ||
(-l "$udev_dev/$device->{exp_name}")) {
@@ -2257,21 +2263,72 @@ sub check_remove {
}
}
+sub run_udev {
+ my ($action, $dev, $sleep_us, $sema) = @_;
+
+ # Notify main process that this worker has started
+ $sema->op(0, 1, 0);
+
+ # Wait for start
+ $sema->op(0, 0, 0);
+ usleep($sleep_us) if defined ($sleep_us);
+ my $rc = udev($action, $dev->{devpath});
+ exit $rc;
+}
+
+sub fork_and_run_udev {
+ my ($action, $rules, $sema) = @_;
+ my @devices = @{$rules->{devices}};
+ my $dev;
+ my $k = 0;
+
+ $sema->setval(0, 1);
+ foreach $dev (@devices) {
+ my $pid = fork();
+
+ if (!$pid) {
+ run_udev($action, $dev,
+ defined($rules->{sleep_us}) ? $k * $rules->{sleep_us} : undef,
+ $sema);
+ } else {
+ $dev->{pid} = $pid;
+ }
+ $k++;
+ }
+
+ # This operation waits for all workers to become ready, and
+ # starts them off when that's the case.
+ $sema->op(0, -($#devices + 2), 0);
+
+ foreach $dev (@devices) {
+ my $rc;
+ my $pid;
+
+ $pid = waitpid($dev->{pid}, 0);
+ if ($pid == -1) {
+ print "error waiting for pid dev->{pid}\n";
+ $error += 1;
+ }
+ if (WIFEXITED($?)) {
+ $rc = WEXITSTATUS($?);
+
+ if ($rc) {
+ print "$udev_bin $action for $dev->{devpath} failed with code $rc\n";
+ $error += 1;
+ }
+ }
+ }
+}
+
sub run_test {
- my ($rules, $number) = @_;
+ my ($rules, $number, $sema) = @_;
my $rc;
my @devices = @{$rules->{devices}};
print "TEST $number: $rules->{desc}\n";
create_rules(\$rules->{rules});
- foreach my $dev (@devices) {
- print "device \'$dev->{devpath}\' expecting node/link \'$dev->{exp_name}\'\n";
- $rc = udev("add", $dev->{devpath});
- if ($rc != 0) {
- print "$udev_bin add failed with code $rc\n";
- $error++;
- }
- }
+
+ fork_and_run_udev("add", $rules, $sema);
foreach my $dev (@devices) {
check_add($dev);
@@ -2282,13 +2339,8 @@ sub run_test {
return;
}
- foreach my $dev (@devices) {
- $rc = udev("remove", $dev->{devpath});
- if ($rc != 0) {
- print "$udev_bin remove failed with code $rc\n";
- $error++;
- }
- }
+ fork_and_run_udev("remove", $rules, $sema);
+
foreach my $dev (@devices) {
check_remove($dev);
}
@@ -2350,12 +2402,13 @@ foreach my $arg (@ARGV) {
push(@list, $arg);
}
}
+my $sema = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR | IPC_CREAT);
if ($list[0]) {
foreach my $arg (@list) {
if (defined($tests[$arg-1]->{desc})) {
print "udev-test will run test number $arg:\n\n";
- run_test($tests[$arg-1], $arg);
+ run_test($tests[$arg-1], $arg, $sema);
} else {
print "test does not exist.\n";
}
@@ -2365,11 +2418,12 @@ if ($list[0]) {
print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
foreach my $rules (@tests) {
- run_test($rules, $test_num);
+ run_test($rules, $test_num, $sema);
$test_num++;
}
}
+$sema->remove;
print "$error errors occurred\n\n";
cleanup();