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 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 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 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 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 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 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 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 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 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 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 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 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 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