1 | /* Bug 23844: Test for pthread_rwlock_trywrlock stalls. |
2 | Copyright (C) 2019-2024 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 | /* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c. |
20 | |
21 | Summary for the pthread_rwlock_trywrlock() stall: |
22 | |
23 | The stall is caused by pthread_rwlock_trywrlock setting |
24 | __wrphase_futex futex to 1 and losing the |
25 | PTHREAD_RWLOCK_FUTEX_USED bit. |
26 | |
27 | The fix for bug 23844 ensures that waiters on __wrphase_futex are |
28 | correctly woken. Before the fix the test stalls as readers can |
29 | wait forever on __wrphase_futex. */ |
30 | |
31 | #include <stdio.h> |
32 | #include <stdlib.h> |
33 | #include <unistd.h> |
34 | #include <pthread.h> |
35 | #include <support/xthread.h> |
36 | #include <errno.h> |
37 | |
38 | /* We need only one lock to reproduce the issue. We will need multiple |
39 | threads to get the exact case where we have a read, try, and unlock |
40 | all interleaving to produce the case where the readers are waiting |
41 | and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a |
42 | subsequent unlock fails to wake them. */ |
43 | pthread_rwlock_t onelock; |
44 | |
45 | /* The number of threads is arbitrary but empirically chosen to have |
46 | enough threads that we see the condition where waiting readers are |
47 | not woken by a successful unlock. */ |
48 | #define NTHREADS 32 |
49 | |
50 | _Atomic int do_exit; |
51 | |
52 | void * |
53 | run_loop (void *arg) |
54 | { |
55 | int i = 0, ret; |
56 | while (!do_exit) |
57 | { |
58 | /* Arbitrarily choose if we are the writer or reader. Choose a |
59 | high enough ratio of readers to writers to make it likely |
60 | that readers block (and eventually are susceptable to |
61 | stalling). |
62 | |
63 | If we are a writer, take the write lock, and then unlock. |
64 | If we are a reader, try the lock, then lock, then unlock. */ |
65 | if ((i % 8) != 0) |
66 | { |
67 | if ((ret = pthread_rwlock_trywrlock (rwlock: &onelock)) != 0) |
68 | { |
69 | if (ret == EBUSY) |
70 | xpthread_rwlock_wrlock (rwlock: &onelock); |
71 | else |
72 | exit (EXIT_FAILURE); |
73 | } |
74 | } |
75 | else |
76 | xpthread_rwlock_rdlock (rwlock: &onelock); |
77 | /* Thread does some work and then unlocks. */ |
78 | xpthread_rwlock_unlock (rwlock: &onelock); |
79 | i++; |
80 | } |
81 | return NULL; |
82 | } |
83 | |
84 | int |
85 | do_test (void) |
86 | { |
87 | int i; |
88 | pthread_t tids[NTHREADS]; |
89 | xpthread_rwlock_init (rwlock: &onelock, NULL); |
90 | for (i = 0; i < NTHREADS; i++) |
91 | tids[i] = xpthread_create (NULL, thread_func: run_loop, NULL); |
92 | /* Run for some amount of time. The pthread_rwlock_tryrwlock stall |
93 | is very easy to trigger and happens in seconds under the test |
94 | conditions. */ |
95 | sleep (seconds: 10); |
96 | /* Then exit. */ |
97 | printf (format: "INFO: Exiting...\n" ); |
98 | do_exit = 1; |
99 | /* If any readers stalled then we will timeout waiting for them. */ |
100 | for (i = 0; i < NTHREADS; i++) |
101 | xpthread_join (thr: tids[i]); |
102 | printf (format: "INFO: Done.\n" ); |
103 | xpthread_rwlock_destroy (rwlock: &onelock); |
104 | printf (format: "PASS: No pthread_rwlock_tryrwlock stalls detected.\n" ); |
105 | return 0; |
106 | } |
107 | |
108 | #include <support/test-driver.c> |
109 | |