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