source: rtems/cpukit/score/include/rtems/score/mrspimpl.h @ 0e1d11f3

5
Last change on this file since 0e1d11f3 was 0e1d11f3, checked in by Sebastian Huber <sebastian.huber@…>, on 05/27/16 at 11:26:53

score: Add _Thread_queue_Context_set_MP_callout()

Add _Thread_queue_Context_set_MP_callout() to simplify
_Thread_queue_Context_initialize(). This makes it possible to more
easily add additional fields to Thread_queue_Context.

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