From e7312cccea37c12bea6b9a0e6ba5c9f39762391a Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Mon, 17 Apr 2023 14:45:26 +0800 Subject: [PATCH] pthread: added pthread_rwlock_tryrd/wrlock() Closes https://github.com/espressif/esp-idf/issues/9229 --- components/pthread/pthread_rwlock.c | 59 ++++++++++++- .../main/test_pthread_rwlock.c | 86 +++++++++++++++++++ docs/en/api-reference/system/pthread.rst | 21 +++-- 3 files changed, 157 insertions(+), 9 deletions(-) diff --git a/components/pthread/pthread_rwlock.c b/components/pthread/pthread_rwlock.c index e17712a54b..91f4d49420 100644 --- a/components/pthread/pthread_rwlock.c +++ b/components/pthread/pthread_rwlock.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -191,6 +191,34 @@ int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) return 0; } +int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + esp_pthread_rwlock_t *esp_rwlock; + int res; + + res = checkrw_lock(rwlock); + if (res != 0) { + return res; + } + + esp_rwlock = (esp_pthread_rwlock_t *)*rwlock; + res = pthread_mutex_trylock(&esp_rwlock->resource_mutex); + if (res != 0) { + return res; + } + + if (esp_rwlock->active_writers == 0) { + esp_rwlock->active_readers++; + res = 0; + } else { + res = EBUSY; + } + + pthread_mutex_unlock(&esp_rwlock->resource_mutex); + + return res; +} + int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { esp_pthread_rwlock_t *esp_rwlock; @@ -219,6 +247,35 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) return 0; } +int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) { + esp_pthread_rwlock_t *esp_rwlock; + int res; + + res = checkrw_lock(rwlock); + if (res != 0) { + return res; + } + + esp_rwlock = (esp_pthread_rwlock_t *)*rwlock; + res = pthread_mutex_trylock(&esp_rwlock->resource_mutex); + if (res != 0) { + return res; + } + + if (esp_rwlock->active_readers > 0 || + esp_rwlock->active_writers > 0 || + esp_rwlock->waiting_writers > 0) { // the last check for waiting_writers is to avoid skipping the queue + res = EBUSY; + } else { + esp_rwlock->active_writers++; + res = 0; + } + + pthread_mutex_unlock(&esp_rwlock->resource_mutex); + + return res; +} + int pthread_rwlock_unlock (pthread_rwlock_t *rwlock) { esp_pthread_rwlock_t *esp_rwlock; diff --git a/components/pthread/test_apps/pthread_unity_tests/main/test_pthread_rwlock.c b/components/pthread/test_apps/pthread_unity_tests/main/test_pthread_rwlock.c index 06df0fcd8a..b42f7c7af9 100644 --- a/components/pthread/test_apps/pthread_unity_tests/main/test_pthread_rwlock.c +++ b/components/pthread/test_apps/pthread_unity_tests/main/test_pthread_rwlock.c @@ -293,3 +293,89 @@ TEST_CASE("wrlock multiple writers wait", "[pthread][rwlock]") TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); vQueueDelete(wait_queue); } + +TEST_CASE("tryrdlock invalid param", "[pthread][rwlock]") +{ + TEST_ASSERT_EQUAL_INT(pthread_rwlock_tryrdlock(NULL), EINVAL); + + pthread_rwlock_t rwlock = 0; + TEST_ASSERT_EQUAL_INT(pthread_rwlock_tryrdlock(&rwlock), EINVAL); +} + +TEST_CASE("tryrdlock fails on write-locked rwlock", "[pthread][rwlock]") +{ + pthread_rwlock_t rwlock; + TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_tryrdlock(&rwlock), EBUSY); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); +} + +TEST_CASE("tryrdlock succeeds on read-locked rwlock", "[pthread][rwlock]") +{ + pthread_rwlock_t rwlock; + TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_tryrdlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); +} + +TEST_CASE("tryrdlock lock statically initialized lock", "[pthread][rwlock]") +{ + pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_tryrdlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); +} + +TEST_CASE("trywrlock invalid param", "[pthread][rwlock]") +{ + TEST_ASSERT_EQUAL_INT(pthread_rwlock_trywrlock(NULL), EINVAL); + + pthread_rwlock_t rwlock = 0; + TEST_ASSERT_EQUAL_INT(pthread_rwlock_trywrlock(&rwlock), EINVAL); +} + +TEST_CASE("trywrlock fails on write-locked rwlock", "[pthread][rwlock]") +{ + pthread_rwlock_t rwlock; + TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_trywrlock(&rwlock), EBUSY); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); +} + +TEST_CASE("trywrlock fails on read-locked rwlock", "[pthread][rwlock]") +{ + pthread_rwlock_t rwlock; + TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_trywrlock(&rwlock), EBUSY); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); +} + +TEST_CASE("trywrlock lock statically initialized lock", "[pthread][rwlock]") +{ + pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_trywrlock(&rwlock), 0); + + TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0); + TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0); +} diff --git a/docs/en/api-reference/system/pthread.rst b/docs/en/api-reference/system/pthread.rst index 535b6c8542..3601c7c72c 100644 --- a/docs/en/api-reference/system/pthread.rst +++ b/docs/en/api-reference/system/pthread.rst @@ -123,18 +123,23 @@ In IDF, POSIX *unnamed* semaphores are implemented. The accessible API is descri * `sem_getvalue() `_ Read/Write Locks -^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ +The following API functions of the POSIX reader-writer locks specification are implemented: + +* `pthread_rwlock_init() `_ -* ``pthread_rwlock_init()`` - The ``attr`` argument is not implemented and is ignored. -* ``pthread_rwlock_destroy()`` -* ``pthread_rwlock_rdlock()`` -* ``pthread_rwlock_wrlock()`` -* ``pthread_rwlock_unlock()`` -Static initializer constant ``PTHREAD_RWLOCK_INITIALIZER`` is supported. +* `pthread_rwlock_destroy() `_ +* `pthread_rwlock_rdlock() `_ +* `pthread_rwlock_tryrdlock() `_ +* `pthread_rwlock_wrlock() `_ +* `pthread_rwlock_trywrlock() `_ +* `pthread_rwlock_unlock() `_ -.. note:: These functions can be called from tasks created using either pthread or FreeRTOS APIs +The static initializer constant ``PTHREAD_RWLOCK_INITIALIZER`` is supported. + +.. note:: These functions can be called from tasks created using either pthread or FreeRTOS APIs. Thread-Specific Data ^^^^^^^^^^^^^^^^^^^^