source: rtems/cpukit/score/include/rtems/score/mrspimpl.h @ c3d8d9e

5
Last change on this file since c3d8d9e was 4b04cb61, checked in by Sebastian Huber <sebastian.huber@…>, on 05/18/16 at 06:03:05

score: Rename _ISR_Disable_without_giant()

Rename _ISR_Disable_without_giant() into _ISR_Local_disable(). Rename
_ISR_Enable_without_giant() into _ISR_Local_enable().

This is a preparation to remove the Giant lock.

Update #2555.

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