1 | /* Test rwlocks. |
2 | Copyright (C) 2000-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 | #define _GNU_SOURCE |
20 | |
21 | #include <pthread.h> |
22 | #include <assert.h> |
23 | #include <error.h> |
24 | #include <errno.h> |
25 | |
26 | #define THREADS 1 |
27 | |
28 | int a; |
29 | int b; |
30 | |
31 | /* Get a read lock and assert that a == b. */ |
32 | void * |
33 | test1 (void *arg) |
34 | { |
35 | error_t err; |
36 | pthread_rwlock_t *lock = arg; |
37 | int i; |
38 | |
39 | for (i = 0; i < 200; i++) |
40 | { |
41 | err = pthread_rwlock_rdlock (rwlock: lock); |
42 | assert (err == 0); |
43 | |
44 | assert (a == b); |
45 | |
46 | sched_yield (); |
47 | |
48 | assert (a == b); |
49 | |
50 | err = pthread_rwlock_unlock (rwlock: lock); |
51 | assert (err == 0); |
52 | } |
53 | |
54 | return 0; |
55 | } |
56 | |
57 | int |
58 | main (int argc, char **argv) |
59 | { |
60 | error_t err; |
61 | pthread_rwlockattr_t attr; |
62 | pthread_rwlock_t lock; |
63 | int pshared; |
64 | |
65 | int i; |
66 | pthread_t tid[THREADS]; |
67 | void *ret; |
68 | |
69 | err = pthread_rwlockattr_init (attr: &attr); |
70 | if (err) |
71 | error (status: 1, errnum: err, format: "pthread_rwlockattr_init" ); |
72 | |
73 | err = pthread_rwlockattr_getpshared (attr: &attr, pshared: &pshared); |
74 | if (err) |
75 | error (status: 1, errnum: err, format: "pthread_rwlockattr_getpshared" ); |
76 | |
77 | /* Assert the default state as mandated by POSIX. */ |
78 | assert (pshared == PTHREAD_PROCESS_PRIVATE); |
79 | |
80 | err = pthread_rwlockattr_setpshared (attr: &attr, pshared: pshared); |
81 | if (err) |
82 | error (status: 1, errnum: err, format: "pthread_rwlockattr_setpshared" ); |
83 | |
84 | err = pthread_rwlock_init (rwlock: &lock, attr: &attr); |
85 | if (err) |
86 | error (status: 1, errnum: err, format: "pthread_rwlock_init" ); |
87 | |
88 | err = pthread_rwlockattr_destroy (attr: &attr); |
89 | if (err) |
90 | error (status: 1, errnum: err, format: "pthread_rwlockattr_destroy" ); |
91 | |
92 | /* Now test the lock. */ |
93 | |
94 | for (i = 0; i < THREADS; i++) |
95 | { |
96 | err = pthread_create (newthread: &tid[i], attr: 0, start_routine: test1, arg: &lock); |
97 | if (err) |
98 | error (status: 1, errnum: err, format: "pthread_create" ); |
99 | } |
100 | |
101 | for (i = 0; i < 10; i++) |
102 | { |
103 | sched_yield (); |
104 | |
105 | /* Get a write lock. */ |
106 | pthread_rwlock_wrlock (rwlock: &lock); |
107 | /* Increment a and b giving other threads a chance to run in |
108 | between. */ |
109 | sched_yield (); |
110 | a++; |
111 | sched_yield (); |
112 | b++; |
113 | sched_yield (); |
114 | /* Unlock. */ |
115 | pthread_rwlock_unlock (rwlock: &lock); |
116 | } |
117 | |
118 | for (i = 0; i < THREADS; i++) |
119 | { |
120 | err = pthread_join (th: tid[i], thread_return: &ret); |
121 | if (err) |
122 | error (status: 1, errnum: err, format: "pthread_join" ); |
123 | } |
124 | |
125 | /* Read lock it. */ |
126 | err = pthread_rwlock_tryrdlock (rwlock: &lock); |
127 | assert (err == 0); |
128 | |
129 | /* Try to write lock it. It should fail with EBUSY. */ |
130 | err = pthread_rwlock_trywrlock (rwlock: &lock); |
131 | assert (err == EBUSY); |
132 | |
133 | /* Drop the read lock. */ |
134 | err = pthread_rwlock_unlock (rwlock: &lock); |
135 | assert (err == 0); |
136 | |
137 | /* Get a write lock. */ |
138 | err = pthread_rwlock_trywrlock (rwlock: &lock); |
139 | assert (err == 0); |
140 | |
141 | /* Fail trying to acquire another write lock. */ |
142 | err = pthread_rwlock_trywrlock (rwlock: &lock); |
143 | assert (err == EBUSY); |
144 | |
145 | /* Try to get a read lock which should also fail. */ |
146 | err = pthread_rwlock_tryrdlock (rwlock: &lock); |
147 | assert (err == EBUSY); |
148 | |
149 | /* Unlock it. */ |
150 | err = pthread_rwlock_unlock (rwlock: &lock); |
151 | assert (err == 0); |
152 | |
153 | |
154 | err = pthread_rwlock_destroy (rwlock: &lock); |
155 | if (err) |
156 | error (status: 1, errnum: err, format: "pthread_rwlock_destroy" ); |
157 | |
158 | return 0; |
159 | } |
160 | |