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