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