source: rtems/cpukit/score/include/rtems/score/mrspimpl.h @ 864d3475

4.11
Last change on this file since 864d3475 was 864d3475, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 17, 2014 at 2:11:00 PM

smp: Fix timeout for MrsP semaphores

The previous timeout handling was flawed. In case a waiting thread
helped out the owner could use the scheduler node indefinitely long.
Update the resource tree in _MRSP_Timeout() to avoid this issue.

Bug reported by Luca Bonato.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifndef _RTEMS_SCORE_MRSPIMPL_H
16#define _RTEMS_SCORE_MRSPIMPL_H
17
18#include <rtems/score/mrsp.h>
19
20#if defined(RTEMS_SMP)
21
22#include <rtems/score/assert.h>
23#include <rtems/score/chainimpl.h>
24#include <rtems/score/resourceimpl.h>
25#include <rtems/score/schedulerimpl.h>
26#include <rtems/score/watchdogimpl.h>
27#include <rtems/score/wkspace.h>
28
29#ifdef __cplusplus
30extern "C" {
31#endif /* __cplusplus */
32
33/**
34 * @addtogroup ScoreMRSP
35 *
36 * @{
37 */
38
39RTEMS_INLINE_ROUTINE void _MRSP_Elevate_priority(
40  MRSP_Control     *mrsp,
41  Thread_Control   *new_owner,
42  Priority_Control  ceiling_priority
43)
44{
45  _Thread_Change_priority( new_owner, ceiling_priority, false );
46}
47
48RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority(
49  Thread_Control   *thread,
50  Priority_Control  initial_priority
51)
52{
53  /*
54   * The Thread_Control::resource_count is used by the normal priority ceiling
55   * or priority inheritance semaphores.
56   */
57  if ( thread->resource_count == 0 ) {
58    Priority_Control new_priority = _Scheduler_Highest_priority_of_two(
59      _Scheduler_Get( thread ),
60      initial_priority,
61      thread->real_priority
62    );
63
64    _Thread_Change_priority( thread, new_priority, true );
65  }
66}
67
68RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
69  MRSP_Control     *mrsp,
70  Thread_Control   *new_owner,
71  Priority_Control  initial_priority,
72  Priority_Control  ceiling_priority
73)
74{
75  _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
76  _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
77  mrsp->initial_priority_of_owner = initial_priority;
78  _MRSP_Elevate_priority( mrsp, new_owner, ceiling_priority );
79  _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
80}
81
82RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
83  MRSP_Control     *mrsp,
84  Priority_Control  ceiling_priority,
85  Thread_Control   *executing,
86  bool              initially_locked
87)
88{
89  uint32_t scheduler_count = _Scheduler_Count;
90  uint32_t i;
91
92  if ( initially_locked ) {
93    return MRSP_INVALID_NUMBER;
94  }
95
96  mrsp->ceiling_priorities = _Workspace_Allocate(
97    sizeof( *mrsp->ceiling_priorities ) * scheduler_count
98  );
99  if ( mrsp->ceiling_priorities == NULL ) {
100    return MRSP_NO_MEMORY;
101  }
102
103  for ( i = 0 ; i < scheduler_count ; ++i ) {
104    mrsp->ceiling_priorities[ i ] = ceiling_priority;
105  }
106
107  _Resource_Initialize( &mrsp->Resource );
108  _Chain_Initialize_empty( &mrsp->Rivals );
109
110  return MRSP_SUCCESSFUL;
111}
112
113RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_ceiling_priority(
114  MRSP_Control *mrsp,
115  uint32_t      scheduler_index
116)
117{
118  return mrsp->ceiling_priorities[ scheduler_index ];
119}
120
121RTEMS_INLINE_ROUTINE void _MRSP_Set_ceiling_priority(
122  MRSP_Control      *mrsp,
123  uint32_t           scheduler_index,
124  Priority_Control   ceiling_priority
125)
126{
127  mrsp->ceiling_priorities[ scheduler_index ] = ceiling_priority;
128}
129
130RTEMS_INLINE_ROUTINE void _MRSP_Timeout(
131  Objects_Id  id,
132  void       *arg
133)
134{
135  MRSP_Rival *rival = arg;
136  Thread_Control *thread = rival->thread;
137  ISR_Level level;
138
139  (void) id;
140
141  _ISR_Disable( level );
142
143  if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
144    _Chain_Extract_unprotected( &rival->Node );
145
146    _ISR_Enable( level );
147
148    rival->status = MRSP_TIMEOUT;
149
150    _Resource_Node_extract( &thread->Resource_node );
151    _Resource_Node_set_dependency( &thread->Resource_node, NULL );
152    _Scheduler_Thread_change_help_state( thread, rival->initial_help_state );
153    _Scheduler_Thread_change_resource_root( thread, thread );
154    _MRSP_Restore_priority( thread, rival->initial_priority );
155  } else {
156    _ISR_Enable( level );
157  }
158}
159
160RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
161  MRSP_Control      *mrsp,
162  Resource_Node     *owner,
163  Thread_Control    *executing,
164  Priority_Control   initial_priority,
165  Priority_Control   ceiling_priority,
166  Watchdog_Interval  timeout
167)
168{
169  MRSP_Status status;
170  MRSP_Rival rival;
171  bool initial_life_protection;
172  ISR_Level level;
173
174  rival.thread = executing;
175  rival.initial_priority = initial_priority;
176  rival.initial_help_state =
177    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
178  rival.status = MRSP_WAIT_FOR_OWNERSHIP;
179
180  _MRSP_Elevate_priority( mrsp, executing, ceiling_priority );
181
182  _ISR_Disable( level );
183  _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
184  _ISR_Enable( level );
185
186  _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
187  _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
188
189  _Scheduler_Thread_change_resource_root(
190    executing,
191    THREAD_RESOURCE_NODE_TO_THREAD( _Resource_Node_get_root( owner ) )
192  );
193
194  if ( timeout > 0 ) {
195    _Watchdog_Initialize(
196      &executing->Timer,
197      _MRSP_Timeout,
198      0,
199      &rival
200    );
201    _Watchdog_Insert_ticks( &executing->Timer, timeout );
202  }
203
204  initial_life_protection = _Thread_Set_life_protection( true );
205  _Thread_Enable_dispatch();
206
207  _Assert( _Debug_Is_thread_dispatching_allowed() );
208
209  /* Wait for state change */
210  do {
211    status = rival.status;
212  } while ( status == MRSP_WAIT_FOR_OWNERSHIP );
213
214  _Thread_Disable_dispatch();
215  _Thread_Set_life_protection( initial_life_protection );
216
217  if ( timeout > 0 ) {
218    _Watchdog_Remove( &executing->Timer );
219  }
220
221  return status;
222}
223
224RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
225  MRSP_Control      *mrsp,
226  Thread_Control    *executing,
227  bool               wait,
228  Watchdog_Interval  timeout
229)
230{
231  MRSP_Status status;
232  const Scheduler_Control *scheduler = _Scheduler_Get( executing );
233  uint32_t scheduler_index = _Scheduler_Get_index( scheduler );
234  Priority_Control initial_priority = executing->current_priority;
235  Priority_Control ceiling_priority =
236    _MRSP_Get_ceiling_priority( mrsp, scheduler_index );
237  bool priority_ok = !_Scheduler_Is_priority_higher_than(
238    scheduler,
239    initial_priority,
240    ceiling_priority
241  );
242  Resource_Node *owner;
243
244  if ( !priority_ok) {
245    return MRSP_INVALID_PRIORITY;
246  }
247
248  owner = _Resource_Get_owner( &mrsp->Resource );
249  if ( owner == NULL ) {
250    _MRSP_Claim_ownership(
251      mrsp,
252      executing,
253      initial_priority,
254      ceiling_priority
255    );
256    status = MRSP_SUCCESSFUL;
257  } else if ( _Resource_Node_get_root( owner ) == &executing->Resource_node ) {
258    /* Nested access or deadlock */
259    status = MRSP_UNSATISFIED;
260  } else if ( wait ) {
261    status = _MRSP_Wait_for_ownership(
262      mrsp,
263      owner,
264      executing,
265      initial_priority,
266      ceiling_priority,
267      timeout
268    );
269  } else {
270    status = MRSP_UNSATISFIED;
271  }
272
273  return status;
274}
275
276RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
277  MRSP_Control   *mrsp,
278  Thread_Control *executing
279)
280{
281  ISR_Level level;
282
283  if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
284    return MRSP_NOT_OWNER_OF_RESOURCE;
285  }
286
287  if (
288    !_Resource_Is_most_recently_obtained(
289      &mrsp->Resource,
290      &executing->Resource_node
291    )
292  ) {
293    return MRSP_INCORRECT_STATE;
294  }
295
296  _Resource_Extract( &mrsp->Resource );
297  _MRSP_Restore_priority( executing, mrsp->initial_priority_of_owner );
298
299  _ISR_Disable( level );
300
301  if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
302    _ISR_Enable( level );
303
304    _Resource_Set_owner( &mrsp->Resource, NULL );
305  } else {
306    MRSP_Rival *rival = (MRSP_Rival *)
307      _Chain_Get_first_unprotected( &mrsp->Rivals );
308    Thread_Control *new_owner;
309
310    /*
311     * This must be inside the critical section since the status prevents a
312     * potential double extraction in _MRSP_Timeout().
313     */
314    rival->status = MRSP_SUCCESSFUL;
315
316    _ISR_Enable( level );
317
318    new_owner = rival->thread;
319    mrsp->initial_priority_of_owner = rival->initial_priority;
320    _Resource_Node_extract( &new_owner->Resource_node );
321    _Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
322    _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
323    _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
324    _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
325    _Scheduler_Thread_change_resource_root( new_owner, new_owner );
326  }
327
328  if ( !_Resource_Node_owns_resources( &executing->Resource_node ) ) {
329    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF );
330  }
331
332  return MRSP_SUCCESSFUL;
333}
334
335RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Destroy( MRSP_Control *mrsp )
336{
337  if ( _Resource_Get_owner( &mrsp->Resource ) != NULL ) {
338    return MRSP_RESOUCE_IN_USE;
339  }
340
341  _Workspace_Free( mrsp->ceiling_priorities );
342
343  return MRSP_SUCCESSFUL;
344}
345
346/** @} */
347
348#ifdef __cplusplus
349}
350#endif /* __cplusplus */
351
352#endif /* RTEMS_SMP */
353
354#endif /* _RTEMS_SCORE_MRSPIMPL_H */
Note: See TracBrowser for help on using the repository browser.