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