pthread_addr_t arg; /* Startup argument */
FAR void *joininfo; /* Detach-able info to support join */
+ /* Robust mutex support *********************************************/
+
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
+ FAR struct pthread_mutex_s *mhead; /* List of mutexes held by thread */
+#endif
+
+ /* Clean-up stack ***************************************************/
+
#ifdef CONFIG_PTHREAD_CLEANUP
/* tos - The index to the next avaiable entry at the top of the stack.
* stack - The pre-allocated clean-up stack memory.
CSRCS += pthread_yield.c pthread_getschedparam.c pthread_setschedparam.c
CSRCS += pthread_mutexinit.c pthread_mutexdestroy.c
CSRCS += pthread_mutexlock.c pthread_mutextrylock.c pthread_mutexunlock.c
-CSRCS += pthread_mutexconsistent.c
CSRCS += pthread_condinit.c pthread_conddestroy.c
CSRCS += pthread_condwait.c pthread_condsignal.c pthread_condbroadcast.c
CSRCS += pthread_barrierinit.c pthread_barrierdestroy.c pthread_barrierwait.c
CSRCS += pthread_initialize.c pthread_completejoin.c pthread_findjoininfo.c
CSRCS += pthread_once.c pthread_release.c pthread_setschedprio.c
+ifneq ($(CONFIG_PTHREAD_MUTEX_UNSAFE),y)
+CSRCS += pthread_mutex.c pthread_mutexconsistent.c pthread_mutexinconsistent.c
+endif
+
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
CSRCS += pthread_condtimedwait.c pthread_kill.c pthread_sigmask.c
endif
void pthread_destroyjoin(FAR struct task_group_s *group, FAR struct join_s *pjoin);
FAR struct join_s *pthread_findjoininfo(FAR struct task_group_s *group, pid_t pid);
void pthread_release(FAR struct task_group_s *group);
-int pthread_givesemaphore(sem_t *sem);
int pthread_takesemaphore(sem_t *sem, bool intr);
+int pthread_givesemaphore(sem_t *sem);
+
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
+int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr);
+int pthread_mutex_give(FAR struct pthread_mutex_s *mutex);
+void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb);
+#else
+#define pthread_mutex_take(m,i) pthread_takesemaphore(&(m)->sem,(i))
+#define pthread_mutex_give(m) pthread_givesemaphore(&(m)->sem)
+#endif
#ifdef CONFIG_MUTEX_TYPES
int pthread_mutexattr_verifytype(int type);
int pthread_cancel(pthread_t thread)
{
- struct pthread_tcb_s *tcb;
+ FAR struct pthread_tcb_s *tcb;
/* First, make sure that the handle references a valid thread */
tcb = (FAR struct pthread_tcb_s *)sched_gettcb((pid_t)thread);
if (!tcb) {
+
/* The pid does not correspond to any known thread. The thread
* has probably already exited.
*/
return ESRCH;
}
+ DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD);
+
/* Check to see if this thread has the non-cancelable bit set in its
* flags. Suppress context changes for a bit so that the flags are stable.
* (the flags should not change in interrupt handling.
* same as pthread_exit(PTHREAD_CANCELED).
*/
- if (tcb == (struct pthread_tcb_s *)g_readytorun.head) {
+ if (tcb == (FAR struct pthread_tcb_s *)g_readytorun.head) {
pthread_exit(PTHREAD_CANCELED);
}
(void)pthread_completejoin((pid_t)thread, PTHREAD_CANCELED);
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
+ /* Recover any mutexes still held by the canceled thread */
+ pthread_mutex_inconsistent(tcb);
+#endif
+
/* Then let task_terminate do the real work */
return task_terminate((pid_t)thread, false);
/* Give up the mutex */
mutex->pid = -1;
- ret = pthread_givesemaphore((sem_t *)&mutex->sem);
+ ret = pthread_mutex_give(mutex);
if (ret != 0) {
/* Restore interrupts (pre-emption will be enabled when
* we fall through the if/then/else)
/* Reacquire the mutex (retaining the ret). */
svdbg("Re-locking...\n");
- status = pthread_takesemaphore((FAR sem_t *)&mutex->sem, false);
+ status = pthread_mutex_take(mutex, false);
if (status == OK) {
mutex->pid = mypid;
} else if (ret == 0) {
sched_lock();
mutex->pid = -1;
- ret = pthread_givesemaphore((sem_t *)&mutex->sem);
+ ret = pthread_mutex_give(mutex);
/* Take the semaphore */
- status = pthread_takesemaphore((FAR sem_t *)&cond->sem, false);
+ status = pthread_mutex_take(mutex, false);
if (ret == OK) {
/* Report the first failure that occurs */
exit(EXIT_FAILURE);
}
+
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
+ /* Recover any mutexes still held by the canceled thread */
+ pthread_mutex_inconsistent((FAR struct pthread_tcb_s *)tcb);
+#endif
/* Perform common task termination logic. This will get called again later
* through logic kicked off by _exit(). However, we need to call it before
--- /dev/null
+/****************************************************************************
+ *
+ * Copyright 2016 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.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/pthread/pthread_mutex.c
+ *
+ * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <stdbool.h>
+#include <sched.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <tinyara/irq.h>
+#include <tinyara/sched.h>
+
+#include "sched/sched.h"
+#include "pthread/pthread.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_mutex_add
+ *
+ * Description:
+ * Add the mutex to the list of mutexes held by this thread.
+ *
+ * Parameters:
+ * mutex - The mux to be locked
+ *
+ * Return Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex)
+{
+ FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task();
+ irqstate_t flags;
+
+ DEBUGASSERT(mutex->flink == NULL);
+
+ /* Add the mutex to the list of mutexes held by this task */
+
+ flags = irqsave();
+ mutex->flink = rtcb->mhead;
+ rtcb->mhead = mutex;
+ irqrestore(flags);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_mutex_take
+ *
+ * Description:
+ * Take the pthread_mutex, waiting if necessary. If successful, add the
+ * mutex to the list of mutexes held by this thread.
+ *
+ * Parameters:
+ * mutex - The mutex to be locked
+ * intr - false: ignore EINTR errors when locking; true treat EINTR as
+ * other errors by returning the errno value
+ *
+ * Return Value:
+ * 0 on success or an errno value on failure.
+ *
+ ****************************************************************************/
+
+int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr)
+{
+ int ret = EINVAL;
+
+ /* Verify input parameters */
+
+ DEBUGASSERT(mutex != NULL);
+ if (mutex != NULL) {
+ /* Make sure that no unexpected context switches occur */
+
+ sched_lock();
+
+ /* Error out if the mutex is already in an inconsistent state. */
+
+ if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) {
+ ret = EOWNERDEAD;
+ } else {
+ /* Take semaphore underlying the mutex. pthread_takesemaphore
+ * returns zero on success and a positive errno value on failure.
+ */
+
+ ret = pthread_takesemaphore(&mutex->sem, intr);
+ if (ret == OK) {
+ /* Check if the holder of the mutex has terminated without
+ * releasing. In that case, the state of the mutex is
+ * inconsistent and we return EOWNERDEAD.
+ */
+
+ if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) {
+ ret = EOWNERDEAD;
+ }
+
+ /* Add the mutex to the list of mutexes held by this task */
+
+ else {
+ pthread_mutex_add(mutex);
+ }
+ }
+ }
+
+ sched_unlock();
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pthread_mutex_trytake
+ *
+ * Description:
+ * Try to take the pthread_mutex without waiting. If successful, add the
+ * mutex to the list of mutexes held by this thread.
+ *
+ * Parameters:
+ * mutex - The mutex to be locked
+ * intr - false: ignore EINTR errors when locking; true treat EINTR as
+ * other errors by returning the errno value
+ *
+ * Return Value:
+ * 0 on success or an errno value on failure.
+ *
+ ****************************************************************************/
+
+int pthread_mutex_trytake(FAR struct pthread_mutex_s *mutex)
+{
+ int ret = EINVAL;
+
+ /* Verify input parameters */
+
+ DEBUGASSERT(mutex != NULL);
+ if (mutex != NULL) {
+ /* Make sure that no unexpected context switches occur */
+
+ sched_lock();
+
+ /* Error out if the mutex is already in an inconsistent state. */
+
+ if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) {
+ ret = EOWNERDEAD;
+ } else {
+ /* Try to take the semaphore underlying the mutex */
+
+ ret = sem_trywait(&mutex->sem);
+ if (ret < OK) {
+ ret = get_errno();
+ } else {
+ /* Add the mutex to the list of mutexes held by this task */
+
+ pthread_mutex_add(mutex);
+ }
+ }
+
+ sched_unlock();
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pthread_mutex_give
+ *
+ * Description:
+ * Take the pthread_mutex and, if successful, add the mutex to the ist of
+ * mutexes held by this thread.
+ *
+ * Parameters:
+ * mutex - The mux to be unlocked
+ *
+ * Return Value:
+ * 0 on success or an errno value on failure.
+ *
+ ****************************************************************************/
+
+int pthread_mutex_give(FAR struct pthread_mutex_s *mutex)
+{
+ FAR struct pthread_mutex_s *curr;
+ FAR struct pthread_mutex_s *prev;
+ int ret = EINVAL;
+
+ /* Verify input parameters */
+
+ DEBUGASSERT(mutex != NULL);
+ if (mutex != NULL) {
+ FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task();
+ irqstate_t flags;
+
+ flags = irqsave();
+
+ /* Remove the mutex from the list of mutexes held by this task */
+
+ for (prev = NULL, curr = rtcb->mhead; curr != NULL && curr != mutex; prev = curr, curr = curr->flink) ;
+
+ DEBUGASSERT(curr == mutex);
+
+ /* Remove the mutex from the list. prev == NULL means that the mutex
+ * to be removed is at the head of the list.
+ */
+
+ if (prev == NULL) {
+ rtcb->mhead = mutex->flink;
+ } else {
+ prev->flink = mutex->flink;
+ }
+
+ mutex->flink = NULL;
+ irqrestore(flags);
+
+ /* Now release the underlying semaphore */
+
+ ret = pthread_givesemaphore(&mutex->sem);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pthread_disable_cancel() and pthread_enable_cancel()
+ *
+ * Description:
+ * Temporarily disable cancellation and return old cancel state, which
+ * can later be restored. This is useful when a cancellation point
+ * function is called from within the OS by a non-cancellation point:
+ * In certain such cases, we need to defer the cancellation to prevent
+ * bad things from happening.
+ *
+ * Parameters:
+ * saved cancel flags for pthread_enable_cancel()
+ *
+ * Return Value:
+ * old cancel flags for pthread_disable_cancel()
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CANCELLATION_POINTS
+uint16_t pthread_disable_cancel(void)
+{
+ FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)this_task();
+ irqstate_t flags;
+ uint16_t old;
+
+ /* We need perform the following operations from within a critical section
+ * because it can compete with interrupt level activity.
+ */
+
+ flags = irqsave();
+ old = tcb->cmn.flags & (TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
+ tcb->cmn.flags &= ~(TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
+ irqrestore(flags);
+ return old;
+}
+
+void pthread_enable_cancel(uint16_t cancelflags)
+{
+ FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)this_task();
+ irqstate_t flags;
+
+ /* We need perform the following operations from within a critical section
+ * because it can compete with interrupt level activity.
+ */
+
+ flags = irqsave();
+ tcb->cmn.flags |= cancelflags;
+
+ /* What should we do if there is a pending cancellation?
+ *
+ * If the thread is executing with deferred cancellation, we need do
+ * nothing more; the cancellation cannot occur until the next
+ * cancellation point.
+ *
+ * However, if the thread is executing in asynchronous cancellation mode,
+ * then we need to terminate now by simply calling pthread_exit().
+ */
+
+ if ((tcb->cmn.flags & TCB_FLAG_CANCEL_DEFERRED) == 0 && (tcb->cmn.flags & TCB_FLAG_CANCEL_PENDING) != 0) {
+ pthread_exit(NULL);
+ }
+
+ irqrestore(flags);
+}
+#endif /* CONFIG_CANCELLATION_POINTS */
/* The thread associated with the PID no longer exists */
mutex->pid = -1;
- mutex->flags &= _PTHREAD_MFLAGS_ROBUST;
+ mutex->flags = 0;
#ifdef CONFIG_MUTEX_TYPES
mutex->nlocks = 0;
#endif
--- /dev/null
+/****************************************************************************
+ *
+ * Copyright 2016 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.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * kernel/pthread/pthread_mutexinconsistent.c
+ *
+ * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <pthread.h>
+#include <sched.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <tinyara/sched.h>
+#include <tinyara/semaphore.h>
+
+#include "pthread/pthread.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pthread_mutex_inconsistent
+ *
+ * Description:
+ * This function is called when a pthread is terminated via either
+ * pthread_exit() or pthread_cancel(). It will check for any mutexes
+ * held by exitting thread. It will mark them as inconsistent and
+ * then wake up the highest priority waiter for the mutex. That
+ * instance of pthread_mutex_lock() will then return EOWNERDEAD.
+ *
+ * Input Parameters:
+ * tcb -- a reference to the TCB of the exitting pthread.
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb)
+{
+ FAR struct pthread_mutex_s *mutex;
+ irqstate_t flags;
+
+ DEBUGASSERT(tcb != NULL);
+
+ sched_lock();
+
+ /* Remove and process each mutex from the list of mutexes held by this task */
+
+ while (tcb->mhead != NULL) {
+ /* Remove the mutex from the TCB list */
+
+ flags = irqsave();
+ mutex = tcb->mhead;
+ tcb->mhead = mutex->flink;
+ mutex->flink = NULL;
+ irqrestore(flags);
+
+ /* Mark the mutex as INCONSISTENT and wake up any waiting thread */
+
+ mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT;
+ (void)pthread_givesemaphore(&mutex->sem);
+ }
+
+ sched_unlock();
+}
}
#endif
- /* Set up attributes unique to the mutex type */
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
+ /* Initial internal fields of the mutex */
+
+ mutex->flink = NULL;
+ mutex->flags = 0;
+#endif
#ifdef CONFIG_MUTEX_TYPES
+ /* Set up attributes unique to the mutex type */
+
mutex->type = type;
mutex->nlocks = 0;
#endif
sched_lock();
- /* Does this thread already hold the semaphore? */
+#ifdef CONFIG_MUTEX_TYPES
+ /* All mutex types except for NORMAL (and DEFAULT) will return
+ * and an error error if the caller does not hold the mutex.
+ */
- if (mutex->pid == mypid) {
+ if (mutex->type != PTHREAD_MUTEX_NORMAL && mutex->pid == mypid) {
/* Yes.. Is this a recursive mutex? */
-#ifdef CONFIG_MUTEX_TYPES
if (mutex->type == PTHREAD_MUTEX_RECURSIVE) {
/* Yes... just increment the number of locks held and return success */
- mutex->nlocks++;
- ret = OK;
+ if (mutex->nlocks < INT16_MAX) {
+ mutex->nlocks++;
+ ret = OK;
+ } else {
+ ret = EOVERFLOW;
+ }
} else
-#endif
{
/* No, then we would deadlock... return an error (default behavior
* is like PTHREAD_MUTEX_ERRORCHECK)
sdbg("Returning EDEADLK\n");
ret = EDEADLK;
}
- }
+ } else
+#endif /* CONFIG_MUTEX_TYPES */
+
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* The calling thread does not hold the semaphore. The correct
* behavior for the 'robust' mutex is to verify that the holder of the
* mutex is still valid. This is protection from the case
* where the holder of the mutex has exitted without unlocking it.
*/
- else if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) {
+ if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) {
DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
+ DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0);
/* A thread holds the mutex, but there is no such thread. POSIX
* requires that the 'robust' mutex return EOWNERDEAD in this case.
* fo fix the mutex.
*/
+ mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT;
ret = EOWNERDEAD;
} else {
- /* Take the underlying semaphore, waiting if necessary */
+#endif /* !CONFIG_PTHREAD_MUTEX_UNSAFE */
- ret = pthread_takesemaphore((FAR sem_t *)&mutex->sem, true);
+ /* Take the underlying semaphore, waiting if necessary. NOTE that
+ * is required to deadlock for the case of the non-robust NORMAL or
+ * default mutex.
+ */
+
+ ret = pthread_mutex_take(mutex, true);
/* If we succussfully obtained the semaphore, then indicate
* that we own it.
#endif
}
- /* Check if we were awakened by a signal. This might happen if the
- * tasking holding the mutex just exitted.
- */
-
- else if (ret == EINTR) {
- }
}
sched_unlock();
/* sem_trywait failed */
else {
- /* Did it fail because the semaphore was not avaialabl? */
+ /* Did it fail because the semaphore was not available? */
int errcode = get_errno();
if (errcode == EAGAIN) {
#ifdef CONFIG_MUTEX_TYPES
if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->pid == mypid) {
/* Increment the number of locks held and return successfully. */
- mutex->nlocks++;
- ret = OK;
+ if (mutex->nlocks < INT16_MAX) {
+ mutex->nlocks++;
+ ret = OK;
+ } else {
+ ret = EOVERFLOW;
+ }
} else
#endif
+
+#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
/* The calling thread does not hold the semaphore. The correct
* behavior for the 'robust' mutex is to verify that the holder of
* the mutex is still valid. This is protection from the case
if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) {
DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */
+ DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0);
/* A thread holds the mutex, but there is no such thread.
* POSIX requires that the 'robust' mutex return EOWNERDEAD
* call pthread_mutx_consistent() fo fix the mutex.
*/
+ mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT;
ret = EOWNERDEAD;
}
/* The mutex is locked by another, active thread */
- else {
+ else
+#endif /* CONFIG_PTHREAD_MUTEX_UNSAFE */
+ {
ret = EBUSY;
}
sched_lock();
- /* Does the calling thread own the semaphore? */
- if (mutex->pid != (int)getpid()) {
+#if !defined(CONFIG_PTHREAD_MUTEX_UNSAFE) || !defined(CONFIG_MUTEX_TYPES)
+ /* Does the calling thread own the semaphore? Should we report the
+ * EPERM error? This applies to robust NORMAL (and DEFAULT) mutexes
+ * as well as ERRORCHECK and RECURSIVE mutexes.
+ */
+
+ if (mutex->pid != (int)getpid())
+#else
+ /* Does the calling thread own the semaphore? Should we report the
+ * EPERM error? This applies to ERRORCHECK and RECURSIVE mutexes.
+ */
+ if (mutex->type != PTHREAD_MUTEX_NORMAL && mutex->pid != (int)getpid())
+#endif
+ {
/* No... return an error (default behavior is like PTHREAD_MUTEX_ERRORCHECK) */
sdbg("Holder=%d returning EPERM\n", mutex->pid);
ret = EPERM;
- }
+ } else
- /* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
#ifdef CONFIG_MUTEX_TYPES
- else if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->nlocks > 1) {
+ /* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
+
+ if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->nlocks > 1) {
/* This is a recursive mutex and we there are multiple locks held. Retain
* the mutex lock, just decrement the count of locks held, and return
* success.
mutex->nlocks--;
ret = OK;
}
-#endif
+ else
+
+#endif /* CONFIG_MUTEX_TYPES */
/* This is either a non-recursive mutex or is the outermost unlock of
* a recursive mutex.
+ *
+ * In the case where the calling thread is NOT the holder of the thread,
+ * the behavior is undefined per POSIX. Here we do the same as GLIBC:
+ * We allow the other thread to release the mutex even though it does
+ * not own it.
*/
+
- else {
+ {
/* Nullify the pid and lock count then post the semaphore */
mutex->pid = -1;
#ifdef CONFIG_MUTEX_TYPES
mutex->nlocks = 0;
#endif
- ret = pthread_givesemaphore((sem_t *)&mutex->sem);
+ ret = pthread_mutex_give(mutex);
}
sched_unlock();
}
#define MAX_TASKS_MASK (CONFIG_MAX_TASKS-1)
#define PIDHASH(pid) ((pid) & MAX_TASKS_MASK)
+/* These are macros to access the current CPU and the current task on a CPU.
+ * These macros are intended to support a future SMP implementation.
+ */
+#define current_task(cpu) ((FAR struct tcb_s *)g_readytorun.head)
+#define this_cpu() (0)
+#define this_task() (current_task(this_cpu()))
+
+
/****************************************************************************
* Public Type Definitions
****************************************************************************/