|  | /* Copyright (C) 2003-2016 Free Software Foundation, Inc. | 
|  | This file is part of the GNU C Library. | 
|  | Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. | 
|  |  | 
|  | The GNU C Library is free software; you can redistribute it and/or | 
|  | modify it under the terms of the GNU Lesser General Public | 
|  | License as published by the Free Software Foundation; either | 
|  | version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | The GNU C Library is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | Lesser General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU Lesser General Public | 
|  | License along with the GNU C Library; if not, see | 
|  | <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include <pthread.h> | 
|  | #include <signal.h> | 
|  | #include <stdint.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  |  | 
|  | #ifdef SIGRTMIN | 
|  |  | 
|  | # define N 2 | 
|  | static pthread_barrier_t bar; | 
|  | static struct | 
|  | { | 
|  | void *p; | 
|  | pthread_t s; | 
|  | } ti[N]; | 
|  | static int sig1; | 
|  |  | 
|  |  | 
|  | static void | 
|  | handler (int sig) | 
|  | { | 
|  | pthread_t self = pthread_self (); | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < N; ++i) | 
|  | if (ti[i].s == self) | 
|  | { | 
|  | if ((uintptr_t) ti[i].p <= (uintptr_t) &self | 
|  | && (uintptr_t) ti[i].p + 2 * MINSIGSTKSZ > (uintptr_t) &self) | 
|  | { | 
|  | puts ("alt stack not used"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | printf ("thread %zu used alt stack for signal %d\n", i, sig); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | puts ("handler: thread not found"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void * | 
|  | tf (void *arg) | 
|  | { | 
|  | size_t nr = (uintptr_t) arg; | 
|  | if (nr >= N) | 
|  | { | 
|  | puts ("wrong nr parameter"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | sigset_t ss; | 
|  | sigemptyset (&ss); | 
|  | size_t i; | 
|  | for (i = 0; i < N; ++i) | 
|  | if (i != nr) | 
|  | if (sigaddset (&ss, sig1 + i) != 0) | 
|  | { | 
|  | puts ("tf: sigaddset failed"); | 
|  | exit (1); | 
|  | } | 
|  | if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) | 
|  | { | 
|  | puts ("tf: sigmask failed"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | void *p = malloc (2 * MINSIGSTKSZ); | 
|  | if (p == NULL) | 
|  | { | 
|  | puts ("tf: malloc failed"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | stack_t s; | 
|  | s.ss_sp = p; | 
|  | s.ss_size = 2 * MINSIGSTKSZ; | 
|  | s.ss_flags = 0; | 
|  | if (sigaltstack (&s, NULL) != 0) | 
|  | { | 
|  | puts ("tf: sigaltstack failed"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | ti[nr].p = p; | 
|  | ti[nr].s = pthread_self (); | 
|  |  | 
|  | pthread_barrier_wait (&bar); | 
|  |  | 
|  | pthread_barrier_wait (&bar); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int | 
|  | do_test (void) | 
|  | { | 
|  | sig1 = SIGRTMIN; | 
|  | if (sig1 + N > SIGRTMAX) | 
|  | { | 
|  | puts ("too few RT signals"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | struct sigaction sa; | 
|  | sa.sa_handler = handler; | 
|  | sa.sa_flags = 0; | 
|  | sigemptyset (&sa.sa_mask); | 
|  |  | 
|  | if (sigaction (sig1, &sa, NULL) != 0 | 
|  | || sigaction (sig1 + 1, &sa, NULL) != 0 | 
|  | || sigaction (sig1 + 2, &sa, NULL) != 0) | 
|  | { | 
|  | puts ("sigaction failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (pthread_barrier_init (&bar, NULL, 1 + N) != 0) | 
|  | { | 
|  | puts ("barrier_init failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | pthread_t th[N]; | 
|  | size_t i; | 
|  | for (i = 0; i < N; ++i) | 
|  | if (pthread_create (&th[i], NULL, tf, (void *) (long int) i) != 0) | 
|  | { | 
|  | puts ("create failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Block the three signals.  */ | 
|  | sigset_t ss; | 
|  | sigemptyset (&ss); | 
|  | for (i = 0; i <= N; ++i) | 
|  | sigaddset (&ss, sig1 + i); | 
|  | if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) | 
|  | { | 
|  | puts ("main: sigmask failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | pthread_barrier_wait (&bar); | 
|  |  | 
|  | /* Send some signals.  */ | 
|  | pid_t me = getpid (); | 
|  | kill (me, sig1 + N); | 
|  | for (i = 0; i < N; ++i) | 
|  | kill (me, sig1 + i); | 
|  | kill (me, sig1 + N); | 
|  |  | 
|  | /* Give the signals a chance to be worked on.  */ | 
|  | sleep (1); | 
|  |  | 
|  | pthread_barrier_wait (&bar); | 
|  |  | 
|  | for (i = 0; i < N; ++i) | 
|  | if (pthread_join (th[i], NULL) != 0) | 
|  | { | 
|  | puts ("join failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | # define TEST_FUNCTION do_test () | 
|  |  | 
|  | #else | 
|  | # define TEST_FUNCTION 0 | 
|  | #endif | 
|  | #include "../test-skeleton.c" |