(root)/
glibc-2.38/
nptl/
tst-signal3.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <pthread.h>
      20  #include <semaphore.h>
      21  #include <signal.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <unistd.h>
      25  
      26  
      27  #ifdef SIGRTMIN
      28  
      29  /* Number of different signals to use.  Also is the number of threads.  */
      30  # define N 10
      31  /* Maximum number of threads in flight at any one time.  */
      32  # define INFLIGHT 5
      33  /* Number of signals sent in total.  */
      34  # define ROUNDS 10000
      35  
      36  
      37  static int received[N][N];
      38  static int nsig[N];
      39  static pthread_t th[N];
      40  static sem_t sem;
      41  static pthread_mutex_t lock[N];
      42  static pthread_t th_main;
      43  static int sig0;
      44  
      45  static void
      46  handler (int sig)
      47  {
      48    int i;
      49    for (i = 0; i < N; ++i)
      50      if (pthread_equal (pthread_self (), th[i]))
      51        break;
      52  
      53    if (i == N)
      54      {
      55        if (pthread_equal (pthread_self (), th_main))
      56  	puts ("signal received by main thread");
      57        else
      58  	printf ("signal received by unknown thread (%lx)\n",
      59  		(unsigned long int) pthread_self ());
      60        exit (1);
      61      }
      62  
      63    ++received[i][sig - sig0];
      64  
      65    sem_post (&sem);
      66  }
      67  
      68  
      69  static void *
      70  tf (void *arg)
      71  {
      72    int idx = (long int) arg;
      73  
      74    sigset_t ss;
      75    sigemptyset (&ss);
      76  
      77    int i;
      78    for (i = 0; i <= idx; ++i)
      79      sigaddset (&ss, sig0 + i);
      80  
      81    if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0)
      82      {
      83        printf ("thread %d: pthread_sigmask failed\n", i);
      84        exit (1);
      85      }
      86  
      87    pthread_mutex_lock (&lock[idx]);
      88  
      89    return NULL;
      90  }
      91  
      92  
      93  static int
      94  do_test (void)
      95  {
      96    /* Block all signals.  */
      97    sigset_t ss;
      98    sigfillset (&ss);
      99  
     100    th_main = pthread_self ();
     101  
     102    sig0 = SIGRTMIN;
     103  
     104    if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
     105      {
     106        puts ("1st pthread_sigmask failed");
     107        exit (1);
     108      }
     109  
     110    /* Install the handler.  */
     111    int i;
     112    for (i = 0; i < N; ++i)
     113      {
     114        struct sigaction sa =
     115  	{
     116  	  .sa_handler = handler,
     117  	  .sa_flags = 0
     118  	};
     119        sigfillset (&sa.sa_mask);
     120  
     121        if (sigaction (sig0 + i, &sa, NULL) != 0)
     122  	{
     123  	  printf ("sigaction for signal %d failed\n", i);
     124  	  exit (1);
     125  	}
     126      }
     127  
     128    if (sem_init (&sem, 0, INFLIGHT) != 0)
     129      {
     130        puts ("sem_init failed");
     131        exit (1);
     132      }
     133  
     134    pthread_attr_t a;
     135  
     136    if (pthread_attr_init (&a) != 0)
     137      {
     138        puts ("attr_init failed");
     139        exit (1);
     140      }
     141  
     142    if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
     143      {
     144        puts ("attr_setstacksize failed");
     145        return 1;
     146      }
     147  
     148    for (i = 0; i < N; ++i)
     149      {
     150        if (pthread_mutex_init (&lock[i], NULL) != 0)
     151  	{
     152  	  printf ("mutex_init[%d] failed\n", i);
     153  	}
     154  
     155        if (pthread_mutex_lock (&lock[i]) != 0)
     156  	{
     157  	  printf ("mutex_lock[%d] failed\n", i);
     158  	}
     159  
     160        if (pthread_create (&th[i], &a, tf, (void *) (long int) i) != 0)
     161  	{
     162  	  printf ("create of thread %d failed\n", i);
     163  	  exit (1);
     164  	}
     165      }
     166  
     167    if (pthread_attr_destroy (&a) != 0)
     168      {
     169        puts ("attr_destroy failed");
     170        exit (1);
     171      }
     172  
     173    int result = 0;
     174    unsigned int r = 42;
     175    pid_t pid = getpid ();
     176  
     177    for (i = 0; i < ROUNDS; ++i)
     178      {
     179        if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0)
     180  	{
     181  	  printf ("sem_wait round %d failed: %m\n", i);
     182  	  exit (1);
     183  	}
     184  
     185        int s = rand_r (&r) % N;
     186  
     187        kill (pid, sig0 + s);
     188      }
     189  
     190    void *status;
     191    for (i = 0; i < N; ++i)
     192      {
     193        if (pthread_mutex_unlock (&lock[i]) != 0)
     194  	{
     195  	  printf ("unlock %d failed\n", i);
     196  	  exit (1);
     197  	}
     198  
     199        if (pthread_join (th[i], &status) != 0)
     200  	{
     201  	  printf ("join %d failed\n", i);
     202  	  result = 1;
     203  	}
     204        else if (status != NULL)
     205  	{
     206  	  printf ("%d: result != NULL\n", i);
     207  	  result = 1;
     208  	}
     209      }
     210  
     211    int total = 0;
     212    for (i = 0; i < N; ++i)
     213      {
     214        int j;
     215  
     216        for (j = 0; j <= i; ++j)
     217  	total += received[i][j];
     218  
     219        for (j = i + 1; j < N; ++j)
     220  	if (received[i][j] != 0)
     221  	  {
     222  	    printf ("thread %d received signal SIGRTMIN+%d\n", i, j);
     223  	    result = 1;
     224  	  }
     225      }
     226  
     227    if (total != ROUNDS)
     228      {
     229        printf ("total number of handled signals is %d, expected %d\n",
     230  	      total, ROUNDS);
     231        result = 1;
     232      }
     233  
     234    printf ("A total of %d signals sent and received\n", total);
     235    for (i = 0; i < N; ++i)
     236      {
     237        printf ("thread %2d:", i);
     238  
     239        int j;
     240        for (j = 0; j <= i; ++j)
     241  	{
     242  	  printf (" %5d", received[i][j]);
     243  	  nsig[j] += received[i][j];
     244  	}
     245  
     246        putchar ('\n');
     247  
     248      }
     249  
     250    printf ("\nTotal    :");
     251    for (i = 0; i < N; ++i)
     252      printf (" %5d", nsig[i]);
     253    putchar ('\n');
     254  
     255    return result;
     256  }
     257  
     258  # define TEST_FUNCTION do_test ()
     259  
     260  #else
     261  # define TEST_FUNCTION 0
     262  #endif
     263  
     264  #include "../test-skeleton.c"