From 7bb26d26150d2540d97d6e8a146309866d278ad5 Mon Sep 17 00:00:00 2001 From: Mark Schulte Date: Fri, 7 Apr 2017 07:03:00 -0600 Subject: [PATCH 1/3] pthreads: Adding rwlock implementation Adding an implementation for read/write locks into the pthread library. These locks are writer priority, such that if any writers come in they are given priority for writing. --- include/pthread.h | 43 +++++++- libc/pthread/Make.defs | 4 + libc/pthread/pthread_rwlock.c | 127 ++++++++++++++++++++++++ libc/pthread/pthread_rwlock_rdlock.c | 143 +++++++++++++++++++++++++++ libc/pthread/pthread_rwlock_wrlock.c | 133 +++++++++++++++++++++++++ sched/Kconfig | 6 ++ 6 files changed, 454 insertions(+), 2 deletions(-) create mode 100644 libc/pthread/pthread_rwlock.c create mode 100644 libc/pthread/pthread_rwlock_rdlock.c create mode 100644 libc/pthread/pthread_rwlock_wrlock.c diff --git a/include/pthread.h b/include/pthread.h index af6ef51e23e..cfa054cfcac 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -337,6 +337,28 @@ typedef struct pthread_barrier_s pthread_barrier_t; typedef bool pthread_once_t; #define __PTHREAD_ONCE_T_DEFINED 1 +#ifdef CONFIG_PTHREAD_RWLOCK +struct pthread_rwlock_s +{ + pthread_mutex_t lock; + pthread_cond_t cv; + unsigned int num_readers; + unsigned int num_writers; +}; + +typedef struct pthread_rwlock_s pthread_rwlock_t; + +typedef int pthread_rwlockattr_t; + +#define PTHREAD_RWLOCK_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, \ + PTHREAD_COND_INITIALIZER, \ + 0, 0} + +#define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1, \ + __PTHREAD_MUTEX_DEFAULT_FLAGS, \ + PTHREAD_MUTEX_DEFAULT, 0} +#endif + #ifdef CONFIG_PTHREAD_CLEANUP /* This type describes the pthread cleanup callback (non-standard) */ @@ -539,8 +561,8 @@ int pthread_barrierattr_setpshared(FAR pthread_barrierattr_t *attr, int pthread_barrier_destroy(FAR pthread_barrier_t *barrier); int pthread_barrier_init(FAR pthread_barrier_t *barrier, - FAR const pthread_barrierattr_t *attr, - unsigned int count); + FAR const pthread_barrierattr_t *attr, + unsigned int count); int pthread_barrier_wait(FAR pthread_barrier_t *barrier); /* Pthread initialization */ @@ -548,6 +570,23 @@ int pthread_barrier_wait(FAR pthread_barrier_t *barrier); int pthread_once(FAR pthread_once_t *once_control, CODE void (*init_routine)(void)); +/* Pthread rwlock */ + +#ifdef CONFIG_PTHREAD_RWLOCK +int pthread_rwlock_destroy(FAR pthread_rwlock_t *rw_lock); +int pthread_rwlock_init(FAR pthread_rwlock_t *rw_lock, + FAR const pthread_rwlockattr_t *attr); +int pthread_rwlock_rdlock(pthread_rwlock_t *lock); +int pthread_rwlock_timedrdlock(FAR pthread_rwlock_t *lock, + FAR const struct timespec *abstime); +int pthread_rwlock_tryrdlock(FAR pthread_rwlock_t *lock); +int pthread_rwlock_wrlock(FAR pthread_rwlock_t *lock); +int pthread_rwlock_timedwrlock(FAR pthread_rwlock_t *lock, + FAR const struct timespec *abstime); +int pthread_rwlock_trywrlock(FAR pthread_rwlock_t *lock); +int pthread_rwlock_unlock(FAR pthread_rwlock_t *lock); +#endif /* CONFIG_PTHREAD_RWLOCK */ + /* Pthread signal management APIs */ int pthread_kill(pthread_t thread, int sig); diff --git a/libc/pthread/Make.defs b/libc/pthread/Make.defs index b8be2927d2f..1f6cacb88e0 100644 --- a/libc/pthread/Make.defs +++ b/libc/pthread/Make.defs @@ -53,6 +53,10 @@ CSRCS += pthread_mutexattr_setrobust.c pthread_mutexattr_getrobust.c CSRCS += pthread_setcancelstate.c pthread_setcanceltype.c CSRCS += pthread_testcancel.c +ifeq ($(CONFIG_PTHREAD_RWLOCK),y) +CSRCS += pthread_rwlock.c pthread_rwlock_rdlock.c pthread_rwlock_wrlock.c +endif + ifeq ($(CONFIG_SMP),y) CSRCS += pthread_attr_getaffinity.c pthread_attr_setaffinity.c endif diff --git a/libc/pthread/pthread_rwlock.c b/libc/pthread/pthread_rwlock.c new file mode 100644 index 00000000000..3f902089b00 --- /dev/null +++ b/libc/pthread/pthread_rwlock.c @@ -0,0 +1,127 @@ +/**************************************************************************** + * libc/pthread/pthread_rwlock.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int pthread_rwlock_init(FAR pthread_rwlock_t *lock, + FAR const pthread_rwlockattr_t *attr) +{ + int err; + + if (attr != NULL) + { + return -ENOSYS; + } + + lock->num_readers = 0; + lock->num_writers = 0; + + err = pthread_cond_init(&lock->cv, NULL); + if (err != 0) + { + return err; + } + + err = pthread_mutex_init(&lock->lock, NULL); + if (err != 0) + { + pthread_cond_destroy(&lock->cv); + return err; + } + + return err; +} + +int pthread_rwlock_destroy(FAR pthread_rwlock_t *lock) +{ + int cond_err = pthread_cond_destroy(&lock->cv); + int mutex_err = pthread_mutex_destroy(&lock->lock); + + if (mutex_err) + { + return mutex_err; + } + + return cond_err; +} + +int pthread_rwlock_unlock(FAR pthread_rwlock_t *rw_lock) +{ + int err; + + err = pthread_mutex_lock(&rw_lock->lock); + if (err != 0) + { + return err; + } + + if (rw_lock->num_readers > 0) + { + rw_lock->num_readers--; + + if (rw_lock->num_readers == 0) + { + err = pthread_cond_broadcast(&rw_lock->cv); + } + } + else if (rw_lock->num_writers > 0) + { + rw_lock->num_writers--; + + err = pthread_cond_broadcast(&rw_lock->cv); + } + else + { + err = EINVAL; + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} diff --git a/libc/pthread/pthread_rwlock_rdlock.c b/libc/pthread/pthread_rwlock_rdlock.c new file mode 100644 index 00000000000..6270d2bbe4e --- /dev/null +++ b/libc/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,143 @@ +/**************************************************************************** + * libc/pthread/pthread_rwlockread.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int tryrdlock(FAR pthread_rwlock_t *rw_lock) +{ + int err; + + if (rw_lock->num_writers > 0) + { + err = EBUSY; + } + else if (rw_lock->num_readers == UINT_MAX) + { + err = EAGAIN; + } + else + { + rw_lock->num_readers++; + err = OK; + } + + return err; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_rwlock_rdlock + * + * Description: + * Locks a read/write lock for reading + * + * Parameters: + * None + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int pthread_rwlock_tryrdlock(FAR pthread_rwlock_t *rw_lock) +{ + int err = pthread_mutex_trylock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + err = tryrdlock(rw_lock); + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_timedrdlock(FAR pthread_rwlock_t *rw_lock, + FAR const struct timespec *ts) +{ + int err = pthread_mutex_lock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + while ((err = tryrdlock(rw_lock)) == EBUSY) + { + if (ts != NULL) + { + err = pthread_cond_timedwait(&rw_lock->cv, &rw_lock->lock, ts); + } + else + { + err = pthread_cond_wait(&rw_lock->cv, &rw_lock->lock); + } + + if (err != 0) + { + break; + } + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_rdlock(FAR pthread_rwlock_t * rw_lock) +{ + return pthread_rwlock_timedrdlock(rw_lock, NULL); +} diff --git a/libc/pthread/pthread_rwlock_wrlock.c b/libc/pthread/pthread_rwlock_wrlock.c new file mode 100644 index 00000000000..dc2d155021e --- /dev/null +++ b/libc/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * libc/pthread/pthread_rwlockwrite.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_rwlock_rdlock + * + * Description: + * Locks a read/write lock for reading + * + * Parameters: + * None + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int pthread_rwlock_trywrlock(FAR pthread_rwlock_t *rw_lock) +{ + int err = pthread_mutex_trylock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + if (rw_lock->num_readers > 0 || rw_lock->num_writers > 0) + { + err = EBUSY; + } + else + { + rw_lock->num_writers++; + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +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) + { + goto exit_with_mutex; + } + + while (rw_lock->num_writers != num_writers_current) + { + if (ts != NULL) + { + err = pthread_cond_timedwait(&rw_lock->cv, &rw_lock->lock, ts); + } + else + { + err = pthread_cond_wait(&rw_lock->cv, &rw_lock->lock); + } + + if (err != 0) + { + break; + } + } + +exit_with_mutex: + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_wrlock(FAR pthread_rwlock_t *rw_lock) +{ + return pthread_rwlock_timedwrlock(rw_lock, NULL); +} diff --git a/sched/Kconfig b/sched/Kconfig index 50613fb44d3..02096b268d9 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -573,6 +573,12 @@ config PTHREAD_MUTEX_DEFAULT_UNSAFE endchoice # Default NORMAL mutex robustness +config PTHREAD_RWLOCK + bool "Enable pthread rwlock API" + default n + ---help--- + Add supports for the rwlock interfaces + config NPTHREAD_KEYS int "Maximum number of pthread keys" default 4 From b631dc886f3d1533b70d38385e42fabc9fde93fe Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 7 Apr 2017 07:34:22 -0600 Subject: [PATCH 2/3] Remove CONFIG_PTHREAD_RWLOCK. Rwlock interfaces built unconditionally. --- include/pthread.h | 4 ---- libc/pthread/Make.defs | 3 --- sched/Kconfig | 6 ------ 3 files changed, 13 deletions(-) diff --git a/include/pthread.h b/include/pthread.h index cfa054cfcac..be555fed75e 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -337,7 +337,6 @@ typedef struct pthread_barrier_s pthread_barrier_t; typedef bool pthread_once_t; #define __PTHREAD_ONCE_T_DEFINED 1 -#ifdef CONFIG_PTHREAD_RWLOCK struct pthread_rwlock_s { pthread_mutex_t lock; @@ -357,7 +356,6 @@ typedef int pthread_rwlockattr_t; #define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1, \ __PTHREAD_MUTEX_DEFAULT_FLAGS, \ PTHREAD_MUTEX_DEFAULT, 0} -#endif #ifdef CONFIG_PTHREAD_CLEANUP /* This type describes the pthread cleanup callback (non-standard) */ @@ -572,7 +570,6 @@ int pthread_once(FAR pthread_once_t *once_control, /* Pthread rwlock */ -#ifdef CONFIG_PTHREAD_RWLOCK int pthread_rwlock_destroy(FAR pthread_rwlock_t *rw_lock); int pthread_rwlock_init(FAR pthread_rwlock_t *rw_lock, FAR const pthread_rwlockattr_t *attr); @@ -585,7 +582,6 @@ int pthread_rwlock_timedwrlock(FAR pthread_rwlock_t *lock, FAR const struct timespec *abstime); int pthread_rwlock_trywrlock(FAR pthread_rwlock_t *lock); int pthread_rwlock_unlock(FAR pthread_rwlock_t *lock); -#endif /* CONFIG_PTHREAD_RWLOCK */ /* Pthread signal management APIs */ diff --git a/libc/pthread/Make.defs b/libc/pthread/Make.defs index 1f6cacb88e0..291dfdfd4e6 100644 --- a/libc/pthread/Make.defs +++ b/libc/pthread/Make.defs @@ -52,10 +52,7 @@ CSRCS += pthread_mutexattr_settype.c pthread_mutexattr_gettype.c CSRCS += pthread_mutexattr_setrobust.c pthread_mutexattr_getrobust.c CSRCS += pthread_setcancelstate.c pthread_setcanceltype.c CSRCS += pthread_testcancel.c - -ifeq ($(CONFIG_PTHREAD_RWLOCK),y) CSRCS += pthread_rwlock.c pthread_rwlock_rdlock.c pthread_rwlock_wrlock.c -endif ifeq ($(CONFIG_SMP),y) CSRCS += pthread_attr_getaffinity.c pthread_attr_setaffinity.c diff --git a/sched/Kconfig b/sched/Kconfig index 02096b268d9..50613fb44d3 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -573,12 +573,6 @@ config PTHREAD_MUTEX_DEFAULT_UNSAFE endchoice # Default NORMAL mutex robustness -config PTHREAD_RWLOCK - bool "Enable pthread rwlock API" - default n - ---help--- - Add supports for the rwlock interfaces - config NPTHREAD_KEYS int "Maximum number of pthread keys" default 4 From 2b1ca79b4b2549f63df9b1c77138e9ef1c848ee4 Mon Sep 17 00:00:00 2001 From: Mark Schulte Date: Fri, 7 Apr 2017 15:45:24 -0600 Subject: [PATCH 3/3] pthread rwlock bugfixes --- include/pthread.h | 1 + libc/pthread/pthread_rwlock.c | 9 +++++---- libc/pthread/pthread_rwlock_rdlock.c | 2 +- libc/pthread/pthread_rwlock_wrlock.c | 27 +++++++++++++++++++++------ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/include/pthread.h b/include/pthread.h index be555fed75e..a75cd9e9015 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 3f902089b00..b40b655b26d 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 6270d2bbe4e..9fd461a758e 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 dc2d155021e..ecda4cb25be 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;