1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2010-10-26 Bernard the first version
9 */
10
11 #include <pthread.h>
12
pthread_rwlockattr_init(pthread_rwlockattr_t * attr)13 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
14 {
15 if (!attr)
16 return EINVAL;
17 *attr = PTHREAD_PROCESS_PRIVATE;
18
19 return 0;
20 }
21 RTM_EXPORT(pthread_rwlockattr_init);
22
pthread_rwlockattr_destroy(pthread_rwlockattr_t * attr)23 int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
24 {
25 if (!attr)
26 return EINVAL;
27
28 return 0;
29 }
30 RTM_EXPORT(pthread_rwlockattr_destroy);
31
pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * attr,int * pshared)32 int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
33 int *pshared)
34 {
35 if (!attr || !pshared)
36 return EINVAL;
37
38 *pshared = PTHREAD_PROCESS_PRIVATE;
39
40 return 0;
41 }
42 RTM_EXPORT(pthread_rwlockattr_getpshared);
43
pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr,int pshared)44 int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared)
45 {
46 if (!attr || pshared != PTHREAD_PROCESS_PRIVATE)
47 return EINVAL;
48
49 return 0;
50 }
51 RTM_EXPORT(pthread_rwlockattr_setpshared);
52
pthread_rwlock_init(pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attr)53 int pthread_rwlock_init(pthread_rwlock_t *rwlock,
54 const pthread_rwlockattr_t *attr)
55 {
56 if (!rwlock)
57 return EINVAL;
58
59 rwlock->attr = PTHREAD_PROCESS_PRIVATE;
60 pthread_mutex_init(&(rwlock->rw_mutex), NULL);
61 pthread_cond_init(&(rwlock->rw_condreaders), NULL);
62 pthread_cond_init(&(rwlock->rw_condwriters), NULL);
63
64 rwlock->rw_nwaitwriters = 0;
65 rwlock->rw_nwaitreaders = 0;
66 rwlock->rw_refcount = 0;
67
68 return 0;
69 }
70 RTM_EXPORT(pthread_rwlock_init);
71
pthread_rwlock_destroy(pthread_rwlock_t * rwlock)72 int pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
73 {
74 int result;
75
76 if (!rwlock)
77 return EINVAL;
78 if (rwlock->attr == -1)
79 return 0; /* rwlock is not initialized */
80
81 if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
82 return(result);
83
84 if (rwlock->rw_refcount != 0 ||
85 rwlock->rw_nwaitreaders != 0 ||
86 rwlock->rw_nwaitwriters != 0)
87 {
88 result = EBUSY;
89
90 return result;
91 }
92 else
93 {
94 /* check whether busy */
95 result = rt_sem_trytake(&(rwlock->rw_condreaders.sem));
96 if (result == RT_EOK)
97 {
98 result = rt_sem_trytake(&(rwlock->rw_condwriters.sem));
99 if (result == RT_EOK)
100 {
101 rt_sem_release(&(rwlock->rw_condreaders.sem));
102 rt_sem_release(&(rwlock->rw_condwriters.sem));
103
104 pthread_cond_destroy(&rwlock->rw_condreaders);
105 pthread_cond_destroy(&rwlock->rw_condwriters);
106 }
107 else
108 {
109 rt_sem_release(&(rwlock->rw_condreaders.sem));
110 result = EBUSY;
111 }
112 }
113 else
114 result = EBUSY;
115 }
116
117 pthread_mutex_unlock(&rwlock->rw_mutex);
118 if (result == 0)
119 pthread_mutex_destroy(&rwlock->rw_mutex);
120
121 return result;
122 }
123 RTM_EXPORT(pthread_rwlock_destroy);
124
pthread_rwlock_rdlock(pthread_rwlock_t * rwlock)125 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
126 {
127 int result;
128
129 if (!rwlock)
130 return EINVAL;
131 if (rwlock->attr == -1)
132 pthread_rwlock_init(rwlock, NULL);
133
134 if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
135 return(result);
136
137 /* give preference to waiting writers */
138 while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0)
139 {
140 rwlock->rw_nwaitreaders++;
141 /* rw_mutex will be released when waiting for rw_condreaders */
142 result = pthread_cond_wait(&rwlock->rw_condreaders, &rwlock->rw_mutex);
143 /* rw_mutex should have been taken again when returned from waiting */
144 rwlock->rw_nwaitreaders--;
145 if (result != 0) /* wait error */
146 break;
147 }
148
149 /* another reader has a read lock */
150 if (result == 0)
151 rwlock->rw_refcount++;
152
153 pthread_mutex_unlock(&rwlock->rw_mutex);
154
155 return (result);
156 }
157 RTM_EXPORT(pthread_rwlock_rdlock);
158
pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock)159 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
160 {
161 int result;
162
163 if (!rwlock)
164 return EINVAL;
165 if (rwlock->attr == -1)
166 pthread_rwlock_init(rwlock, NULL);
167
168 if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
169 return(result);
170
171 if (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0)
172 result = EBUSY; /* held by a writer or waiting writers */
173 else
174 rwlock->rw_refcount++; /* increment count of reader locks */
175
176 pthread_mutex_unlock(&rwlock->rw_mutex);
177
178 return(result);
179 }
180 RTM_EXPORT(pthread_rwlock_tryrdlock);
181
pthread_rwlock_timedrdlock(pthread_rwlock_t * rwlock,const struct timespec * abstime)182 int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
183 const struct timespec *abstime)
184 {
185 int result;
186
187 if (!rwlock)
188 return EINVAL;
189 if (rwlock->attr == -1)
190 pthread_rwlock_init(rwlock, NULL);
191
192 if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
193 return(result);
194
195 /* give preference to waiting writers */
196 while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0)
197 {
198 rwlock->rw_nwaitreaders++;
199 /* rw_mutex will be released when waiting for rw_condreaders */
200 result = pthread_cond_timedwait(&rwlock->rw_condreaders, &rwlock->rw_mutex, abstime);
201 /* rw_mutex should have been taken again when returned from waiting */
202 rwlock->rw_nwaitreaders--;
203 if (result != 0)
204 break;
205 }
206
207 /* another reader has a read lock */
208 if (result == 0)
209 rwlock->rw_refcount++;
210
211 pthread_mutex_unlock(&rwlock->rw_mutex);
212
213 return (result);
214 }
215 RTM_EXPORT(pthread_rwlock_timedrdlock);
216
pthread_rwlock_timedwrlock(pthread_rwlock_t * rwlock,const struct timespec * abstime)217 int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
218 const struct timespec *abstime)
219 {
220 int result;
221
222 if (!rwlock)
223 return EINVAL;
224 if (rwlock->attr == -1)
225 pthread_rwlock_init(rwlock, NULL);
226
227 if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
228 return(result);
229
230 while (rwlock->rw_refcount != 0)
231 {
232 rwlock->rw_nwaitwriters++;
233 /* rw_mutex will be released when waiting for rw_condwriters */
234 result = pthread_cond_timedwait(&rwlock->rw_condwriters, &rwlock->rw_mutex, abstime);
235 /* rw_mutex should have been taken again when returned from waiting */
236 rwlock->rw_nwaitwriters--;
237
238 if (result != 0)
239 break;
240 }
241
242 if (result == 0)
243 rwlock->rw_refcount = -1;
244
245 pthread_mutex_unlock(&rwlock->rw_mutex);
246
247 return(result);
248 }
249 RTM_EXPORT(pthread_rwlock_timedwrlock);
250
pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock)251 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
252 {
253 int result;
254
255 if (!rwlock)
256 return EINVAL;
257 if (rwlock->attr == -1)
258 pthread_rwlock_init(rwlock, NULL);
259
260 if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
261 return(result);
262
263 if (rwlock->rw_refcount != 0)
264 result = EBUSY; /* held by either writer or reader(s) */
265 else
266 rwlock->rw_refcount = -1; /* available, indicate a writer has it */
267
268 pthread_mutex_unlock(&rwlock->rw_mutex);
269
270 return(result);
271 }
272 RTM_EXPORT(pthread_rwlock_trywrlock);
273
pthread_rwlock_unlock(pthread_rwlock_t * rwlock)274 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
275 {
276 int result;
277
278 if (!rwlock)
279 return EINVAL;
280 if (rwlock->attr == -1)
281 pthread_rwlock_init(rwlock, NULL);
282
283 if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
284 return(result);
285
286 if (rwlock->rw_refcount > 0)
287 rwlock->rw_refcount--; /* releasing a reader */
288 else if (rwlock->rw_refcount == -1)
289 rwlock->rw_refcount = 0; /* releasing a writer */
290
291 /* give preference to waiting writers over waiting readers */
292 if (rwlock->rw_nwaitwriters > 0)
293 {
294 if (rwlock->rw_refcount == 0)
295 result = pthread_cond_signal(&rwlock->rw_condwriters);
296 }
297 else if (rwlock->rw_nwaitreaders > 0)
298 {
299 result = pthread_cond_broadcast(&rwlock->rw_condreaders);
300 }
301
302 pthread_mutex_unlock(&rwlock->rw_mutex);
303
304 return(result);
305 }
306 RTM_EXPORT(pthread_rwlock_unlock);
307
pthread_rwlock_wrlock(pthread_rwlock_t * rwlock)308 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
309 {
310 int result;
311
312 if (!rwlock)
313 return EINVAL;
314 if (rwlock->attr == -1)
315 pthread_rwlock_init(rwlock, NULL);
316
317 if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0)
318 return(result);
319
320 while (rwlock->rw_refcount != 0)
321 {
322 rwlock->rw_nwaitwriters++;
323 /* rw_mutex will be released when waiting for rw_condwriters */
324 result = pthread_cond_wait(&rwlock->rw_condwriters, &rwlock->rw_mutex);
325 /* rw_mutex should have been taken again when returned from waiting */
326 rwlock->rw_nwaitwriters--;
327
328 if (result != 0)
329 break;
330 }
331
332 if (result == 0)
333 rwlock->rw_refcount = -1;
334
335 pthread_mutex_unlock(&rwlock->rw_mutex);
336
337 return(result);
338 }
339 RTM_EXPORT(pthread_rwlock_wrlock);
340
341