source: rtems/cpukit/score/include/rtems/score/mrspimpl.h @ 631b3c8

Last change on this file since 631b3c8 was 631b3c8, checked in by Sebastian Huber <sebastian.huber@…>, on May 23, 2016 at 9:40:18 AM

score: Move thread queue MP callout to context

Drop the multiprocessing (MP) dependent callout parameter from the
thread queue extract, dequeue, flush and unblock methods. Merge this
parameter with the lock context into new structure Thread_queue_Context.
This helps to gets rid of the conditionally compiled method call
helpers.

  • Property mode set to 100644
File size: 11.8 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  Thread_queue_Context *queue_context
59)
60{
61  _ISR_lock_Acquire( &mrsp->Lock, &queue_context->Lock_context );
62}
63
64RTEMS_INLINE_ROUTINE void _MRSP_Release(
65  MRSP_Control         *mrsp,
66  Thread_queue_Context *queue_context
67)
68{
69  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &queue_context->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  Thread_queue_Context *queue_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( &queue_context->Lock_context );
122  _MRSP_Release( mrsp, queue_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  Thread_queue_Context queue_context;
184
185  _Thread_queue_Context_initialize( &queue_context, NULL );
186  _ISR_lock_ISR_disable( &queue_context.Lock_context );
187  _MRSP_Acquire_critical( mrsp, &queue_context );
188
189  if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
190    ISR_lock_Context giant_lock_context;
191
192    _MRSP_Giant_acquire( &giant_lock_context );
193
194    _Chain_Extract_unprotected( &rival->Node );
195    _Resource_Node_extract( &thread->Resource_node );
196    _Resource_Node_set_dependency( &thread->Resource_node, NULL );
197    _Scheduler_Thread_change_help_state( thread, rival->initial_help_state );
198    _Scheduler_Thread_change_resource_root( thread, thread );
199
200    _MRSP_Giant_release( &giant_lock_context );
201
202    rival->status = MRSP_TIMEOUT;
203
204    _MRSP_Release( mrsp, &queue_context );
205  } else {
206    _MRSP_Release( mrsp, &queue_context );
207  }
208}
209
210RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
211  MRSP_Control         *mrsp,
212  Resource_Node        *owner,
213  Thread_Control       *executing,
214  Priority_Control      initial_priority,
215  Priority_Control      ceiling_priority,
216  Watchdog_Interval     timeout,
217  Thread_queue_Context *queue_context
218)
219{
220  MRSP_Status status;
221  MRSP_Rival rival;
222  Thread_Life_state life_state;
223  Per_CPU_Control *cpu_self;
224  ISR_lock_Context giant_lock_context;
225  ISR_Level level;
226
227  rival.thread = executing;
228  rival.resource = mrsp;
229  rival.initial_priority = initial_priority;
230
231  _MRSP_Giant_acquire( &giant_lock_context );
232
233  rival.initial_help_state =
234    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
235  rival.status = MRSP_WAIT_FOR_OWNERSHIP;
236
237  _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
238  _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
239  _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
240  _Scheduler_Thread_change_resource_root(
241    executing,
242    THREAD_RESOURCE_NODE_TO_THREAD( _Resource_Node_get_root( owner ) )
243  );
244
245  _MRSP_Giant_release( &giant_lock_context );
246
247  cpu_self = _Thread_Dispatch_disable_critical( &queue_context->Lock_context );
248  _MRSP_Release( mrsp, queue_context );
249
250  _Thread_Raise_priority( executing, ceiling_priority );
251
252  if ( timeout > 0 ) {
253    _Watchdog_Preinitialize( &rival.Watchdog, cpu_self );
254    _Watchdog_Initialize( &rival.Watchdog, _MRSP_Timeout );
255    _ISR_Local_disable( level );
256    _Watchdog_Per_CPU_insert_relative( &rival.Watchdog, cpu_self, timeout );
257    _ISR_Local_enable( level );
258  }
259
260  life_state = _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
261  _Thread_Dispatch_enable( cpu_self );
262
263  _Assert( _Debug_Is_thread_dispatching_allowed() );
264
265  /* Wait for state change */
266  do {
267    status = rival.status;
268  } while ( status == MRSP_WAIT_FOR_OWNERSHIP );
269
270  _Thread_Set_life_protection( life_state );
271
272  if ( timeout > 0 ) {
273    _ISR_Local_disable( level );
274    _Watchdog_Per_CPU_remove(
275      &rival.Watchdog,
276      cpu_self,
277      &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]
278    );
279    _ISR_Local_enable( level );
280
281    if ( status == MRSP_TIMEOUT ) {
282      _MRSP_Restore_priority( executing, initial_priority );
283    }
284  }
285
286  return status;
287}
288
289RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Seize(
290  MRSP_Control         *mrsp,
291  Thread_Control       *executing,
292  bool                  wait,
293  Watchdog_Interval     timeout,
294  Thread_queue_Context *queue_context
295)
296{
297  MRSP_Status status;
298  const Scheduler_Control *scheduler = _Scheduler_Get_own( executing );
299  uint32_t scheduler_index = _Scheduler_Get_index( scheduler );
300  Priority_Control initial_priority = executing->current_priority;
301  Priority_Control ceiling_priority =
302    _MRSP_Get_ceiling_priority( mrsp, scheduler_index );
303  bool priority_ok = !_Thread_Priority_less_than(
304    ceiling_priority,
305    initial_priority
306  );
307  Resource_Node *owner;
308
309  if ( !priority_ok) {
310    _ISR_lock_ISR_enable( &queue_context->Lock_context );
311    return MRSP_INVALID_PRIORITY;
312  }
313
314  _MRSP_Acquire_critical( mrsp, queue_context );
315  owner = _Resource_Get_owner( &mrsp->Resource );
316  if ( owner == NULL ) {
317    _MRSP_Claim_ownership(
318      mrsp,
319      executing,
320      initial_priority,
321      ceiling_priority,
322      queue_context
323    );
324    status = MRSP_SUCCESSFUL;
325  } else if (
326    wait
327      && _Resource_Node_get_root( owner ) != &executing->Resource_node
328  ) {
329    status = _MRSP_Wait_for_ownership(
330      mrsp,
331      owner,
332      executing,
333      initial_priority,
334      ceiling_priority,
335      timeout,
336      queue_context
337    );
338  } else {
339    _MRSP_Release( mrsp, queue_context );
340    /* Not available, nested access or deadlock */
341    status = MRSP_UNSATISFIED;
342  }
343
344  return status;
345}
346
347RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Surrender(
348  MRSP_Control         *mrsp,
349  Thread_Control       *executing,
350  Thread_queue_Context *queue_context
351)
352{
353  Priority_Control initial_priority;
354  Per_CPU_Control *cpu_self;
355  ISR_lock_Context giant_lock_context;
356
357  if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
358    _ISR_lock_ISR_enable( &queue_context->Lock_context );
359    return MRSP_NOT_OWNER_OF_RESOURCE;
360  }
361
362  if (
363    !_Resource_Is_most_recently_obtained(
364      &mrsp->Resource,
365      &executing->Resource_node
366    )
367  ) {
368    _ISR_lock_ISR_enable( &queue_context->Lock_context );
369    return MRSP_INCORRECT_STATE;
370  }
371
372  initial_priority = mrsp->initial_priority_of_owner;
373
374  _MRSP_Acquire_critical( mrsp, queue_context );
375
376  _MRSP_Giant_acquire( &giant_lock_context );
377
378  _Resource_Extract( &mrsp->Resource );
379
380  if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
381    _Resource_Set_owner( &mrsp->Resource, NULL );
382  } else {
383    MRSP_Rival *rival = (MRSP_Rival *)
384      _Chain_Get_first_unprotected( &mrsp->Rivals );
385    Thread_Control *new_owner;
386
387    /*
388     * This must be inside the critical section since the status prevents a
389     * potential double extraction in _MRSP_Timeout().
390     */
391    rival->status = MRSP_SUCCESSFUL;
392
393    new_owner = rival->thread;
394    mrsp->initial_priority_of_owner = rival->initial_priority;
395    _Resource_Node_extract( &new_owner->Resource_node );
396    _Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
397    _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
398    _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
399    _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
400    _Scheduler_Thread_change_resource_root( new_owner, new_owner );
401  }
402
403  if ( !_Resource_Node_owns_resources( &executing->Resource_node ) ) {
404    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF );
405  }
406
407  _MRSP_Giant_release( &giant_lock_context );
408
409  cpu_self = _Thread_Dispatch_disable_critical( &queue_context->Lock_context );
410  _MRSP_Release( mrsp, queue_context );
411
412  _MRSP_Restore_priority( executing, initial_priority );
413
414  _Thread_Dispatch_enable( cpu_self );
415
416  return MRSP_SUCCESSFUL;
417}
418
419RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Can_destroy( MRSP_Control *mrsp )
420{
421  if ( _Resource_Get_owner( &mrsp->Resource ) != NULL ) {
422    return MRSP_RESOUCE_IN_USE;
423  }
424
425  return MRSP_SUCCESSFUL;
426}
427
428RTEMS_INLINE_ROUTINE void _MRSP_Destroy(
429  MRSP_Control         *mrsp,
430  Thread_queue_Context *queue_context
431)
432{
433  _MRSP_Release( mrsp, queue_context );
434  _ISR_lock_Destroy( &mrsp->Lock );
435  _Workspace_Free( mrsp->ceiling_priorities );
436}
437
438/** @} */
439
440#ifdef __cplusplus
441}
442#endif /* __cplusplus */
443
444#endif /* RTEMS_SMP */
445
446#endif /* _RTEMS_SCORE_MRSPIMPL_H */
Note: See TracBrowser for help on using the repository browser.