source: rtems/cpukit/score/src/threadhandler.c @ a38ced2

4.115
Last change on this file since a38ced2 was a38ced2, checked in by Sebastian Huber <sebastian.huber@…>, on 10/10/14 at 07:09:19

score: Rework global construction

Ensure that the global construction is performed in the context of the
first initialization thread. On SMP this was not guaranteed in the
previous implementation.

  • Property mode set to 100644
File size: 4.6 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
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    /*
42     * have to put level into a register for those cpu's that use
43     * inline asm here
44     */
45    level = executing->Start.isr_level;
46    _ISR_Set_level( level );
47  #endif
48
49  /*
50   * Initialize the floating point context because we do not come
51   * through _Thread_Dispatch on our first invocation. So the normal
52   * code path for performing the FP context switch is not hit.
53   */
54  #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
55    #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
56      if ( (executing->fp_context != NULL) &&
57            !_Thread_Is_allocated_fp( executing ) ) {
58        if ( _Thread_Allocated_fp != NULL )
59          _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
60        _Thread_Allocated_fp = executing;
61      }
62    #endif
63  #endif
64
65  /*
66   * Take care that 'begin' extensions get to complete before
67   * 'switch' extensions can run.  This means must keep dispatch
68   * disabled until all 'begin' extensions complete.
69   */
70  _User_extensions_Thread_begin( executing );
71
72  /*
73   *  At this point, the dispatch disable level BETTER be 1.
74   */
75  #if defined(RTEMS_SMP)
76    {
77      /*
78       * On SMP we enter _Thread_Handler() with interrupts disabled and
79       * _Thread_Dispatch() obtained the per-CPU lock for us.  We have to
80       * release it here and set the desired interrupt level of the thread.
81       */
82      Per_CPU_Control *cpu_self = _Per_CPU_Get();
83
84      _Assert( cpu_self->thread_dispatch_disable_level == 1 );
85      _Assert( _ISR_Get_level() != 0 );
86
87      _Thread_Debug_set_real_processor( executing, cpu_self );
88
89      cpu_self->thread_dispatch_disable_level = 0;
90      _Profiling_Thread_dispatch_enable( cpu_self, 0 );
91
92      level = executing->Start.isr_level;
93      _ISR_Set_level( level);
94
95      /*
96       * The thread dispatch level changed from one to zero.  Make sure we lose
97       * no thread dispatch necessary update.
98       */
99      _Thread_Dispatch();
100    }
101  #else
102    _Thread_Enable_dispatch();
103  #endif
104
105  /*
106   *  RTEMS supports multiple APIs and each API can define a different
107   *  thread/task prototype. The following code supports invoking the
108   *  user thread entry point using the prototype expected.
109   */
110  if ( executing->Start.prototype == THREAD_START_NUMERIC ) {
111    executing->Wait.return_argument =
112      (*(Thread_Entry_numeric) executing->Start.entry_point)(
113        executing->Start.numeric_argument
114      );
115  }
116  #if defined(RTEMS_POSIX_API)
117    else if ( executing->Start.prototype == THREAD_START_POINTER ) {
118      executing->Wait.return_argument =
119        (*(Thread_Entry_pointer) executing->Start.entry_point)(
120          executing->Start.pointer_argument
121        );
122    }
123  #endif
124  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
125    else if ( executing->Start.prototype == THREAD_START_BOTH_POINTER_FIRST ) {
126      executing->Wait.return_argument =
127         (*(Thread_Entry_both_pointer_first) executing->Start.entry_point)(
128           executing->Start.pointer_argument,
129           executing->Start.numeric_argument
130         );
131    }
132    else if ( executing->Start.prototype == THREAD_START_BOTH_NUMERIC_FIRST ) {
133      executing->Wait.return_argument =
134       (*(Thread_Entry_both_numeric_first) executing->Start.entry_point)(
135         executing->Start.numeric_argument,
136         executing->Start.pointer_argument
137       );
138    }
139  #endif
140
141  /*
142   *  In the switch above, the return code from the user thread body
143   *  was placed in return_argument.  This assumed that if it returned
144   *  anything (which is not supporting in all APIs), then it would be
145   *  able to fit in a (void *).
146   */
147
148  _User_extensions_Thread_exitted( executing );
149
150  _Terminate(
151    INTERNAL_ERROR_CORE,
152    true,
153    INTERNAL_ERROR_THREAD_EXITTED
154  );
155}
Note: See TracBrowser for help on using the repository browser.