source: rtems/cpukit/score/src/threadhandler.c @ 54cf0e34

4.115
Last change on this file since 54cf0e34 was 222dc775, checked in by Sebastian Huber <sebastian.huber@…>, on 02/26/15 at 09:32:08

score: Add and use _Thread_Do_dispatch()

The _Thread_Dispatch() function is quite complex and the time to set up
and tear down the stack frame is significant. Split this function into
two parts. The complex part is now in _Thread_Do_dispatch(). Call
_Thread_Do_dispatch() in _Thread_Enable_dispatch() only if necessary.
This increases the average case performance.

Simplify _Thread_Handler() for SMP configurations.

Update #2273.

  • Property mode set to 100644
File size: 4.1 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief Thread Handler
5 *  @ingroup ScoreThread
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2012.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <rtems/score/threadimpl.h>
22#include <rtems/score/assert.h>
23#include <rtems/score/interr.h>
24#include <rtems/score/isrlevel.h>
25#include <rtems/score/userextimpl.h>
26
27void _Thread_Handler( void )
28{
29  Thread_Control  *executing = _Thread_Executing;
30  ISR_Level        level;
31  Per_CPU_Control *cpu_self;
32
33  /*
34   * Some CPUs need to tinker with the call frame or registers when the
35   * thread actually begins to execute for the first time.  This is a
36   * hook point where the port gets a shot at doing whatever it requires.
37   */
38  _Context_Initialization_at_thread_begin();
39
40  #if defined(RTEMS_SMP)
41    /* On SMP we enter _Thread_Handler() with interrupts disabled */
42    _Assert( _ISR_Get_level() != 0 );
43
44    _Thread_Debug_set_real_processor( executing, _Per_CPU_Get() );
45  #endif
46
47  /*
48   * have to put level into a register for those cpu's that use
49   * inline asm here
50   */
51  level = executing->Start.isr_level;
52  _ISR_Set_level( level );
53
54  /*
55   * Initialize the floating point context because we do not come
56   * through _Thread_Dispatch on our first invocation. So the normal
57   * code path for performing the FP context switch is not hit.
58   */
59  _Thread_Restore_fp( executing );
60
61  /*
62   * Take care that 'begin' extensions get to complete before
63   * 'switch' extensions can run.  This means must keep dispatch
64   * disabled until all 'begin' extensions complete.
65   */
66  _User_extensions_Thread_begin( executing );
67
68  /*
69   * Do not use the level of the thread control block, since it has a
70   * different format.
71   */
72  _ISR_Disable_without_giant( level );
73
74  /*
75   *  At this point, the dispatch disable level BETTER be 1.
76   */
77  cpu_self = _Per_CPU_Get();
78  _Assert( cpu_self->thread_dispatch_disable_level == 1 );
79
80  /*
81   * Make sure we lose no thread dispatch necessary update and execute the
82   * post-switch actions.  As a side-effect change the thread dispatch level
83   * from one to zero.  Do not use _Thread_Enable_dispatch() since there is no
84   * valid thread dispatch necessary indicator in this context.
85   */
86  _Thread_Do_dispatch( cpu_self, level );
87
88  /*
89   *  RTEMS supports multiple APIs and each API can define a different
90   *  thread/task prototype. The following code supports invoking the
91   *  user thread entry point using the prototype expected.
92   */
93  if ( executing->Start.prototype == THREAD_START_NUMERIC ) {
94    executing->Wait.return_argument =
95      (*(Thread_Entry_numeric) executing->Start.entry_point)(
96        executing->Start.numeric_argument
97      );
98  }
99  #if defined(RTEMS_POSIX_API)
100    else if ( executing->Start.prototype == THREAD_START_POINTER ) {
101      executing->Wait.return_argument =
102        (*(Thread_Entry_pointer) executing->Start.entry_point)(
103          executing->Start.pointer_argument
104        );
105    }
106  #endif
107  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
108    else if ( executing->Start.prototype == THREAD_START_BOTH_POINTER_FIRST ) {
109      executing->Wait.return_argument =
110         (*(Thread_Entry_both_pointer_first) executing->Start.entry_point)(
111           executing->Start.pointer_argument,
112           executing->Start.numeric_argument
113         );
114    }
115    else if ( executing->Start.prototype == THREAD_START_BOTH_NUMERIC_FIRST ) {
116      executing->Wait.return_argument =
117       (*(Thread_Entry_both_numeric_first) executing->Start.entry_point)(
118         executing->Start.numeric_argument,
119         executing->Start.pointer_argument
120       );
121    }
122  #endif
123
124  /*
125   *  In the switch above, the return code from the user thread body
126   *  was placed in return_argument.  This assumed that if it returned
127   *  anything (which is not supporting in all APIs), then it would be
128   *  able to fit in a (void *).
129   */
130
131  _User_extensions_Thread_exitted( executing );
132
133  _Terminate(
134    INTERNAL_ERROR_CORE,
135    true,
136    INTERNAL_ERROR_THREAD_EXITTED
137  );
138}
Note: See TracBrowser for help on using the repository browser.