source: rtems/cpukit/score/src/threadhandler.c @ 53ad908

4.115
Last change on this file since 53ad908 was 53ad908, checked in by Sebastian Huber <sebastian.huber@…>, on 03/07/14 at 13:36:22

score: Add SMP lock profiling support

  • Property mode set to 100644
File size: 6.5 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.com/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
27/*
28 *  Conditional magic to determine what style of C++ constructor
29 *  initialization this target and compiler version uses.
30 */
31#if defined(__USE_INIT_FINI__)
32  #if defined(__M32R__)
33    #define INIT_NAME __init
34  #elif defined(__ARM_EABI__)
35    #define INIT_NAME __libc_init_array
36  #else
37    #define INIT_NAME _init
38  #endif
39
40  extern void INIT_NAME(void);
41  #define EXECUTE_GLOBAL_CONSTRUCTORS
42#endif
43
44#if defined(__USE__MAIN__)
45  extern void __main(void);
46  #define INIT_NAME __main
47  #define EXECUTE_GLOBAL_CONSTRUCTORS
48#endif
49
50#if defined(EXECUTE_GLOBAL_CONSTRUCTORS)
51  static bool _Thread_Handler_is_constructor_execution_required(
52    Thread_Control *executing
53  )
54  {
55    static bool doneConstructors;
56    bool doCons = false;
57
58    #if defined(RTEMS_SMP)
59      static SMP_lock_Control constructor_lock =
60        SMP_LOCK_INITIALIZER("constructor");
61
62      SMP_lock_Context lock_context;
63
64      if ( !doneConstructors ) {
65        _SMP_lock_Acquire( &constructor_lock, &lock_context );
66    #endif
67
68    #if defined(RTEMS_MULTIPROCESSING)
69      doCons = !doneConstructors
70        && _Objects_Get_API( executing->Object.id ) != OBJECTS_INTERNAL_API;
71      if (doCons)
72        doneConstructors = true;
73    #else
74      (void) executing;
75      doCons = !doneConstructors;
76      doneConstructors = true;
77    #endif
78
79    #if defined(RTEMS_SMP)
80        _SMP_lock_Release( &constructor_lock, &lock_context );
81      }
82    #endif
83
84    return doCons;
85  }
86#endif
87
88void _Thread_Handler( void )
89{
90  ISR_Level  level;
91  Thread_Control *executing;
92  #if defined(EXECUTE_GLOBAL_CONSTRUCTORS)
93    bool doCons;
94  #endif
95
96  executing = _Thread_Executing;
97
98  /*
99   * Some CPUs need to tinker with the call frame or registers when the
100   * thread actually begins to execute for the first time.  This is a
101   * hook point where the port gets a shot at doing whatever it requires.
102   */
103  _Context_Initialization_at_thread_begin();
104
105  #if !defined(RTEMS_SMP)
106    /*
107     * have to put level into a register for those cpu's that use
108     * inline asm here
109     */
110    level = executing->Start.isr_level;
111    _ISR_Set_level( level );
112  #endif
113
114  #if defined(EXECUTE_GLOBAL_CONSTRUCTORS)
115    doCons = _Thread_Handler_is_constructor_execution_required( executing );
116  #endif
117
118  /*
119   * Initialize the floating point context because we do not come
120   * through _Thread_Dispatch on our first invocation. So the normal
121   * code path for performing the FP context switch is not hit.
122   */
123  #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
124    #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
125      if ( (executing->fp_context != NULL) &&
126            !_Thread_Is_allocated_fp( executing ) ) {
127        if ( _Thread_Allocated_fp != NULL )
128          _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
129        _Thread_Allocated_fp = executing;
130      }
131    #endif
132  #endif
133
134  /*
135   * Take care that 'begin' extensions get to complete before
136   * 'switch' extensions can run.  This means must keep dispatch
137   * disabled until all 'begin' extensions complete.
138   */
139  _User_extensions_Thread_begin( executing );
140
141  /*
142   *  At this point, the dispatch disable level BETTER be 1.
143   */
144  #if defined(RTEMS_SMP)
145    {
146      /*
147       * On SMP we enter _Thread_Handler() with interrupts disabled and
148       * _Thread_Dispatch() obtained the per-CPU lock for us.  We have to
149       * release it here and set the desired interrupt level of the thread.
150       */
151      Per_CPU_Control *per_cpu = _Per_CPU_Get();
152
153      _Assert( per_cpu->thread_dispatch_disable_level == 1 );
154      _Assert( _ISR_Get_level() != 0 );
155
156      per_cpu->thread_dispatch_disable_level = 0;
157      _Profiling_Thread_dispatch_enable( per_cpu, 0 );
158
159      _Per_CPU_Release( per_cpu );
160
161      level = executing->Start.isr_level;
162      _ISR_Set_level( level);
163
164      /*
165       * The thread dispatch level changed from one to zero.  Make sure we lose
166       * no thread dispatch necessary update.
167       */
168      _Thread_Dispatch();
169    }
170  #else
171    _Thread_Enable_dispatch();
172  #endif
173
174  #if defined(EXECUTE_GLOBAL_CONSTRUCTORS)
175    /*
176     *  _init could be a weak symbol and we SHOULD test it but it isn't
177     *  in any configuration I know of and it generates a warning on every
178     *  RTEMS target configuration.  --joel (12 May 2007)
179     */
180    if (doCons) /* && (volatile void *)_init) */ {
181      INIT_NAME ();
182    }
183 #endif
184
185  /*
186   *  RTEMS supports multiple APIs and each API can define a different
187   *  thread/task prototype. The following code supports invoking the
188   *  user thread entry point using the prototype expected.
189   */
190  if ( executing->Start.prototype == THREAD_START_NUMERIC ) {
191    executing->Wait.return_argument =
192      (*(Thread_Entry_numeric) executing->Start.entry_point)(
193        executing->Start.numeric_argument
194      );
195  }
196  #if defined(RTEMS_POSIX_API)
197    else if ( executing->Start.prototype == THREAD_START_POINTER ) {
198      executing->Wait.return_argument =
199        (*(Thread_Entry_pointer) executing->Start.entry_point)(
200          executing->Start.pointer_argument
201        );
202    }
203  #endif
204  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
205    else if ( executing->Start.prototype == THREAD_START_BOTH_POINTER_FIRST ) {
206      executing->Wait.return_argument =
207         (*(Thread_Entry_both_pointer_first) executing->Start.entry_point)(
208           executing->Start.pointer_argument,
209           executing->Start.numeric_argument
210         );
211    }
212    else if ( executing->Start.prototype == THREAD_START_BOTH_NUMERIC_FIRST ) {
213      executing->Wait.return_argument =
214       (*(Thread_Entry_both_numeric_first) executing->Start.entry_point)(
215         executing->Start.numeric_argument,
216         executing->Start.pointer_argument
217       );
218    }
219  #endif
220
221  /*
222   *  In the switch above, the return code from the user thread body
223   *  was placed in return_argument.  This assumed that if it returned
224   *  anything (which is not supporting in all APIs), then it would be
225   *  able to fit in a (void *).
226   */
227
228  _User_extensions_Thread_exitted( executing );
229
230  _Terminate(
231    INTERNAL_ERROR_CORE,
232    true,
233    INTERNAL_ERROR_THREAD_EXITTED
234  );
235}
Note: See TracBrowser for help on using the repository browser.