pthread : add rwlock implementation
authorVidisha Thapa <thapa.v@samsung.com>
Tue, 25 Apr 2017 10:02:24 +0000 (15:32 +0530)
committerjc_.kim <jc_.kim@samsung.com>
Sun, 2 Jul 2017 23:30:53 +0000 (08:30 +0900)
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 <thapa.v@samsung.com>
lib/libc/pthread/Make.defs
lib/libc/pthread/pthread_rwlock.c [new file with mode: 0644]
lib/libc/pthread/pthread_rwlock_rdlock.c [new file with mode: 0644]
lib/libc/pthread/pthread_rwlock_wrlock.c [new file with mode: 0644]
os/include/pthread.h

index 423ac9d..15356ef 100644 (file)
@@ -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 (file)
index 0000000..665767d
--- /dev/null
@@ -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 <mark@mjs.pw>
+ *
+ * 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 <tinyara/config.h>
+
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <tinyara/semaphore.h>
+
+/****************************************************************************
+ * 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 (file)
index 0000000..ffe233f
--- /dev/null
@@ -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 <mark@mjs.pw>
+ *
+ * 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 <tinyara/config.h>
+
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <tinyara/semaphore.h>
+
+/****************************************************************************
+ * 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 (file)
index 0000000..9a902a6
--- /dev/null
@@ -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 <mark@mjs.pw>
+ *
+ * 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 <tinyara/config.h>
+
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <tinyara/semaphore.h>
+
+/****************************************************************************
+ * 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);
+}
index 76fb60a..a5af179 100644 (file)
@@ -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