xref: /nrf52832-nimble/rt-thread/components/libc/pthreads/pthread_rwlock.c (revision 104654410c56c573564690304ae786df310c91fc)
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