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