Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:26

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScore
0007  *
0008  * @brief This source file contains the implementation of
0009  *   _Condition_Wait(), _Condition_Wait_timed(), _Condition_Wait_recursive(),
0010  *   _Condition_Wait_recursive_timed(),
0011  *   _Condition_Wait_recursive_timed_ticks(), _Condition_Signal(), and
0012  *   _Condition_Broadcast().
0013  */
0014 
0015 /*
0016  * Copyright (C) 2015, 2016 embedded brains GmbH & Co. KG
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043 
0044 #include <sys/lock.h>
0045 #include <errno.h>
0046 #include <limits.h>
0047 
0048 #include <rtems/score/atomic.h>
0049 #include <rtems/score/chainimpl.h>
0050 #include <rtems/score/threadimpl.h>
0051 #include <rtems/score/threadqimpl.h>
0052 #include <rtems/score/todimpl.h>
0053 #include <rtems/score/watchdogimpl.h>
0054 
0055 #define CONDITION_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
0056 
0057 typedef struct {
0058   Thread_queue_Syslock_queue Queue;
0059 } Condition_Control;
0060 
0061 RTEMS_STATIC_ASSERT(
0062   offsetof( Condition_Control, Queue )
0063     == offsetof( struct _Condition_Control, _Queue ),
0064   CONDITION_CONTROL_QUEUE
0065 );
0066 
0067 RTEMS_STATIC_ASSERT(
0068   sizeof( Condition_Control ) == sizeof( struct _Condition_Control ),
0069   CONDITION_CONTROL_SIZE
0070 );
0071 
0072 static Condition_Control *_Condition_Get(
0073   struct _Condition_Control *_condition
0074 )
0075 {
0076   return (Condition_Control *) _condition;
0077 }
0078 
0079 static Thread_Control *_Condition_Queue_acquire_critical(
0080   Condition_Control    *condition,
0081   Thread_queue_Context *queue_context
0082 )
0083 {
0084   Thread_Control *executing;
0085 
0086   executing = _Thread_Executing;
0087   _Thread_queue_Queue_acquire_critical(
0088     &condition->Queue.Queue,
0089     &executing->Potpourri_stats,
0090     &queue_context->Lock_context.Lock_context
0091   );
0092 
0093   return executing;
0094 }
0095 
0096 static void _Condition_Queue_release(
0097   Condition_Control    *condition,
0098   Thread_queue_Context *queue_context
0099 )
0100 {
0101   _Thread_queue_Queue_release(
0102     &condition->Queue.Queue,
0103     &queue_context->Lock_context.Lock_context
0104   );
0105 }
0106 
0107 typedef struct {
0108   Thread_queue_Context   Base;
0109   struct _Mutex_Control *mutex;
0110 } Condition_Enqueue_context;
0111 
0112 static void _Condition_Mutex_release( Thread_queue_Context *queue_context )
0113 {
0114   Condition_Enqueue_context *context;
0115 
0116   context = (Condition_Enqueue_context *) queue_context;
0117   _Mutex_Release( context->mutex );
0118 }
0119 
0120 static void _Condition_Enqueue_no_timeout(
0121   Thread_queue_Queue   *queue,
0122   Thread_Control       *the_thread,
0123   Per_CPU_Control      *cpu_self,
0124   Thread_queue_Context *queue_context
0125 )
0126 {
0127   _Condition_Mutex_release( queue_context );
0128 }
0129 
0130 static void _Condition_Enqueue_with_timeout(
0131   Thread_queue_Queue   *queue,
0132   Thread_Control       *the_thread,
0133   Per_CPU_Control      *cpu_self,
0134   Thread_queue_Context *queue_context
0135 )
0136 {
0137   _Thread_queue_Add_timeout_realtime_timespec(
0138     queue,
0139     the_thread,
0140     cpu_self,
0141     queue_context
0142   );
0143   _Condition_Mutex_release( queue_context );
0144 }
0145 
0146 static Thread_Control *_Condition_Do_wait(
0147   struct _Condition_Control *_condition,
0148   struct _Mutex_Control     *_mutex,
0149   Condition_Enqueue_context *context
0150 )
0151 {
0152   Condition_Control *condition;
0153   Thread_Control    *executing;
0154 
0155   context->mutex = _mutex;
0156   condition = _Condition_Get( _condition );
0157   _ISR_lock_ISR_disable( &context->Base.Lock_context.Lock_context );
0158   executing = _Condition_Queue_acquire_critical( condition, &context->Base );
0159   _Thread_queue_Context_set_thread_state(
0160     &context->Base,
0161     STATES_WAITING_FOR_CONDITION_VARIABLE
0162   );
0163   _Thread_queue_Enqueue(
0164     &condition->Queue.Queue,
0165     CONDITION_TQ_OPERATIONS,
0166     executing,
0167     &context->Base
0168   );
0169 
0170   return executing;
0171 }
0172 
0173 void _Condition_Wait(
0174   struct _Condition_Control *_condition,
0175   struct _Mutex_Control     *_mutex
0176 )
0177 {
0178   Condition_Enqueue_context context;
0179 
0180   _Thread_queue_Context_initialize( &context.Base );
0181   _Thread_queue_Context_set_enqueue_callout(
0182     &context.Base,
0183     _Condition_Enqueue_no_timeout
0184   );
0185   _Condition_Do_wait( _condition, _mutex, &context );
0186   _Mutex_Acquire( _mutex );
0187 }
0188 
0189 int _Condition_Wait_timed(
0190   struct _Condition_Control *_condition,
0191   struct _Mutex_Control     *_mutex,
0192   const struct timespec     *abstime
0193 )
0194 {
0195   Condition_Enqueue_context  context;
0196   Thread_Control            *executing;
0197   int                        eno;
0198 
0199   _Thread_queue_Context_initialize( &context.Base );
0200   _Thread_queue_Context_set_enqueue_callout(
0201     &context.Base,
0202     _Condition_Enqueue_with_timeout
0203   );
0204   _Thread_queue_Context_set_timeout_argument( &context.Base, abstime, true );
0205   executing = _Condition_Do_wait( _condition, _mutex, &context );
0206   eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
0207   _Mutex_Acquire( _mutex );
0208 
0209   return eno;
0210 }
0211 
0212 static unsigned int _Condition_Unnest_mutex(
0213   struct _Mutex_recursive_Control *_mutex
0214 )
0215 {
0216   unsigned int nest_level;
0217 
0218   nest_level = _mutex->_nest_level;
0219   _mutex->_nest_level = 0;
0220 
0221   return nest_level;
0222 }
0223 
0224 void _Condition_Wait_recursive(
0225   struct _Condition_Control       *_condition,
0226   struct _Mutex_recursive_Control *_mutex
0227 )
0228 {
0229   Condition_Enqueue_context context;
0230   unsigned int              nest_level;
0231 
0232   _Thread_queue_Context_initialize( &context.Base );
0233   _Thread_queue_Context_set_enqueue_callout(
0234     &context.Base,
0235     _Condition_Enqueue_no_timeout
0236   );
0237   nest_level = _Condition_Unnest_mutex( _mutex );
0238   _Condition_Do_wait( _condition, &_mutex->_Mutex, &context );
0239   _Mutex_recursive_Acquire( _mutex );
0240   _mutex->_nest_level = nest_level;
0241 }
0242 
0243 int _Condition_Wait_recursive_timed(
0244   struct _Condition_Control       *_condition,
0245   struct _Mutex_recursive_Control *_mutex,
0246   const struct timespec           *abstime
0247 )
0248 {
0249   Condition_Enqueue_context  context;
0250   Thread_Control            *executing;
0251   int                        eno;
0252   unsigned int               nest_level;
0253 
0254   _Thread_queue_Context_initialize( &context.Base );
0255   _Thread_queue_Context_set_enqueue_callout(
0256     &context.Base,
0257     _Condition_Enqueue_with_timeout
0258   );
0259   _Thread_queue_Context_set_timeout_argument( &context.Base, abstime, true );
0260   nest_level = _Condition_Unnest_mutex( _mutex );
0261   executing = _Condition_Do_wait( _condition, &_mutex->_Mutex, &context );
0262   eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
0263   _Mutex_recursive_Acquire( _mutex );
0264   _mutex->_nest_level = nest_level;
0265 
0266   return eno;
0267 }
0268 
0269 typedef struct {
0270   Thread_queue_Context Base;
0271   int                  count;
0272 } Condition_Flush_context;
0273 
0274 static Thread_Control *_Condition_Flush_filter(
0275   Thread_Control       *the_thread,
0276   Thread_queue_Queue   *queue,
0277   Thread_queue_Context *queue_context
0278 )
0279 {
0280   Condition_Flush_context *context;
0281 
0282   context = (Condition_Flush_context *) queue_context;
0283 
0284   if ( context->count <= 0 ) {
0285     return NULL;
0286   }
0287 
0288   --context->count;
0289 
0290   return the_thread;
0291 }
0292 
0293 static void _Condition_Wake( struct _Condition_Control *_condition, int count )
0294 {
0295   Condition_Control       *condition;
0296   Condition_Flush_context  context;
0297 
0298   condition = _Condition_Get( _condition );
0299   _Thread_queue_Context_initialize( &context.Base );
0300   _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context );
0301   _Condition_Queue_acquire_critical( condition, &context.Base );
0302 
0303   /*
0304    * In common uses cases of condition variables there are normally no threads
0305    * on the queue, so check this condition early.
0306    */
0307   if (
0308     RTEMS_PREDICT_TRUE( _Thread_queue_Is_empty( &condition->Queue.Queue ) )
0309   ) {
0310     _Condition_Queue_release( condition, &context.Base );
0311     return;
0312   }
0313 
0314   context.count = count;
0315   _Thread_queue_Flush_critical(
0316     &condition->Queue.Queue,
0317     CONDITION_TQ_OPERATIONS,
0318     _Condition_Flush_filter,
0319     &context.Base
0320   );
0321 }
0322 
0323 void _Condition_Signal( struct _Condition_Control *_condition )
0324 {
0325   _Condition_Wake( _condition, 1 );
0326 }
0327 
0328 void _Condition_Broadcast( struct _Condition_Control *_condition )
0329 {
0330   _Condition_Wake( _condition, INT_MAX );
0331 }