source: rtems/cpukit/score/src/condition.c @ 255fe43

Last change on this file since 255fe43 was 255fe43, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 20:40:44

cpukit/: Scripted embedded brains header file clean up

Updates #4625.

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScore
7 *
8 * @brief This source file contains the implementation of
9 *   _Condition_Wait(), _Condition_Wait_timed(), _Condition_Wait_recursive(),
10 *   _Condition_Wait_recursive_timed(),
11 *   _Condition_Wait_recursive_timed_ticks(), _Condition_Signal(), and
12 *   _Condition_Broadcast().
13 */
14
15/*
16 * Copyright (c) 2015, 2016 embedded brains GmbH.  All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
43
44#include <sys/lock.h>
45#include <errno.h>
46#include <limits.h>
47
48#include <rtems/score/atomic.h>
49#include <rtems/score/chainimpl.h>
50#include <rtems/score/threadimpl.h>
51#include <rtems/score/threadqimpl.h>
52#include <rtems/score/todimpl.h>
53#include <rtems/score/watchdogimpl.h>
54
55#define CONDITION_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
56
57typedef struct {
58  Thread_queue_Syslock_queue Queue;
59} Condition_Control;
60
61RTEMS_STATIC_ASSERT(
62  offsetof( Condition_Control, Queue )
63    == offsetof( struct _Condition_Control, _Queue ),
64  CONDITION_CONTROL_QUEUE
65);
66
67RTEMS_STATIC_ASSERT(
68  sizeof( Condition_Control ) == sizeof( struct _Condition_Control ),
69  CONDITION_CONTROL_SIZE
70);
71
72static Condition_Control *_Condition_Get(
73  struct _Condition_Control *_condition
74)
75{
76  return (Condition_Control *) _condition;
77}
78
79static Thread_Control *_Condition_Queue_acquire_critical(
80  Condition_Control    *condition,
81  Thread_queue_Context *queue_context
82)
83{
84  Thread_Control *executing;
85
86  executing = _Thread_Executing;
87  _Thread_queue_Queue_acquire_critical(
88    &condition->Queue.Queue,
89    &executing->Potpourri_stats,
90    &queue_context->Lock_context.Lock_context
91  );
92
93  return executing;
94}
95
96static void _Condition_Queue_release(
97  Condition_Control    *condition,
98  Thread_queue_Context *queue_context
99)
100{
101  _Thread_queue_Queue_release(
102    &condition->Queue.Queue,
103    &queue_context->Lock_context.Lock_context
104  );
105}
106
107typedef struct {
108  Thread_queue_Context   Base;
109  struct _Mutex_Control *mutex;
110} Condition_Enqueue_context;
111
112static void _Condition_Mutex_release( Thread_queue_Context *queue_context )
113{
114  Condition_Enqueue_context *context;
115
116  context = (Condition_Enqueue_context *) queue_context;
117  _Mutex_Release( context->mutex );
118}
119
120static void _Condition_Enqueue_no_timeout(
121  Thread_queue_Queue   *queue,
122  Thread_Control       *the_thread,
123  Per_CPU_Control      *cpu_self,
124  Thread_queue_Context *queue_context
125)
126{
127  _Condition_Mutex_release( queue_context );
128}
129
130static void _Condition_Enqueue_with_timeout(
131  Thread_queue_Queue   *queue,
132  Thread_Control       *the_thread,
133  Per_CPU_Control      *cpu_self,
134  Thread_queue_Context *queue_context
135)
136{
137  _Thread_queue_Add_timeout_realtime_timespec(
138    queue,
139    the_thread,
140    cpu_self,
141    queue_context
142  );
143  _Condition_Mutex_release( queue_context );
144}
145
146static Thread_Control *_Condition_Do_wait(
147  struct _Condition_Control *_condition,
148  struct _Mutex_Control     *_mutex,
149  Condition_Enqueue_context *context
150)
151{
152  Condition_Control *condition;
153  Thread_Control    *executing;
154
155  context->mutex = _mutex;
156  condition = _Condition_Get( _condition );
157  _ISR_lock_ISR_disable( &context->Base.Lock_context.Lock_context );
158  executing = _Condition_Queue_acquire_critical( condition, &context->Base );
159  _Thread_queue_Context_set_thread_state(
160    &context->Base,
161    STATES_WAITING_FOR_CONDITION_VARIABLE
162  );
163  _Thread_queue_Enqueue(
164    &condition->Queue.Queue,
165    CONDITION_TQ_OPERATIONS,
166    executing,
167    &context->Base
168  );
169
170  return executing;
171}
172
173void _Condition_Wait(
174  struct _Condition_Control *_condition,
175  struct _Mutex_Control     *_mutex
176)
177{
178  Condition_Enqueue_context context;
179
180  _Thread_queue_Context_initialize( &context.Base );
181  _Thread_queue_Context_set_enqueue_callout(
182    &context.Base,
183    _Condition_Enqueue_no_timeout
184  );
185  _Condition_Do_wait( _condition, _mutex, &context );
186  _Mutex_Acquire( _mutex );
187}
188
189int _Condition_Wait_timed(
190  struct _Condition_Control *_condition,
191  struct _Mutex_Control     *_mutex,
192  const struct timespec     *abstime
193)
194{
195  Condition_Enqueue_context  context;
196  Thread_Control            *executing;
197  int                        eno;
198
199  _Thread_queue_Context_initialize( &context.Base );
200  _Thread_queue_Context_set_enqueue_callout(
201    &context.Base,
202    _Condition_Enqueue_with_timeout
203  );
204  _Thread_queue_Context_set_timeout_argument( &context.Base, abstime, true );
205  executing = _Condition_Do_wait( _condition, _mutex, &context );
206  eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
207  _Mutex_Acquire( _mutex );
208
209  return eno;
210}
211
212static unsigned int _Condition_Unnest_mutex(
213  struct _Mutex_recursive_Control *_mutex
214)
215{
216  unsigned int nest_level;
217
218  nest_level = _mutex->_nest_level;
219  _mutex->_nest_level = 0;
220
221  return nest_level;
222}
223
224void _Condition_Wait_recursive(
225  struct _Condition_Control       *_condition,
226  struct _Mutex_recursive_Control *_mutex
227)
228{
229  Condition_Enqueue_context context;
230  unsigned int              nest_level;
231
232  _Thread_queue_Context_initialize( &context.Base );
233  _Thread_queue_Context_set_enqueue_callout(
234    &context.Base,
235    _Condition_Enqueue_no_timeout
236  );
237  nest_level = _Condition_Unnest_mutex( _mutex );
238  _Condition_Do_wait( _condition, &_mutex->_Mutex, &context );
239  _Mutex_recursive_Acquire( _mutex );
240  _mutex->_nest_level = nest_level;
241}
242
243int _Condition_Wait_recursive_timed(
244  struct _Condition_Control       *_condition,
245  struct _Mutex_recursive_Control *_mutex,
246  const struct timespec           *abstime
247)
248{
249  Condition_Enqueue_context  context;
250  Thread_Control            *executing;
251  int                        eno;
252  unsigned int               nest_level;
253
254  _Thread_queue_Context_initialize( &context.Base );
255  _Thread_queue_Context_set_enqueue_callout(
256    &context.Base,
257    _Condition_Enqueue_with_timeout
258  );
259  _Thread_queue_Context_set_timeout_argument( &context.Base, abstime, true );
260  nest_level = _Condition_Unnest_mutex( _mutex );
261  executing = _Condition_Do_wait( _condition, &_mutex->_Mutex, &context );
262  eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) );
263  _Mutex_recursive_Acquire( _mutex );
264  _mutex->_nest_level = nest_level;
265
266  return eno;
267}
268
269typedef struct {
270  Thread_queue_Context Base;
271  int                  count;
272} Condition_Flush_context;
273
274static Thread_Control *_Condition_Flush_filter(
275  Thread_Control       *the_thread,
276  Thread_queue_Queue   *queue,
277  Thread_queue_Context *queue_context
278)
279{
280  Condition_Flush_context *context;
281
282  context = (Condition_Flush_context *) queue_context;
283
284  if ( context->count <= 0 ) {
285    return NULL;
286  }
287
288  --context->count;
289
290  return the_thread;
291}
292
293static void _Condition_Wake( struct _Condition_Control *_condition, int count )
294{
295  Condition_Control       *condition;
296  Condition_Flush_context  context;
297
298  condition = _Condition_Get( _condition );
299  _Thread_queue_Context_initialize( &context.Base );
300  _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context );
301  _Condition_Queue_acquire_critical( condition, &context.Base );
302
303  /*
304   * In common uses cases of condition variables there are normally no threads
305   * on the queue, so check this condition early.
306   */
307  if (
308    RTEMS_PREDICT_TRUE( _Thread_queue_Is_empty( &condition->Queue.Queue ) )
309  ) {
310    _Condition_Queue_release( condition, &context.Base );
311    return;
312  }
313
314  context.count = count;
315  _Thread_queue_Flush_critical(
316    &condition->Queue.Queue,
317    CONDITION_TQ_OPERATIONS,
318    _Condition_Flush_filter,
319    &context.Base
320  );
321}
322
323void _Condition_Signal( struct _Condition_Control *_condition )
324{
325  _Condition_Wake( _condition, 1 );
326}
327
328void _Condition_Broadcast( struct _Condition_Control *_condition )
329{
330  _Condition_Wake( _condition, INT_MAX );
331}
Note: See TracBrowser for help on using the repository browser.