Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Nov 2013 23:15:46 +0200
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Vitaly Magerya <vmagerya@gmail.com>
Cc:        freebsd-hackers@freebsd.org, davidxu@freebsd.org, threads@freebsd.org
Subject:   Re: Problem with signal 0 being delivered to SIGUSR1 handler
Message-ID:  <20131121211546.GQ59496@kib.kiev.ua>
In-Reply-To: <528DFEE6.6020504@gmail.com>
References:  <528DFEE6.6020504@gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--JeIqLcbgB5JjL5AU
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Thu, Nov 21, 2013 at 02:39:02PM +0200, Vitaly Magerya wrote:
> Hi, folks. I'm investigating a test case failure that devel/boehm-gc
> has on recent FreeBSD releases. The problem is that a signal
> handler registered for SIGUSR1 is sometimes called with signum=3D0,
> which should not be possible under any conditions.
>=20
> Here's a simple test case that demonstrates this behavior:
>=20
> /* Compile with 'c99 -o example example.c -pthread'
>  */
> #include <pthread.h>
> #include <signal.h>
> #include <stdio.h>
> #include <stdlib.h>
>=20
> void signal_handler(int signum, siginfo_t *si, void *context) {
>     if (signum !=3D SIGUSR1) {
>         printf("bad signal, signum=3D%d\n", signum);
>         exit(1);
>     }
> }
>=20
> void *thread_func(void *arg) {
>     return arg;
> }
>=20
> int main(void) {
>     struct sigaction sa =3D { 0 };
>     sa.sa_flags =3D SA_SIGINFO;
>     sa.sa_sigaction =3D signal_handler;
>     if (sigfillset(&sa.sa_mask) !=3D 0) abort();
>     if (sigaction(SIGUSR1, &sa, NULL) !=3D 0) abort();
>     for (int i =3D 0; i < 10000; i++) {
>         pthread_t t;
>         pthread_create(&t, NULL, thread_func, NULL);
>         pthread_kill(t, SIGUSR1);
Side note.  pthread_kill(3) call behaviour is undefined if pthread_create(3)
in the line before failed.

>     }
>     return 0;
> }
>=20
> Under FreeBSD 9.2-RELEASE amd64 I pretty consistently get
> "signum=3D0" from this program, but you may need to run it a few
> times or increase the number of iterations to see the same.
>=20
> Interestingly enough, I don't see this behavior under 9.0-RELEASE.
>=20
> So, any ideas what the problem here is?

It happens when libthr deferred signal handling path is taken for signal
delivery and for some reason the code inside the deferred path called
into rtld for symbol binding. Than, rtld lock is locked, some code in
rtld is executed, and rtld lock is unlocked. Unlock causes _thr_ast()
run, which results in the nested check_deferred_signal() execution.
The check_deferred_signal() clearks si_signo, so on return the same
signal is delivered one more time, but is advertized as signo zero.

The _thr_rtld_init() approach of doing dummy calls does not really work,
since it is not practically possible to enumerate the symbols needed
during signal delivery.

My first attempt to fix this was to increment curthread->critical_count
around the calls to check_* functions in the _thr_ast(), but it causes
reverse problem of losing _thr_ast() runs on unlock.

I ended up with the flag to indicate that deferred delivery is running,
so check_deferred_signal() should avoid doing anything. A delicate
moment is that user signal handler is allowed to modify the passed
machine context to result the return from the signal handler to cause
arbitrary jump, or just do longjmp(). For this case, I also clear the
flag in thr_sighandler(), since kernel signal delivery means that nested
delivery code should not run right now.

Please try this.

diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_privat=
e.h
index 83a02b5..c6651cd 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -433,6 +433,9 @@ struct pthread {
 	/* the sigaction should be used for deferred signal. */
 	struct sigaction	deferred_sigact;
=20
+	/* deferred signal delivery is performed, do not reenter. */
+	int			deferred_run;
+
 	/* Force new thread to exit. */
 	int			force_exit;
=20
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c
index 415ddb0..57c9406 100644
--- a/lib/libthr/thread/thr_sig.c
+++ b/lib/libthr/thread/thr_sig.c
@@ -162,6 +162,7 @@ thr_sighandler(int sig, siginfo_t *info, void *_ucp)
 	act =3D _thr_sigact[sig-1].sigact;
 	_thr_rwl_unlock(&_thr_sigact[sig-1].lock);
 	errno =3D err;
+	curthread->deferred_run =3D 0;
=20
 	/*
 	 * if a thread is in critical region, for example it holds low level lock=
s,
@@ -320,14 +321,18 @@ check_deferred_signal(struct pthread *curthread)
 	siginfo_t info;
 	int uc_len;
=20
-	if (__predict_true(curthread->deferred_siginfo.si_signo =3D=3D 0))
+	if (__predict_true(curthread->deferred_siginfo.si_signo =3D=3D 0 ||
+	    curthread->deferred_run))
 		return;
=20
+	curthread->deferred_run =3D 1;
 	uc_len =3D __getcontextx_size();
 	uc =3D alloca(uc_len);
 	getcontext(uc);
-	if (curthread->deferred_siginfo.si_signo =3D=3D 0)
+	if (curthread->deferred_siginfo.si_signo =3D=3D 0) {
+		curthread->deferred_run =3D 0;
 		return;
+	}
 	__fillcontextx2((char *)uc);
 	act =3D curthread->deferred_sigact;
 	uc->uc_sigmask =3D curthread->deferred_sigmask;

--JeIqLcbgB5JjL5AU
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (FreeBSD)

iQIcBAEBAgAGBQJSjngBAAoJEJDCuSvBvK1BKx0QAJjAmJSh9i2IQC6e8pF1QXJG
P6lTmX3WpLVdnPAA5ord/KoiBCaNJQ4w2YaEWOzuP3o4GHX70dYLY9HWHuwgMhei
NzS+xOCdzZcPDI68ZghJ/N/67oJSlC9i/N4RLdgDqaBpElYrOKk1pmXqpQ/216op
XinMrpR5oR4TvXJ80dNCsGzc5xQ0J9LW5TjYf3rzHSJSaYWO6jSIUwDrb6kLxtVA
7enT9j8rMO+HbXgWNNcXMBTAfo+2PabK/33twemiX7dbzGTQapbVK6RU9MYBYO0N
2Sa6YI0Zd5SFJyXLLggPi/Qop/mGIrsCgd2ICOsGnBYtc5qGpeFZkbKB8OnRdw02
u4HWokfnaE6eH+ktipA9+nbpAGL3MCsHgSZBLoIKDX0YWmqvEMM6wHdrJWWwIfEB
/YJp8iHGwbrjtXx4ddUqa/30BRU1HzDImPafbAOvVdjLKFQozpHPJFwRhX+2NEA/
TA7PlXXLDVXc4wE7eP0Lo/8Vpnhk/Wv5Xz2a97F6IzdeOZpbuQwLaFf5eOJD77z9
8J1hhwE//c7nlk+9ovvRvqOdXyGeQSZaW22BRNu4VjYW/Cs5uaSGBCfPKJe99DGx
4tl3vaP28nnhQRH3reqyE/fJtfaJkMrGccO2EYVbkibaLWMEMBmLQ57no4TXrdWS
BU5IUgDGkfqq4DKVpL87
=jCRC
-----END PGP SIGNATURE-----

--JeIqLcbgB5JjL5AU--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20131121211546.GQ59496>