From: Vidisha Thapa Date: Tue, 25 Apr 2017 10:02:24 +0000 (+0530) Subject: pthread : add rwlock implementation X-Git-Tag: 1.1_Public_Release~472^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=95287d6e5add8a9666dc5cb95ef8116f82fa45cb;p=rtos%2Ftinyara.git pthread : add rwlock implementation This patch adds pthread read write locks. This implementation is ported by referring os test in latest nuttx. Change-Id: I7f01845f36eb931405ca27f3b3b54cd9599a2e93 Signed-off-by: Vidisha Thapa --- diff --git a/lib/libc/pthread/Make.defs b/lib/libc/pthread/Make.defs index 423ac9d..15356ef 100644 --- a/lib/libc/pthread/Make.defs +++ b/lib/libc/pthread/Make.defs @@ -69,6 +69,7 @@ CSRCS += pthread_mutexattrsettype.c pthread_mutexattrgettype.c CSRCS += pthread_mutexattr_setrobust.c pthread_mutexattr_getrobust.c CSRCS += pthread_setcancelstate.c pthread_setcanceltype.c CSRCS += pthread_testcancel.c +CSRCS += pthread_rwlock.c pthread_rwlock_rdlock.c pthread_rwlock_wrlock.c ifeq ($(CONFIG_ENABLE_IOTIVITY),y) CSRCS += pthread_condattrsetclock.c diff --git a/lib/libc/pthread/pthread_rwlock.c b/lib/libc/pthread/pthread_rwlock.c new file mode 100644 index 0000000..665767d --- /dev/null +++ b/lib/libc/pthread/pthread_rwlock.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * + * Copyright 2017 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ +/**************************************************************************** + * lib/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; + lock->write_in_progress = false; + + 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->write_in_progress) { + rw_lock->write_in_progress = false; + + err = pthread_cond_broadcast(&rw_lock->cv); + } else { + err = EINVAL; + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} diff --git a/lib/libc/pthread/pthread_rwlock_rdlock.c b/lib/libc/pthread/pthread_rwlock_rdlock.c new file mode 100644 index 0000000..ffe233f --- /dev/null +++ b/lib/libc/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,161 @@ +/**************************************************************************** + * + * Copyright 2017 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ +/**************************************************************************** + * lib/libc/pthread/pthread_rwlock_rdlock.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 + ****************************************************************************/ + +#ifdef CONFIG_PTHREAD_CLEANUP +static void rdlock_cleanup(FAR void *arg) +{ + FAR pthread_rwlock_t *rw_lock = (FAR pthread_rwlock_t *) arg; + + (void)pthread_mutex_unlock(&rw_lock->lock); +} +#endif + +static int tryrdlock(FAR pthread_rwlock_t *rw_lock) +{ + int err; + + if (rw_lock->num_writers > 0 || rw_lock->write_in_progress) { + 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; + } +#ifdef CONFIG_PTHREAD_CLEANUP + pthread_cleanup_push(&rdlock_cleanup, rw_lock); +#endif + 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; + } + } +#ifdef CONFIG_PTHREAD_CLEANUP + pthread_cleanup_pop(0); +#endif + + 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/lib/libc/pthread/pthread_rwlock_wrlock.c b/lib/libc/pthread/pthread_rwlock_wrlock.c new file mode 100644 index 0000000..9a902a6 --- /dev/null +++ b/lib/libc/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,169 @@ +/**************************************************************************** + * + * Copyright 2017 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ +/**************************************************************************** + * lib/libc/pthread/pthread_rwlock_wrlock.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 + ****************************************************************************/ + +#ifdef CONFIG_PTHREAD_CLEANUP +static void wrlock_cleanup(FAR void *arg) +{ + FAR pthread_rwlock_t *rw_lock = (FAR pthread_rwlock_t *) arg; + + rw_lock->num_writers--; + (void)pthread_mutex_unlock(&rw_lock->lock); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_rwlock_wrlock + * + * Description: + * Locks a read/write lock for writing + * + * 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->write_in_progress) { + err = EBUSY; + } else { + rw_lock->write_in_progress = true; + } + + 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); + + if (err != 0) { + return err; + } + + if (rw_lock->num_writers == UINT_MAX) { + err = EAGAIN; + goto exit_with_mutex; + } + + rw_lock->num_writers++; + +#ifdef CONFIG_PTHREAD_CLEANUP + pthread_cleanup_push(&wrlock_cleanup, rw_lock); +#endif + while (rw_lock->write_in_progress || rw_lock->num_readers > 0) { + 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; + } + } +#ifdef CONFIG_PTHREAD_CLEANUP + pthread_cleanup_pop(0); +#endif + + 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; +} + +int pthread_rwlock_wrlock(FAR pthread_rwlock_t *rw_lock) +{ + return pthread_rwlock_timedwrlock(rw_lock, NULL); +} diff --git a/os/include/pthread.h b/os/include/pthread.h index 76fb60a..a5af179 100644 --- a/os/include/pthread.h +++ b/os/include/pthread.h @@ -378,6 +378,22 @@ typedef bool pthread_once_t; typedef CODE void (*pthread_cleanup_t)(FAR void *arg); #endif +struct pthread_rwlock_s { + pthread_mutex_t lock; + pthread_cond_t cv; + unsigned int num_readers; + unsigned int num_writers; + bool write_in_progress; +}; + +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, false} + /* Forware references */ struct sched_param; /* Defined in sched.h */ @@ -445,7 +461,7 @@ int pthread_cancel(pthread_t thread); */ int pthread_setcancelstate(int state, FAR int *oldstate); -int pthread_setcanceltype(int type, FAR int *oldtype); +int pthread_setcanceltype(int type, FAR int *oldtype); /** * @cond @@ -831,6 +847,18 @@ int pthread_barrierattr_setpshared(FAR pthread_barrierattr_t *attr, int pshared) /** * @} *///end for PTHREAD_KERNEL +/* 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); + #ifdef __cplusplus } #endif