sched/pthread_cond[timed]wait.c: return special mutex state.

A mutex may be configured with rather exotic options such as recursive, unsafe, etc.  The availability of these mutex options is controlled by configuation settings.  When each option is enabled, additional fields are managed inside of the mutex structure.

pthread_cond_wait() and pthread_timed_wait() do the following atomically:  (1) unlock the mutex, (2) wait for the condition, and (3) restore the mutex lock.  When that lock is restored, pthread_cond_[timed]wait() must also restore the exact configuration of the mutex data structure if these "exotic" features are enabled.
This commit is contained in:
Gregory Nutt 2020-04-05 16:33:44 -06:00 committed by Abdelatif Guettouche
parent 64b398f4c6
commit a48c784cc4
2 changed files with 79 additions and 51 deletions

View File

@ -1,35 +1,20 @@
/****************************************************************************
* sched/pthread/pthread_condtimedwait.c
*
* Copyright (C) 2007-2009, 2013-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* 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.
*
****************************************************************************/
@ -164,7 +149,8 @@ static void pthread_condtimedout(int argc, uint32_t pid, uint32_t signo)
*
****************************************************************************/
int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
int pthread_cond_timedwait(FAR pthread_cond_t *cond,
FAR pthread_mutex_t *mutex,
FAR const struct timespec *abstime)
{
FAR struct tcb_s *rtcb = this_task();
@ -227,8 +213,9 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
sched_lock();
flags = enter_critical_section();
/* Convert the timespec to clock ticks. We must disable pre-emption
* here so that this time stays valid until the wait begins.
/* Convert the timespec to clock ticks. We must disable pre-
* emption here so that this time stays valid until the wait
* begins.
*/
ret = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
@ -242,15 +229,15 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
}
else
{
/* Check the absolute time to wait. If it is now or in the past, then
* just return with the timedout condition.
/* Check the absolute time to wait. If it is now or in the
* past, then just return with the timedout condition.
*/
if (ticks <= 0)
{
/* Restore interrupts and indicate that we have already timed out.
* (pre-emption will be enabled when we fall through the
* if/then/else
/* Restore interrupts and indicate that we have already
* timed out. (pre-emption will be enabled when we fall
* through the if/then/else
*/
leave_critical_section(flags);
@ -258,14 +245,28 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
}
else
{
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
uint8_t mflags;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_TYPES
uint8_t type;
int16_t nlocks;
#endif
/* Give up the mutex */
mutex->pid = -1;
ret = pthread_mutex_give(mutex);
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
mflags = mutex->flags;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_TYPES
type = mutex->type;
nlocks = mutex->nlocks;
#endif
ret = pthread_mutex_give(mutex);
if (ret != 0)
{
/* Restore interrupts (pre-emption will be enabled when
* we fall through the if/then/else)
/* Restore interrupts (pre-emption will be enabled
* when we fall through the if/then/else)
*/
leave_critical_section(flags);
@ -279,10 +280,10 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
2, (uint32_t)mypid,
(uint32_t)SIGCONDTIMEDOUT);
/* Take the condition semaphore. Do not restore interrupts
* until we return from the wait. This is necessary to
* make sure that the watchdog timer and the condition wait
* are started atomically.
/* Take the condition semaphore. Do not restore
* interrupts until we return from the wait. This is
* necessary to make sure that the watchdog timer and
* the condition wait are started atomically.
*/
status = nxsem_wait((FAR sem_t *)&cond->sem);
@ -293,7 +294,8 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
{
/* NO.. Handle the special case where the semaphore
* wait was awakened by the receipt of a signal --
* presumably the signal posted by pthread_condtimedout().
* presumably the signal posted by
* pthread_condtimedout().
*/
if (status == -EINTR)
@ -307,10 +309,10 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
}
}
/* The interrupts stay disabled until after we sample the
* errno. This is because when debug is enabled and the
* console is used for debug output, then the errno can be
* altered by interrupt handling! (bad)
/* The interrupts stay disabled until after we sample
* the errno. This is because when debug is enabled
* and the console is used for debug output, then the
* errno can be altered by interrupt handling! (bad)
*/
leave_critical_section(flags);
@ -323,11 +325,18 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
status = pthread_mutex_take(mutex, NULL, false);
if (status == OK)
{
mutex->pid = mypid;
mutex->pid = mypid;
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
mutex->flags = mflags;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_TYPES
mutex->type = type;
mutex->nlocks = nlocks;
#endif
}
else if (ret == 0)
{
ret = status;
ret = status;
}
}

View File

@ -80,12 +80,27 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex)
}
else
{
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
uint8_t mflags;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_TYPES
uint8_t type;
int16_t nlocks;
#endif
/* Give up the mutex */
sinfo("Give up mutex / take cond\n");
sched_lock();
mutex->pid = -1;
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
mflags = mutex->flags;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_TYPES
type = mutex->type;
nlocks = mutex->nlocks;
#endif
ret = pthread_mutex_give(mutex);
/* Take the semaphore. This may be awakened only be a signal (EINTR)
@ -125,9 +140,13 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex)
{
/* Yes.. Then initialize it properly */
mutex->pid = getpid();
mutex->pid = getpid();
#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE
mutex->flags = mflags;
#endif
#ifdef CONFIG_PTHREAD_MUTEX_TYPES
mutex->nlocks = 1;
mutex->type = type;
mutex->nlocks = nlocks;
#endif
}
}