diff --git a/include/pthread.h b/include/pthread.h index be555fed75..a75cd9e901 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -343,6 +343,7 @@ struct pthread_rwlock_s pthread_cond_t cv; unsigned int num_readers; unsigned int num_writers; + bool write_in_progress; }; typedef struct pthread_rwlock_s pthread_rwlock_t; diff --git a/libc/pthread/pthread_rwlock.c b/libc/pthread/pthread_rwlock.c index 3f902089b0..b40b655b26 100644 --- a/libc/pthread/pthread_rwlock.c +++ b/libc/pthread/pthread_rwlock.c @@ -60,8 +60,9 @@ int pthread_rwlock_init(FAR pthread_rwlock_t *lock, return -ENOSYS; } - lock->num_readers = 0; - lock->num_writers = 0; + lock->num_readers = 0; + lock->num_writers = 0; + lock->write_in_progress = false; err = pthread_cond_init(&lock->cv, NULL); if (err != 0) @@ -111,9 +112,9 @@ int pthread_rwlock_unlock(FAR pthread_rwlock_t *rw_lock) err = pthread_cond_broadcast(&rw_lock->cv); } } - else if (rw_lock->num_writers > 0) + else if (rw_lock->write_in_progress) { - rw_lock->num_writers--; + rw_lock->write_in_progress = false; err = pthread_cond_broadcast(&rw_lock->cv); } diff --git a/libc/pthread/pthread_rwlock_rdlock.c b/libc/pthread/pthread_rwlock_rdlock.c index 6270d2bbe4..9fd461a758 100644 --- a/libc/pthread/pthread_rwlock_rdlock.c +++ b/libc/pthread/pthread_rwlock_rdlock.c @@ -54,7 +54,7 @@ static int tryrdlock(FAR pthread_rwlock_t *rw_lock) { int err; - if (rw_lock->num_writers > 0) + if (rw_lock->num_writers > 0 || rw_lock->write_in_progress) { err = EBUSY; } diff --git a/libc/pthread/pthread_rwlock_wrlock.c b/libc/pthread/pthread_rwlock_wrlock.c index dc2d155021..ecda4cb25b 100644 --- a/libc/pthread/pthread_rwlock_wrlock.c +++ b/libc/pthread/pthread_rwlock_wrlock.c @@ -75,13 +75,13 @@ int pthread_rwlock_trywrlock(FAR pthread_rwlock_t *rw_lock) return err; } - if (rw_lock->num_readers > 0 || rw_lock->num_writers > 0) + if (rw_lock->num_readers > 0 || rw_lock->write_in_progress) { err = EBUSY; } else { - rw_lock->num_writers++; + rw_lock->write_in_progress = true; } pthread_mutex_unlock(&rw_lock->lock); @@ -92,20 +92,21 @@ int pthread_rwlock_timedwrlock(FAR pthread_rwlock_t *rw_lock, FAR const struct timespec *ts) { int err = pthread_mutex_lock(&rw_lock->lock); - int num_writers_current; if (err != 0) { return err; } - num_writers_current = rw_lock->num_writers++; - if (num_writers_current == 0) + if (rw_lock->num_writers == UINT_MAX) { + err = EAGAIN; goto exit_with_mutex; } - while (rw_lock->num_writers != num_writers_current) + rw_lock->num_writers++; + + while (rw_lock->write_in_progress || rw_lock->num_readers > 0) { if (ts != NULL) { @@ -122,6 +123,20 @@ int pthread_rwlock_timedwrlock(FAR pthread_rwlock_t *rw_lock, } } + if (err == 0) + { + rw_lock->write_in_progress = true; + } + + else + { + /* In case of error, notify any blocked readers. */ + + (void) pthread_cond_broadcast(&rw_lock->cv); + } + + rw_lock->num_writers--; + exit_with_mutex: pthread_mutex_unlock(&rw_lock->lock); return err;