(root)/
glibc-2.38/
nptl/
tst-mutex8.c
       1  /* Copyright (C) 2003-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  /* This test checks behavior not required by POSIX.  */
      19  #include <errno.h>
      20  #include <pthread.h>
      21  #include <stdbool.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <unistd.h>
      25  #include <elf/dl-tunables.h>
      26  
      27  static pthread_mutex_t *m;
      28  static pthread_barrier_t b;
      29  static pthread_cond_t c;
      30  static bool done;
      31  
      32  
      33  static void
      34  cl (void *arg)
      35  {
      36    if (pthread_mutex_unlock (m) != 0)
      37      {
      38        puts ("cl: mutex_unlocked failed");
      39        exit (1);
      40      }
      41  }
      42  
      43  
      44  static void *
      45  tf (void *arg)
      46  {
      47    if (pthread_mutex_lock (m) != 0)
      48      {
      49        puts ("tf: mutex_lock failed");
      50        return (void *) 1l;
      51      }
      52  
      53    int e = pthread_barrier_wait (&b);
      54    if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
      55      {
      56        puts ("barrier_wait failed");
      57        return (void *) 1l;
      58      }
      59  
      60    if (arg == NULL)
      61      do
      62        if (pthread_cond_wait (&c, m) != 0)
      63  	{
      64  	  puts ("tf: cond_wait failed");
      65  	  return (void *) 1l;
      66  	}
      67      while (! done);
      68    else
      69      do
      70        {
      71  	pthread_cleanup_push (cl, NULL);
      72  
      73  	if (pthread_cond_wait (&c, m) != 0)
      74  	  {
      75  	    puts ("tf: cond_wait failed");
      76  	    return (void *) 1l;
      77  	  }
      78  
      79  	pthread_cleanup_pop (0);
      80        }
      81      while (! done);
      82  
      83    if (pthread_mutex_unlock (m) != 0)
      84      {
      85        puts ("tf: mutex_unlock failed");
      86        return (void *) 1l;
      87      }
      88  
      89    return NULL;
      90  }
      91  
      92  
      93  static int
      94  check_type (const char *mas, pthread_mutexattr_t *ma)
      95  {
      96    int e;
      97  
      98    /* Check if a mutex will be elided.  Lock elision can only be activated via
      99       the tunables framework.  By default, lock elision is disabled.  */
     100    bool assume_elided_mutex = false;
     101    int ma_type = PTHREAD_MUTEX_TIMED_NP;
     102    if (ma != NULL)
     103      {
     104        e = pthread_mutexattr_gettype (ma, &ma_type);
     105        if (e != 0)
     106  	{
     107  	  printf ("pthread_mutexattr_gettype failed with %d (%m)\n", e);
     108  	  return 1;
     109  	}
     110      }
     111    if (ma_type == PTHREAD_MUTEX_TIMED_NP)
     112      {
     113        /* This type of mutex can be elided if elision is enabled via the tunables
     114  	 framework.  Some tests below are failing if the mutex is elided.
     115  	 Thus we only run those if we assume that the mutex won't be elided.  */
     116        if (TUNABLE_GET_FULL (glibc, elision, enable, int32_t, NULL) == 1)
     117  	assume_elided_mutex = true;
     118      }
     119  
     120    e = pthread_mutex_init (m, ma);
     121    if (e != 0)
     122      {
     123  #ifdef ENABLE_PI
     124        if (e == ENOTSUP)
     125  	{
     126  	  puts ("PI mutexes unsupported");
     127  	  return 0;
     128  	}
     129  #endif
     130        printf ("1st mutex_init failed for %s\n", mas);
     131        return 1;
     132      }
     133  
     134    if (pthread_mutex_destroy (m) != 0)
     135      {
     136        printf ("immediate mutex_destroy failed for %s\n", mas);
     137        return 1;
     138      }
     139  
     140    if (pthread_mutex_init (m, ma) != 0)
     141      {
     142        printf ("2nd mutex_init failed for %s\n", mas);
     143        return 1;
     144      }
     145  
     146    if (pthread_mutex_lock (m) != 0)
     147      {
     148        printf ("1st mutex_lock failed for %s\n", mas);
     149        return 1;
     150      }
     151  
     152    /* Elided mutexes don't fail destroy, thus only test this if we don't assume
     153       elision.  */
     154    if (assume_elided_mutex == false)
     155      {
     156        e = pthread_mutex_destroy (m);
     157        if (e == 0)
     158  	{
     159  	  printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas);
     160  	  return 1;
     161  	}
     162        if (e != EBUSY)
     163  	{
     164  	  printf ("\
     165  mutex_destroy of self-locked mutex did not return EBUSY %s\n",
     166  		  mas);
     167  	  return 1;
     168  	}
     169      }
     170  
     171    if (pthread_mutex_unlock (m) != 0)
     172      {
     173        printf ("1st mutex_unlock failed for %s\n", mas);
     174        return 1;
     175      }
     176  
     177    if (pthread_mutex_trylock (m) != 0)
     178      {
     179        printf ("mutex_trylock failed for %s\n", mas);
     180        return 1;
     181      }
     182  
     183    /* Elided mutexes don't fail destroy.  */
     184    if (assume_elided_mutex == false)
     185      {
     186        e = pthread_mutex_destroy (m);
     187        if (e == 0)
     188  	{
     189  	  printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n",
     190  		  mas);
     191  	  return 1;
     192  	}
     193        if (e != EBUSY)
     194  	{
     195  	  printf ("\
     196  mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
     197  		  mas);
     198  	  return 1;
     199  	}
     200      }
     201  
     202    if (pthread_mutex_unlock (m) != 0)
     203      {
     204        printf ("2nd mutex_unlock failed for %s\n", mas);
     205        return 1;
     206      }
     207  
     208    pthread_t th;
     209    if (pthread_create (&th, NULL, tf, NULL) != 0)
     210      {
     211        puts ("1st create failed");
     212        return 1;
     213      }
     214    done = false;
     215  
     216    e = pthread_barrier_wait (&b);
     217    if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     218      {
     219        puts ("1st barrier_wait failed");
     220        return 1;
     221      }
     222  
     223    if (pthread_mutex_lock (m) != 0)
     224      {
     225        printf ("2nd mutex_lock failed for %s\n", mas);
     226        return 1;
     227      }
     228  
     229    if (pthread_mutex_unlock (m) != 0)
     230      {
     231        printf ("3rd mutex_unlock failed for %s\n", mas);
     232        return 1;
     233      }
     234  
     235    /* Elided mutexes don't fail destroy.  */
     236    if (assume_elided_mutex == false)
     237      {
     238        e = pthread_mutex_destroy (m);
     239        if (e == 0)
     240  	{
     241  	  printf ("mutex_destroy of condvar-used mutex succeeded for %s\n",
     242  		  mas);
     243  	  return 1;
     244  	}
     245        if (e != EBUSY)
     246  	{
     247  	  printf ("\
     248  mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
     249  	  return 1;
     250  	}
     251      }
     252  
     253    done = true;
     254    if (pthread_cond_signal (&c) != 0)
     255      {
     256        puts ("cond_signal failed");
     257        return 1;
     258      }
     259  
     260    void *r;
     261    if (pthread_join (th, &r) != 0)
     262      {
     263        puts ("join failed");
     264        return 1;
     265      }
     266    if (r != NULL)
     267      {
     268        puts ("thread didn't return NULL");
     269        return 1;
     270      }
     271  
     272    if (pthread_mutex_destroy (m) != 0)
     273      {
     274        printf ("mutex_destroy after condvar-use failed for %s\n", mas);
     275        return 1;
     276      }
     277  
     278    if (pthread_mutex_init (m, ma) != 0)
     279      {
     280        printf ("3rd mutex_init failed for %s\n", mas);
     281        return 1;
     282      }
     283  
     284    if (pthread_create (&th, NULL, tf, (void *) 1) != 0)
     285      {
     286        puts ("2nd create failed");
     287        return 1;
     288      }
     289    done = false;
     290  
     291    e = pthread_barrier_wait (&b);
     292    if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     293      {
     294        puts ("2nd barrier_wait failed");
     295        return 1;
     296      }
     297  
     298    if (pthread_mutex_lock (m) != 0)
     299      {
     300        printf ("3rd mutex_lock failed for %s\n", mas);
     301        return 1;
     302      }
     303  
     304    if (pthread_mutex_unlock (m) != 0)
     305      {
     306        printf ("4th mutex_unlock failed for %s\n", mas);
     307        return 1;
     308      }
     309  
     310    /* Elided mutexes don't fail destroy.  */
     311    if (assume_elided_mutex == false)
     312      {
     313        e = pthread_mutex_destroy (m);
     314        if (e == 0)
     315  	{
     316  	  printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n",
     317  		  mas);
     318  	  return 1;
     319  	}
     320        if (e != EBUSY)
     321  	{
     322  	  printf ("\
     323  2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n",
     324  		  mas);
     325  	  return 1;
     326  	}
     327      }
     328  
     329    if (pthread_cancel (th) != 0)
     330      {
     331        puts ("cond_cancel failed");
     332        return 1;
     333      }
     334  
     335    if (pthread_join (th, &r) != 0)
     336      {
     337        puts ("join failed");
     338        return 1;
     339      }
     340    if (r != PTHREAD_CANCELED)
     341      {
     342        puts ("thread not canceled");
     343        return 1;
     344      }
     345  
     346    if (pthread_mutex_destroy (m) != 0)
     347      {
     348        printf ("mutex_destroy after condvar-canceled failed for %s\n", mas);
     349        return 1;
     350      }
     351  
     352    return 0;
     353  }
     354  
     355  
     356  static int
     357  do_test (void)
     358  {
     359    pthread_mutex_t mm;
     360    m = &mm;
     361  
     362    if (pthread_barrier_init (&b, NULL, 2) != 0)
     363      {
     364        puts ("barrier_init failed");
     365        return 1;
     366      }
     367  
     368    if (pthread_cond_init (&c, NULL) != 0)
     369      {
     370        puts ("cond_init failed");
     371        return 1;
     372      }
     373  
     374    puts ("check normal mutex");
     375    int res = check_type ("normal", NULL);
     376  
     377    pthread_mutexattr_t ma;
     378    if (pthread_mutexattr_init (&ma) != 0)
     379      {
     380        puts ("1st mutexattr_init failed");
     381        return 1;
     382      }
     383    if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0)
     384      {
     385        puts ("1st mutexattr_settype failed");
     386        return 1;
     387      }
     388  #ifdef ENABLE_PI
     389    if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
     390      {
     391        puts ("1st pthread_mutexattr_setprotocol failed");
     392        return 1;
     393      }
     394  #endif
     395    puts ("check recursive mutex");
     396    res |= check_type ("recursive", &ma);
     397    if (pthread_mutexattr_destroy (&ma) != 0)
     398      {
     399        puts ("1st mutexattr_destroy failed");
     400        return 1;
     401      }
     402  
     403    if (pthread_mutexattr_init (&ma) != 0)
     404      {
     405        puts ("2nd mutexattr_init failed");
     406        return 1;
     407      }
     408    if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
     409      {
     410        puts ("2nd mutexattr_settype failed");
     411        return 1;
     412      }
     413  #ifdef ENABLE_PI
     414    if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
     415      {
     416        puts ("2nd pthread_mutexattr_setprotocol failed");
     417        return 1;
     418      }
     419  #endif
     420    puts ("check error-checking mutex");
     421    res |= check_type ("error-checking", &ma);
     422    if (pthread_mutexattr_destroy (&ma) != 0)
     423      {
     424        puts ("2nd mutexattr_destroy failed");
     425        return 1;
     426      }
     427  
     428    return res;
     429  }
     430  
     431  #define TEST_FUNCTION do_test ()
     432  #include "../test-skeleton.c"