You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
4.6 KiB
109 lines
4.6 KiB
From 61b1834c5366c78f0e4d3b21a142d7dd6d6322c1 Mon Sep 17 00:00:00 2001
|
|
From: Fabian Vogt <fvogt@suse.de>
|
|
Date: Tue, 13 Apr 2021 15:41:00 +0200
|
|
Subject: [PATCH] signalblocker: Also block SIGCHLD
|
|
|
|
The perl-unaware threads created by OpenCV also crash when they encounter a
|
|
SIGCHLD signal, which happens by using perl's "system" function for instance.
|
|
---
|
|
signalblocker.pm | 22 +++++++++++-----------
|
|
t/28-signalblocker.t | 14 ++++++++++++--
|
|
2 files changed, 23 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/signalblocker.pm b/signalblocker.pm
|
|
index 1ff3652c..dea56e12 100644
|
|
--- a/signalblocker.pm
|
|
+++ b/signalblocker.pm
|
|
@@ -1,4 +1,4 @@
|
|
-# Copyright © 2020 SUSE LLC
|
|
+# Copyright © 2021 SUSE LLC
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -19,23 +19,23 @@ use Mojo::Base -base;
|
|
use bmwqemu;
|
|
use POSIX ':signal_h';
|
|
|
|
-# OpenCV forks a lot of threads and the TERM signal we may get from the
|
|
-# parent process would be delivered to an undefined thread. But as those
|
|
-# threads do not have a perl interpreter, the perl signal handler (we set
|
|
-# later) would crash. So we need to block the TERM signal in the forked
|
|
-# processes before we set the signal handler of our choice.
|
|
+# OpenCV forks a lot of threads and the signals we may get (TERM from the
|
|
+# parent, CHLD from children) would be delivered to an undefined thread.
|
|
+# But as those threads do not have a perl interpreter, the perl signal
|
|
+# handler would crash. We need to block those signals in those threads, so
|
|
+# that they get delivered only to those threads which can handle it.
|
|
|
|
sub new {
|
|
my ($class, @args) = @_;
|
|
|
|
# block signals
|
|
- bmwqemu::diag('Blocking SIGTERM');
|
|
+ bmwqemu::diag('Blocking SIGCHLD and SIGCHLD');
|
|
my %old_sig = %SIG;
|
|
$SIG{TERM} = 'IGNORE';
|
|
$SIG{INT} = 'IGNORE';
|
|
$SIG{HUP} = 'IGNORE';
|
|
- my $sigset = POSIX::SigSet->new(SIGTERM);
|
|
- die "Could not block SIGTERM\n" unless defined sigprocmask(SIG_BLOCK, $sigset, undef);
|
|
+ my $sigset = POSIX::SigSet->new(SIGCHLD, SIGTERM);
|
|
+ die "Could not block SIGCHLD and SIGTERM\n" unless defined sigprocmask(SIG_BLOCK, $sigset, undef);
|
|
|
|
# create the actual object holding the information to restore the previous state
|
|
my $self = $class->SUPER::new(@args);
|
|
@@ -48,8 +48,8 @@ sub DESTROY {
|
|
my ($self) = @_;
|
|
|
|
# set back signal handling to default to be able to terminate properly
|
|
- bmwqemu::diag('Unblocking SIGTERM');
|
|
- die "Could not unblock SIGTERM\n" unless defined sigprocmask(SIG_UNBLOCK, $self->{_sigset}, undef);
|
|
+ bmwqemu::diag('Unblocking SIGCHLD and SIGTERM');
|
|
+ die "Could not unblock SIGCHLD and SIGTERM\n" unless defined sigprocmask(SIG_UNBLOCK, $self->{_sigset}, undef);
|
|
%SIG = %{$self->{_old_sig}};
|
|
}
|
|
|
|
diff --git a/t/28-signalblocker.t b/t/28-signalblocker.t
|
|
index 31ddb6f6..9e1a99a5 100755
|
|
--- a/t/28-signalblocker.t
|
|
+++ b/t/28-signalblocker.t
|
|
@@ -1,6 +1,6 @@
|
|
#!/usr/bin/perl
|
|
#
|
|
-# Copyright (c) 2020 SUSE LLC
|
|
+# Copyright (c) 2021 SUSE LLC
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -44,9 +44,13 @@ my $no_signal_blocker = $ENV{OS_AUTOINST_TEST_NO_SIGNAL_BLOCKER};
|
|
sub thread_count { scalar split("\n", `ps huH p $$`) }
|
|
is(my $last_thread_count = thread_count, 1, 'initially one thread');
|
|
|
|
-# count SIGTERMs we receive; this handler should work after creating/destroying the signal blocker
|
|
+# count SIGTERMs we receive; those handlers should work after creating/destroying the signal blocker
|
|
+# Note that without these handlers, there won't be any crash in Perl's signal handler as it's never
|
|
+# registered for those signals.
|
|
my $received_sigterm = 0;
|
|
$SIG{TERM} = sub { $received_sigterm += 1; note "received SIGTERM $received_sigterm"; };
|
|
+my $received_sigchld = 0;
|
|
+$SIG{CHLD} = sub { $received_sigchld += 1; note "received SIGCHLD $received_sigchld"; };
|
|
|
|
# initialize OpenCV via signalblocker and create_threads
|
|
{
|
|
@@ -75,6 +79,12 @@ waitpid $fork, 0;
|
|
note 'waiting for at least one signal to be handled' and sleep .2 until $received_sigterm >= 1 || ($timeout -= .2) < 0;
|
|
note "handled $received_sigterm TERM signals";
|
|
ok($received_sigterm > 0, "received SIGTERM $received_sigterm times; no crashes after at least 200 ms idling time");
|
|
+
|
|
+$received_sigchld = 0;
|
|
+# 0 here means WIFEXITED and WEXITSTATUS == 0
|
|
+cmp_ok(system("true"), '==', 0, 'system returns exit status');
|
|
+is($received_sigchld, 1, 'got SIGCHLD after system');
|
|
+
|
|
cmp_ok(thread_count, '<=', $last_thread_count, 'still no new threads after sending signals');
|
|
|
|
done_testing;
|
|
--
|
|
2.31.1
|
|
|