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 RTEMSScoreFutex
0007  *
0008  * @brief This source file contains the implementation of
0009  *   _Futex_Wait() and _Futex_Wake().
0010  */
0011 
0012 /*
0013  * Copyright (C) 2015, 2016 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 /**
0038  * @defgroup RTEMSScoreFutex Futex Handler
0039  *
0040  * @ingroup RTEMSScore
0041  *
0042  * @brief This group contains the Futex Handler implementation.
0043  *
0044  * The behaviour of the futex operations is defined by Linux, see also:
0045  *
0046  * https://man7.org/linux/man-pages/man2/futex.2.html
0047  */
0048 
0049 #ifdef HAVE_CONFIG_H
0050 #include "config.h"
0051 #endif
0052 
0053 #include <sys/lock.h>
0054 #include <errno.h>
0055 
0056 #include <rtems/score/atomic.h>
0057 #include <rtems/score/chainimpl.h>
0058 #include <rtems/score/threadimpl.h>
0059 #include <rtems/score/threadqimpl.h>
0060 
0061 #define FUTEX_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
0062 
0063 typedef struct {
0064   Thread_queue_Syslock_queue Queue;
0065 } Futex_Control;
0066 
0067 RTEMS_STATIC_ASSERT(
0068   offsetof( Futex_Control, Queue )
0069     == offsetof( struct _Futex_Control, _Queue ),
0070   FUTEX_CONTROL_QUEUE
0071 );
0072 
0073 RTEMS_STATIC_ASSERT(
0074   sizeof( Futex_Control ) == sizeof( struct _Futex_Control ),
0075   FUTEX_CONTROL_SIZE
0076 );
0077 
0078 static Futex_Control *_Futex_Get( struct _Futex_Control *_futex )
0079 {
0080   return (Futex_Control *) _futex;
0081 }
0082 
0083 static Thread_Control *_Futex_Queue_acquire_critical(
0084   Futex_Control        *futex,
0085   Thread_queue_Context *queue_context
0086 )
0087 {
0088   Thread_Control *executing;
0089 
0090   executing = _Thread_Executing;
0091   _Thread_queue_Queue_acquire_critical(
0092     &futex->Queue.Queue,
0093     &executing->Potpourri_stats,
0094     &queue_context->Lock_context.Lock_context
0095   );
0096 
0097   return executing;
0098 }
0099 
0100 static void _Futex_Queue_release(
0101   Futex_Control        *futex,
0102   ISR_Level             level,
0103   Thread_queue_Context *queue_context
0104 )
0105 {
0106   _Thread_queue_Queue_release_critical(
0107     &futex->Queue.Queue,
0108     &queue_context->Lock_context.Lock_context
0109   );
0110   _ISR_Local_enable( level );
0111 }
0112 
0113 /**
0114  * @brief Performs the ``FUTEX_WAIT`` operation.
0115  *
0116  * @param[in, out] _futex is the futex object.
0117  *
0118  * @param[in] uaddr is the address to the futex state.
0119  *
0120  * @param val is the expected futex state value.
0121  *
0122  * @retval 0 Returns zero if the futex state is equal to the expected value.
0123  *   In this case the calling thread is enqueued on the thread queue of the
0124  *   futex object.
0125  *
0126  * @retval EAGAIN Returns EAGAIN if the futex state is not equal to the
0127  *   expected value.
0128  */
0129 int _Futex_Wait( struct _Futex_Control *_futex, int *uaddr, int val )
0130 {
0131   Futex_Control        *futex;
0132   ISR_Level             level;
0133   Thread_queue_Context  queue_context;
0134   Thread_Control       *executing;
0135   int                   eno;
0136 
0137   futex = _Futex_Get( _futex );
0138   _Thread_queue_Context_initialize( &queue_context );
0139   _Thread_queue_Context_ISR_disable( &queue_context, level );
0140   executing = _Futex_Queue_acquire_critical( futex, &queue_context );
0141 
0142   if ( *uaddr == val ) {
0143     _Thread_queue_Context_set_thread_state(
0144       &queue_context,
0145       STATES_WAITING_FOR_FUTEX
0146     );
0147     _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
0148     _Thread_queue_Context_set_ISR_level( &queue_context, level );
0149     _Thread_queue_Enqueue(
0150       &futex->Queue.Queue,
0151       FUTEX_TQ_OPERATIONS,
0152       executing,
0153       &queue_context
0154     );
0155     eno = 0;
0156   } else {
0157     _Futex_Queue_release( futex, level, &queue_context );
0158     eno = EAGAIN;
0159   }
0160 
0161   return eno;
0162 }
0163 
0164 typedef struct {
0165   Thread_queue_Context Base;
0166   int                  count;
0167 } Futex_Context;
0168 
0169 static Thread_Control *_Futex_Flush_filter(
0170   Thread_Control       *the_thread,
0171   Thread_queue_Queue   *queue,
0172   Thread_queue_Context *queue_context
0173 )
0174 {
0175   Futex_Context *context;
0176 
0177   context = (Futex_Context *) queue_context;
0178 
0179   if ( context->count <= 0 ) {
0180     return NULL;
0181   }
0182 
0183   --context->count;
0184 
0185   return the_thread;
0186 }
0187 
0188 /**
0189  * @brief Performs the ``FUTEX_WAKE`` operation.
0190  *
0191  * @param[in, out] _futex is the futex object.
0192  *
0193  * @param count is the maximum count of threads to wake up.
0194  *
0195  * @return Returns the count of woken up threads.
0196  */
0197 int _Futex_Wake( struct _Futex_Control *_futex, int count )
0198 {
0199   Futex_Control *futex;
0200   ISR_Level      level;
0201   Futex_Context  context;
0202 
0203   futex = _Futex_Get( _futex );
0204   _Thread_queue_Context_initialize( &context.Base );
0205   _Thread_queue_Context_ISR_disable( &context.Base, level );
0206   _Futex_Queue_acquire_critical( futex, &context.Base );
0207 
0208   /*
0209    * For some synchronization objects like barriers the _Futex_Wake() must be
0210    * called in the fast path.  Normally there are no threads on the queue, so
0211    * check this condition early.
0212    */
0213   if ( RTEMS_PREDICT_TRUE( _Thread_queue_Is_empty( &futex->Queue.Queue ) ) ) {
0214     _Futex_Queue_release( futex, level, &context.Base );
0215     return 0;
0216   }
0217 
0218   context.count = count;
0219   _Thread_queue_Context_set_ISR_level( &context.Base, level );
0220   return (int) _Thread_queue_Flush_critical(
0221     &futex->Queue.Queue,
0222     FUTEX_TQ_OPERATIONS,
0223     _Futex_Flush_filter,
0224     &context.Base
0225   );
0226 }