source: rtems/cpukit/score/include/rtems/score/mrspimpl.h @ 03b900d

5
Last change on this file since 03b900d was 03b900d, checked in by Sebastian Huber <sebastian.huber@…>, on 02/18/16 at 07:36:26

score: Replace watchdog handler implementation

Use a red-black tree instead of delta chains.

Close #2344.
Update #2554.
Update #2555.
Close #2606.

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 * Copyright (c) 2014, 2016 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
39/*
40 * FIXME: Operations with the resource dependency tree are protected by the
41 * global scheduler lock.  Since the scheduler lock should be scheduler
42 * instance specific in the future this will only work temporarily.  A more
43 * sophisticated locking strategy is necessary.
44 */
45
46RTEMS_INLINE_ROUTINE void _MRSP_Giant_acquire( ISR_lock_Context *lock_context )
47{
48  _ISR_lock_Acquire( &_Scheduler_Lock, lock_context );
49}
50
51RTEMS_INLINE_ROUTINE void _MRSP_Giant_release( ISR_lock_Context *lock_context )
52{
53  _ISR_lock_Release( &_Scheduler_Lock, lock_context );
54}
55
56RTEMS_INLINE_ROUTINE bool _MRSP_Restore_priority_filter(
57  Thread_Control   *thread,
58  Priority_Control *new_priority,
59  void             *arg
60)
61{
62  *new_priority = _Thread_Priority_highest(
63    thread->real_priority,
64    *new_priority
65  );
66
67  return *new_priority != thread->current_priority;
68}
69
70RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority(
71  Thread_Control   *thread,
72  Priority_Control  initial_priority
73)
74{
75  /*
76   * The Thread_Control::resource_count is used by the normal priority ceiling
77   * or priority inheritance semaphores.
78   */
79  if ( thread->resource_count == 0 ) {
80    _Thread_Change_priority(
81      thread,
82      initial_priority,
83      NULL,
84      _MRSP_Restore_priority_filter,
85      true
86    );
87  }
88}
89
90RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
91  MRSP_Control     *mrsp,
92  Thread_Control   *new_owner,
93  Priority_Control  initial_priority,
94  Priority_Control  ceiling_priority,
95  ISR_lock_Context *lock_context
96)
97{
98  Per_CPU_Control *cpu_self;
99
100  _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
101  _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
102  mrsp->initial_priority_of_owner = initial_priority;
103  _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
104
105  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
106  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
107
108  _Thread_Raise_priority( new_owner, ceiling_priority );
109
110  _Thread_Dispatch_enable( cpu_self );
111}
112
113RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
114  MRSP_Control     *mrsp,
115  Priority_Control  ceiling_priority,
116  Thread_Control   *executing,
117  bool              initially_locked
118)
119{
120  uint32_t scheduler_count = _Scheduler_Count;
121  uint32_t i;
122
123  if ( initially_locked ) {
124    return MRSP_INVALID_NUMBER;
125  }
126
127  mrsp->ceiling_priorities = _Workspace_Allocate(
128    sizeof( *mrsp->ceiling_priorities ) * scheduler_count
129  );
130  if ( mrsp->ceiling_priorities == NULL ) {
131    return MRSP_NO_MEMORY;
132  }
133
134  for ( i = 0 ; i < scheduler_count ; ++i ) {
135    mrsp->ceiling_priorities[ i ] = ceiling_priority;
136  }
137
138  _Resource_Initialize( &mrsp->Resource );
139  _Chain_Initialize_empty( &mrsp->Rivals );
140  _ISR_lock_Initialize( &mrsp->Lock, "MrsP" );
141
142  return MRSP_SUCCESSFUL;
143}
144
145RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_ceiling_priority(
146  MRSP_Control *mrsp,
147  uint32_t      scheduler_index
148)
149{
150  return mrsp->ceiling_priorities[ scheduler_index ];
151}
152
153RTEMS_INLINE_ROUTINE void _MRSP_Set_ceiling_priority(
154  MRSP_Control      *mrsp,
155  uint32_t           scheduler_index,
156  Priority_Control   ceiling_priority
157)
158{
159  mrsp->ceiling_priorities[ scheduler_index ] = ceiling_priority;
160}
161
162RTEMS_INLINE_ROUTINE void _MRSP_Timeout( Watchdog_Control *watchdog )
163{
164  MRSP_Rival *rival = RTEMS_CONTAINER_OF( watchdog, MRSP_Rival, Watchdog );
165  MRSP_Control *mrsp = rival->resource;
166  Thread_Control *thread = rival->thread;
167  ISR_lock_Context lock_context;
168
169  _ISR_lock_ISR_disable_and_acquire( &mrsp->Lock, &lock_context );
170
171  if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
172    ISR_lock_Context giant_lock_context;
173
174    _MRSP_Giant_acquire( &giant_lock_context );
175
176    _Chain_Extract_unprotected( &rival->Node );
177    _Resource_Node_extract( &thread->Resource_node );
178    _Resource_Node_set_dependency( &thread->Resource_node, NULL );
179    _Scheduler_Thread_change_help_state( thread, rival->initial_help_state );
180    _Scheduler_Thread_change_resource_root( thread, thread );
181
182    _MRSP_Giant_release( &giant_lock_context );
183
184    rival->status = MRSP_TIMEOUT;
185
186    _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context );
187  } else {
188    _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context );
189  }
190}
191
192RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
193  MRSP_Control      *mrsp,
194  Resource_Node     *owner,
195  Thread_Control    *executing,
196  Priority_Control   initial_priority,
197  Priority_Control   ceiling_priority,
198  Watchdog_Interval  timeout,
199  ISR_lock_Context  *lock_context
200)
201{
202  MRSP_Status status;
203  MRSP_Rival rival;
204  bool initial_life_protection;
205  Per_CPU_Control *cpu_self;
206  ISR_lock_Context giant_lock_context;
207  ISR_Level level;
208
209  rival.thread = executing;
210  rival.resource = mrsp;
211  rival.initial_priority = initial_priority;
212
213  _MRSP_Giant_acquire( &giant_lock_context );
214
215  rival.initial_help_state =
216    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
217  rival.status = MRSP_WAIT_FOR_OWNERSHIP;
218
219  _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
220  _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
221  _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
222  _Scheduler_Thread_change_resource_root(
223    executing,
224    THREAD_RESOURCE_NODE_TO_THREAD( _Resource_Node_get_root( owner ) )
225  );
226
227  _MRSP_Giant_release( &giant_lock_context );
228
229  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
230  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
231
232  _Thread_Raise_priority( executing, ceiling_priority );
233
234  if ( timeout > 0 ) {
235    _Watchdog_Preinitialize( &rival.Watchdog, cpu_self );
236    _Watchdog_Initialize( &rival.Watchdog, _MRSP_Timeout );
237    _ISR_Disable_without_giant( level );
238    _Watchdog_Per_CPU_insert_relative( &rival.Watchdog, cpu_self, timeout );
239    _ISR_Enable_without_giant( level );
240  }
241
242  initial_life_protection = _Thread_Set_life_protection( true );
243  _Thread_Dispatch_enable( cpu_self );
244
245  _Assert( _Debug_Is_thread_dispatching_allowed() );
246
247  /* Wait for state change */
248  do {
249    status = rival.status;
250  } while ( status == MRSP_WAIT_FOR_OWNERSHIP );
251
252  _Thread_Set_life_protection( initial_life_protection );
253
254  if ( timeout > 0 ) {
255    _ISR_Disable_without_giant( level );
256    _Watchdog_Per_CPU_remove(
257      &rival.Watchdog,
258      cpu_self,
259      &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]
260    );
261    _ISR_Enable_without_giant( level );
262
263    if ( status == MRSP_TIMEOUT ) {
264      _MRSP_Restore_priority( executing, initial_priority );
265    }
266  }
267
268  return status;
269}
270
271RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
272  MRSP_Control      *mrsp,
273  Thread_Control    *executing,
274  bool               wait,
275  Watchdog_Interval  timeout,
276  ISR_lock_Context  *lock_context
277)
278{
279  MRSP_Status status;
280  const Scheduler_Control *scheduler = _Scheduler_Get_own( executing );
281  uint32_t scheduler_index = _Scheduler_Get_index( scheduler );
282  Priority_Control initial_priority = executing->current_priority;
283  Priority_Control ceiling_priority =
284    _MRSP_Get_ceiling_priority( mrsp, scheduler_index );
285  bool priority_ok = !_Thread_Priority_less_than(
286    ceiling_priority,
287    initial_priority
288  );
289  Resource_Node *owner;
290
291  if ( !priority_ok) {
292    _ISR_lock_ISR_enable( lock_context );
293    return MRSP_INVALID_PRIORITY;
294  }
295
296  _ISR_lock_Acquire( &mrsp->Lock, lock_context );
297  owner = _Resource_Get_owner( &mrsp->Resource );
298  if ( owner == NULL ) {
299    _MRSP_Claim_ownership(
300      mrsp,
301      executing,
302      initial_priority,
303      ceiling_priority,
304      lock_context
305    );
306    status = MRSP_SUCCESSFUL;
307  } else if (
308    wait
309      && _Resource_Node_get_root( owner ) != &executing->Resource_node
310  ) {
311    status = _MRSP_Wait_for_ownership(
312      mrsp,
313      owner,
314      executing,
315      initial_priority,
316      ceiling_priority,
317      timeout,
318      lock_context
319    );
320  } else {
321    _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
322    /* Not available, nested access or deadlock */
323    status = MRSP_UNSATISFIED;
324  }
325
326  return status;
327}
328
329RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
330  MRSP_Control     *mrsp,
331  Thread_Control   *executing,
332  ISR_lock_Context *lock_context
333)
334{
335  Priority_Control initial_priority;
336  Per_CPU_Control *cpu_self;
337  ISR_lock_Context giant_lock_context;
338
339  if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
340    _ISR_lock_ISR_enable( lock_context );
341    return MRSP_NOT_OWNER_OF_RESOURCE;
342  }
343
344  if (
345    !_Resource_Is_most_recently_obtained(
346      &mrsp->Resource,
347      &executing->Resource_node
348    )
349  ) {
350    _ISR_lock_ISR_enable( lock_context );
351    return MRSP_INCORRECT_STATE;
352  }
353
354  initial_priority = mrsp->initial_priority_of_owner;
355
356  _ISR_lock_Acquire( &mrsp->Lock, lock_context );
357
358  _MRSP_Giant_acquire( &giant_lock_context );
359
360  _Resource_Extract( &mrsp->Resource );
361
362  if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
363    _Resource_Set_owner( &mrsp->Resource, NULL );
364  } else {
365    MRSP_Rival *rival = (MRSP_Rival *)
366      _Chain_Get_first_unprotected( &mrsp->Rivals );
367    Thread_Control *new_owner;
368
369    /*
370     * This must be inside the critical section since the status prevents a
371     * potential double extraction in _MRSP_Timeout().
372     */
373    rival->status = MRSP_SUCCESSFUL;
374
375    new_owner = rival->thread;
376    mrsp->initial_priority_of_owner = rival->initial_priority;
377    _Resource_Node_extract( &new_owner->Resource_node );
378    _Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
379    _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
380    _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
381    _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
382    _Scheduler_Thread_change_resource_root( new_owner, new_owner );
383  }
384
385  if ( !_Resource_Node_owns_resources( &executing->Resource_node ) ) {
386    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF );
387  }
388
389  _MRSP_Giant_release( &giant_lock_context );
390
391  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
392  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
393
394  _MRSP_Restore_priority( executing, initial_priority );
395
396  _Thread_Dispatch_enable( cpu_self );
397
398  return MRSP_SUCCESSFUL;
399}
400
401RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Destroy( MRSP_Control *mrsp )
402{
403  if ( _Resource_Get_owner( &mrsp->Resource ) != NULL ) {
404    return MRSP_RESOUCE_IN_USE;
405  }
406
407  _ISR_lock_Destroy( &mrsp->Lock );
408  _Workspace_Free( mrsp->ceiling_priorities );
409
410  return MRSP_SUCCESSFUL;
411}
412
413/** @} */
414
415#ifdef __cplusplus
416}
417#endif /* __cplusplus */
418
419#endif /* RTEMS_SMP */
420
421#endif /* _RTEMS_SCORE_MRSPIMPL_H */
Note: See TracBrowser for help on using the repository browser.