1 /* Test rwlock with PREFER_WRITER_NONRECURSIVE_NP (bug 23861).
2    Copyright (C) 2018-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <pthread.h>
23 #include <support/xthread.h>
24 
25 /* We choose 10 iterations because this happens to be able to trigger the
26    stall on contemporary hardware.  */
27 #define LOOPS 10
28 /* We need 3 threads to trigger bug 23861.  One thread as a writer, and
29    two reader threads.  The test verifies that the second-to-last reader
30    is able to notify the *last* reader that it should be done waiting.
31    If the second-to-last reader fails to notify the last reader or does
32    so incorrectly then the last reader may stall indefinitely.  */
33 #define NTHREADS 3
34 
35 _Atomic int do_exit;
36 pthread_rwlockattr_t mylock_attr;
37 pthread_rwlock_t mylock;
38 
39 void *
run_loop(void * a)40 run_loop (void *a)
41 {
42   while (!do_exit)
43     {
44       if (random () & 1)
45 	{
46 	  xpthread_rwlock_wrlock (&mylock);
47 	  xpthread_rwlock_unlock (&mylock);
48 	}
49       else
50 	{
51 	  xpthread_rwlock_rdlock (&mylock);
52 	  xpthread_rwlock_unlock (&mylock);
53 	}
54     }
55   return NULL;
56 }
57 
58 int
do_test(void)59 do_test (void)
60 {
61   xpthread_rwlockattr_init (&mylock_attr);
62   xpthread_rwlockattr_setkind_np (&mylock_attr,
63 				  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
64   xpthread_rwlock_init (&mylock, &mylock_attr);
65 
66   for (int n = 0; n < LOOPS; n++)
67     {
68       pthread_t tids[NTHREADS];
69       do_exit = 0;
70       for (int i = 0; i < NTHREADS; i++)
71 	tids[i] = xpthread_create (NULL, run_loop, NULL);
72       /* Let the threads run for some time.  */
73       sleep (1);
74       printf ("Exiting...");
75       fflush (stdout);
76       do_exit = 1;
77       for (int i = 0; i < NTHREADS; i++)
78 	xpthread_join (tids[i]);
79       printf ("done.\n");
80     }
81   pthread_rwlock_destroy (&mylock);
82   pthread_rwlockattr_destroy (&mylock_attr);
83   return 0;
84 }
85 
86 #define TIMEOUT (DEFAULT_TIMEOUT + 3 * LOOPS)
87 #include <support/test-driver.c>
88