source: rtems/c/src/exec/score/src/thread.c @ ac7d5ef0

4.104.114.84.95
Last change on this file since ac7d5ef0 was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on 05/11/95 at 17:39:37

Initial revision

  • Property mode set to 100644
File size: 19.0 KB
Line 
1/*
2 *  Thread Handler
3 *
4 *
5 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
6 *  On-Line Applications Research Corporation (OAR).
7 *  All rights assigned to U.S. Government, 1994.
8 *
9 *  This material may be reproduced by or for the U.S. Government pursuant
10 *  to the copyright license under the clause at DFARS 252.227-7013.  This
11 *  notice must appear in all copies of this file and its derivatives.
12 *
13 *  $Id$
14 */
15
16#include <rtems/system.h>
17#include <rtems/config.h>
18#include <rtems/context.h>
19#include <rtems/fatal.h>
20#include <rtems/init.h>
21#include <rtems/intthrd.h>
22#include <rtems/isr.h>
23#include <rtems/modes.h>
24#include <rtems/object.h>
25#include <rtems/priority.h>
26#include <rtems/states.h>
27#include <rtems/thread.h>
28#include <rtems/userext.h>
29#include <rtems/wkspace.h>
30
31/*PAGE
32 *
33 *  _Thread_Handler_initialization
34 *
35 *  This routine initializes all thread manager related data structures.
36 *
37 *  Input parameters:
38 *    maximum_tasks       - number of tasks to initialize
39 *    ticks_per_timeslice - clock ticks per quantum
40 *
41 *  Output parameters:  NONE
42 */
43
44void _Thread_Handler_initialization(
45  unsigned32   maximum_tasks,
46  unsigned32   ticks_per_timeslice,
47  unsigned32   maximum_proxies
48)
49{
50  unsigned32 index;
51
52  _Context_Switch_necessary = FALSE;
53  _Thread_Executing         = NULL;
54  _Thread_Heir              = NULL;
55  _Thread_Allocated_fp      = NULL;
56
57  _Thread_Ticks_remaining_in_timeslice = ticks_per_timeslice;
58  _Thread_Ticks_per_timeslice          = ticks_per_timeslice;
59
60  _Objects_Initialize_information(
61     &_Thread_Information,
62     TRUE,
63     maximum_tasks,
64     sizeof( Thread_Control )
65  );
66
67  _Thread_Ready_chain = _Workspace_Allocate_or_fatal_error(
68    (RTEMS_MAXIMUM_PRIORITY + 1) * sizeof(Chain_Control)
69  );
70
71  for ( index=0; index <= RTEMS_MAXIMUM_PRIORITY ; index++ )
72    _Chain_Initialize_empty( &_Thread_Ready_chain[ index ] );
73
74  _Thread_MP_Handler_initialization( maximum_proxies );
75}
76
77/*PAGE
78 *
79 *  _Thread_Start_multitasking
80 *
81 *  This kernel routine readies the requested thread, the thread chain
82 *  is adjusted.  A new heir thread may be selected.
83 *
84 *  Input parameters:
85 *    system_thread - pointer to system initialization thread control block
86 *    idle_thread   - pointer to idle thread control block
87 *
88 *  Output parameters:  NONE
89 *
90 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
91 *         This insures the correct heir after a thread restart.
92 *
93 *  INTERRUPT LATENCY:
94 *    ready chain
95 *    select heir
96 */
97
98void _Thread_Start_multitasking(
99  Thread_Control *system_thread,
100  Thread_Control *idle_thread
101)
102{
103
104   _Thread_Executing  =
105   _Thread_Heir       =
106   _Thread_MP_Receive = system_thread;
107
108   /*
109    *  Scheduling will not work "correctly" until the above
110    *  statements have been executed.
111    */
112
113   _Thread_Ready( system_thread );
114   _Thread_Ready( idle_thread );
115
116   _Context_Switch_necessary = FALSE;
117
118   _Context_Switch( &_Thread_BSP_context, &system_thread->Registers );
119
120}
121
122/*PAGE
123 *
124 *  _Thread_Dispatch
125 *
126 *  This kernel routine determines if a dispatch is needed, and if so
127 *  dispatches to the heir thread.  Once the heir is running an attempt
128 *  is made to dispatch any ASRs.
129 *
130 *  ALTERNATE ENTRY POINTS:
131 *    void _Thread_Enable_dispatch();
132 *
133 *  Input parameters:  NONE
134 *
135 *  Output parameters:  NONE
136 *
137 *  INTERRUPT LATENCY:
138 *    dispatch thread
139 *    no dispatch thread
140 */
141
142#if ( CPU_INLINE_ENABLE_DISPATCH == FALSE )
143void _Thread_Enable_dispatch( void )
144{
145  if ( --_Thread_Dispatch_disable_level )
146    return;
147  _Thread_Dispatch();
148}
149#endif
150
151void _Thread_Dispatch( void )
152{
153  Thread_Control  *executing;
154  Thread_Control  *heir;
155  ISR_Level               level;
156  rtems_signal_set  signal_set;
157  rtems_mode           previous_mode;
158
159  executing   = _Thread_Executing;
160  _ISR_Disable( level );
161  while ( _Context_Switch_necessary == TRUE ) {
162    heir = _Thread_Heir;
163    _Thread_Dispatch_disable_level = 1;
164    _Context_Switch_necessary = FALSE;
165    _Thread_Executing = heir;
166    _ISR_Enable( level );
167
168    _User_extensions_Task_switch( executing, heir );
169
170    _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
171
172    /*
173     *  If the CPU has hardware floating point, then we must address saving
174     *  and restoring it as part of the context switch.
175     *
176     *  The second conditional compilation section selects the algorithm used
177     *  to context switch between floating point tasks.  The deferred algorithm
178     *  can be significantly better in a system with few floating point tasks
179     *  because it reduces the total number of save and restore FP context
180     *  operations.  However, this algorithm can not be used on all CPUs due
181     *  to unpredictable use of FP registers by some compilers for integer
182     *  operations.
183     */
184
185#if ( CPU_HARDWARE_FP == TRUE )
186#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
187    if ( (heir->fp_context != NULL) && !_Thread_Is_allocated_fp( heir ) ) {
188      if ( _Thread_Allocated_fp != NULL )
189        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
190      _Context_Restore_fp( &heir->fp_context );
191      _Thread_Allocated_fp = heir;
192    }
193#else
194    if ( executing->fp_context != NULL )
195      _Context_Save_fp( &executing->fp_context );
196
197    if ( heir->fp_context != NULL )
198      _Context_Restore_fp( &heir->fp_context );
199#endif
200#endif
201
202    _Context_Switch( &executing->Registers, &heir->Registers );
203
204    executing = _Thread_Executing;
205    _ISR_Disable( level );
206  }
207
208  _Thread_Dispatch_disable_level = 0;
209
210  if ( _ASR_Are_signals_pending( &executing->Signal ) ) {
211    signal_set                       = executing->Signal.signals_posted;
212    executing->Signal.signals_posted = 0;
213    _ISR_Enable( level );
214
215    executing->Signal.nest_level += 1;
216    if (_Thread_Change_mode( executing->Signal.mode_set,
217                                RTEMS_ALL_MODE_MASKS, &previous_mode ))
218        _Thread_Dispatch();
219
220    (*executing->Signal.handler)( signal_set );
221
222    executing->Signal.nest_level -= 1;
223    if (_Thread_Change_mode( previous_mode,
224                                RTEMS_ALL_MODE_MASKS, &previous_mode ))
225        _Thread_Dispatch();
226  }
227  else
228    _ISR_Enable( level );
229}
230
231/*PAGE
232 *
233 *  _Thread_Ready
234 *
235 *  This kernel routine readies the requested thread, the thread chain
236 *  is adjusted.  A new heir thread may be selected.
237 *
238 *  Input parameters:
239 *    the_thread - pointer to thread control block
240 *
241 *  Output parameters:  NONE
242 *
243 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
244 *         This insures the correct heir after a thread restart.
245 *
246 *  INTERRUPT LATENCY:
247 *    ready chain
248 *    select heir
249 */
250
251void _Thread_Ready(
252  Thread_Control *the_thread
253)
254{
255  ISR_Level              level;
256  Thread_Control *heir;
257
258  _ISR_Disable( level );
259
260  the_thread->current_state = STATES_READY;
261
262  _Priority_Add_to_bit_map( &the_thread->Priority_map );
263
264  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
265
266  _ISR_Flash( level );
267
268  _Thread_Calculate_heir();
269
270  heir = _Thread_Heir;
271
272  if ( !_Thread_Is_executing( heir ) &&
273        _Modes_Is_preempt( _Thread_Executing->current_modes ) )
274    _Context_Switch_necessary = TRUE;
275
276  _ISR_Enable( level );
277}
278
279/*PAGE
280 *
281 *  _Thread_Clear_state
282 *
283 *  This kernel routine clears the appropriate states in the
284 *  requested thread.  The thread ready chain is adjusted if
285 *  necessary and the Heir thread is set accordingly.
286 *
287 *  Input parameters:
288 *    the_thread - pointer to thread control block
289 *    state      - state set to clear
290 *
291 *  Output parameters:  NONE
292 *
293 *  INTERRUPT LATENCY:
294 *    priority map
295 *    select heir
296 */
297
298void _Thread_Clear_state(
299  Thread_Control *the_thread,
300  States_Control  state
301)
302{
303  ISR_Level level;
304
305  _ISR_Disable( level );
306    the_thread->current_state =
307      _States_Clear( state, the_thread->current_state );
308
309    if ( _States_Is_ready( the_thread->current_state ) ) {
310
311      _Priority_Add_to_bit_map( &the_thread->Priority_map );
312
313      _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
314
315      _ISR_Flash( level );
316
317      if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
318        _Thread_Heir = the_thread;
319        if ( _Modes_Is_preempt( _Thread_Executing->current_modes ) )
320          _Context_Switch_necessary = TRUE;
321      }
322    }
323  _ISR_Enable( level );
324}
325
326/*PAGE
327 *
328 * _Thread_Set_state
329 *
330 * This kernel routine sets the requested state in the THREAD.  The
331 * THREAD chain is adjusted if necessary.
332 *
333 * Input parameters:
334 *   the_thread   - pointer to thread control block
335 *   state - state to be set
336 *
337 * Output parameters:  NONE
338 *
339 *  INTERRUPT LATENCY:
340 *    ready chain
341 *    select map
342 */
343
344void _Thread_Set_state(
345  Thread_Control *the_thread,
346  States_Control         state
347)
348{
349  ISR_Level             level;
350  Chain_Control *ready;
351
352  ready = the_thread->ready;
353  _ISR_Disable( level );
354  if ( !_States_Is_ready( the_thread->current_state ) ) {
355    the_thread->current_state =
356       _States_Set( state, the_thread->current_state );
357    _ISR_Enable( level );
358    return;
359  }
360
361  the_thread->current_state = state;
362
363  if ( _Chain_Has_only_one_node( ready ) ) {
364
365    _Chain_Initialize_empty( ready );
366    _Priority_Remove_from_bit_map( &the_thread->Priority_map );
367
368  } else
369    _Chain_Extract_unprotected( &the_thread->Object.Node );
370
371  _ISR_Flash( level );
372
373  if ( _Thread_Is_heir( the_thread ) )
374     _Thread_Calculate_heir();
375
376  if ( _Thread_Is_executing( the_thread ) )
377    _Context_Switch_necessary = TRUE;
378
379  _ISR_Enable( level );
380}
381
382/*PAGE
383 *
384 *  _Thread_Set_transient
385 *
386 *  This kernel routine places the requested thread in the transient state
387 *  which will remove it from the ready queue, if necessary.  No
388 *  rescheduling is necessary because it is assumed that the transient
389 *  state will be cleared before dispatching is enabled.
390 *
391 *  Input parameters:
392 *    the_thread - pointer to thread control block
393 *
394 *  Output parameters:  NONE
395 *
396 *  INTERRUPT LATENCY:
397 *    only case
398 */
399
400void _Thread_Set_transient(
401  Thread_Control *the_thread
402)
403{
404  ISR_Level             level;
405  unsigned32            old_state;
406  Chain_Control *ready;
407
408  ready = the_thread->ready;
409  _ISR_Disable( level );
410
411  old_state = the_thread->current_state;
412  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );
413
414  if ( _States_Is_ready( old_state ) ) {
415    if ( _Chain_Has_only_one_node( ready ) ) {
416
417      _Chain_Initialize_empty( ready );
418      _Priority_Remove_from_bit_map( &the_thread->Priority_map );
419
420    } else
421      _Chain_Extract_unprotected( &the_thread->Object.Node );
422  }
423
424  _ISR_Enable( level );
425
426}
427
428/*PAGE
429 *
430 *  _Thread_Reset_timeslice
431 *
432 *  This routine will remove the running thread from the ready chain
433 *  and place it immediately at the rear of this chain and then the
434 *  timeslice counter is reset.  The heir THREAD will be updated if
435 *  the running is also the currently the heir.
436 *
437 *  Input parameters:   NONE
438 *
439 *  Output parameters:  NONE
440 *
441 *  INTERRUPT LATENCY:
442 *    ready chain
443 *    select heir
444 */
445
446void _Thread_Reset_timeslice( void )
447{
448  ISR_Level              level;
449  Thread_Control *executing;
450  Chain_Control  *ready;
451
452  executing = _Thread_Executing;
453  ready     = executing->ready;
454  _ISR_Disable( level );
455    if ( _Chain_Has_only_one_node( ready ) ) {
456      _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
457      _ISR_Enable( level );
458      return;
459    }
460    _Chain_Extract_unprotected( &executing->Object.Node );
461    _Chain_Append_unprotected( ready, &executing->Object.Node );
462
463  _ISR_Flash( level );
464
465    if ( _Thread_Is_heir( executing ) )
466      _Thread_Heir = (Thread_Control *) ready->first;
467
468    _Context_Switch_necessary = TRUE;
469
470  _ISR_Enable( level );
471}
472
473/*PAGE
474 *
475 *  _Thread_Tickle_timeslice
476 *
477 *  This scheduler routine determines if timeslicing is enabled
478 *  for the currently executing thread and, if so, updates the
479 *  timeslice count and checks for timeslice expiration.
480 *
481 *  Input parameters:   NONE
482 *
483 *  Output parameters:  NONE
484 */
485
486void _Thread_Tickle_timeslice( void )
487{
488  if ( ( _Modes_Is_timeslice(_Thread_Executing->current_modes) )  &&
489       ( _States_Is_ready( _Thread_Executing->current_state ) ) &&
490       ( --_Thread_Ticks_remaining_in_timeslice == 0 ) ) {
491      _Thread_Reset_timeslice();
492  }
493}
494
495/*PAGE
496 *
497 *  _Thread_Yield_processor
498 *
499 *  This kernel routine will remove the running THREAD from the ready chain
500 *  and place it immediatly at the rear of this chain.  Reset timeslice
501 *  and yield the processor functions both use this routine, therefore if
502 *  reset is TRUE and this is the only thread on the chain then the
503 *  timeslice counter is reset.  The heir THREAD will be updated if the
504 *  running is also the currently the heir.
505 *
506 *  Input parameters:   NONE
507 *
508 *  Output parameters:  NONE
509 *
510 *  INTERRUPT LATENCY:
511 *    ready chain
512 *    select heir
513 */
514
515void _Thread_Yield_processor( void )
516{
517  ISR_Level       level;
518  Thread_Control *executing;
519  Chain_Control  *ready;
520
521  executing = _Thread_Executing;
522  ready     = executing->ready;
523  _ISR_Disable( level );
524    if ( !_Chain_Has_only_one_node( ready ) ) {
525      _Chain_Extract_unprotected( &executing->Object.Node );
526      _Chain_Append_unprotected( ready, &executing->Object.Node );
527
528      _ISR_Flash( level );
529
530      if ( _Thread_Is_heir( executing ) )
531        _Thread_Heir = (Thread_Control *) ready->first;
532      _Context_Switch_necessary = TRUE;
533    }
534    else if ( !_Thread_Is_heir( executing ) )
535      _Context_Switch_necessary = TRUE;
536
537  _ISR_Enable( level );
538}
539
540/*PAGE
541 *
542 *  _Thread_Load_environment
543 *
544 *  Load starting environment for another thread from its start area in the
545 *  thread.  Only called from t_restart and t_start.
546 *
547 *  Input parameters:
548 *    the_thread - thread control block pointer
549 *
550 *  Output parameters:  NONE
551 */
552
553void _Thread_Load_environment(
554  Thread_Control *the_thread
555)
556{
557  if ( the_thread->Start.fp_context ) {
558    the_thread->fp_context = the_thread->Start.fp_context;
559    _Context_Initialize_fp( &the_thread->fp_context );
560  }
561
562  _Context_Initialize(
563    &the_thread->Registers,
564    the_thread->Start.Initial_stack.area,
565    the_thread->Start.Initial_stack.size,
566    _Modes_Get_interrupt_level( the_thread->Start.initial_modes ),
567    _Thread_Handler
568  );
569
570}
571
572/*PAGE
573 *
574 *  _Thread_Handler
575 *
576 *  This routine is the default thread exitted error handler.  It is
577 *  returned to when a thread exits.  The configured fatal error handler
578 *  is invoked to process the exit.
579 *
580 *  Input parameters:   NONE
581 *
582 *  Output parameters:  NONE
583 */
584
585void _Thread_Handler( void )
586{
587  Thread_Control *executing;
588
589  executing = _Thread_Executing;
590
591  _Thread_Dispatch_disable_level = 0;
592
593  /*
594   * Do the 'begin' here instead of after the context switch.
595   * This ensures 'switch' extensions can not be called before
596   * 'begin' extensions.
597   */
598
599  _User_extensions_Task_begin( executing );
600
601  if ( _Thread_Is_context_switch_necessary() )
602    _Thread_Dispatch();
603
604  (*executing->Start.entry_point)( executing->Start.initial_argument );
605
606  _User_extensions_Task_exitted( executing );
607
608  rtems_fatal_error_occurred( RTEMS_TASK_EXITTED );
609}
610
611/*PAGE
612 *
613 *  _Thread_Delay_ended
614 *
615 *  This routine processes a thread whose delay period has ended.
616 *  It is called by the watchdog handler.
617 *
618 *  Input parameters:
619 *    id - thread id
620 *
621 *  Output parameters: NONE
622 */
623
624void _Thread_Delay_ended(
625  Objects_Id  id,
626  void       *ignored
627)
628{
629  Thread_Control *the_thread;
630  Objects_Locations      location;
631
632  the_thread = _Thread_Get( id, &location );
633  switch ( location ) {
634    case OBJECTS_ERROR:
635    case OBJECTS_REMOTE:  /* impossible */
636      break;
637    case OBJECTS_LOCAL:
638      _Thread_Unblock( the_thread );
639      _Thread_Unnest_dispatch();
640      break;
641  }
642}
643
644/*PAGE
645 *
646 *  _Thread_Change_priority
647 *
648 *  This kernel routine changes the priority of the thread.  The
649 *  thread chain is adjusted if necessary.
650 *
651 *  Input parameters:
652 *    the_thread   - pointer to thread control block
653 *    new_priority - ultimate priority
654 *
655 *  Output parameters:  NONE
656 *
657 *  INTERRUPT LATENCY:
658 *    ready chain
659 *    select heir
660 */
661
662void _Thread_Change_priority(
663  Thread_Control *the_thread,
664  rtems_task_priority       new_priority
665)
666{
667  ISR_Level level;
668
669  _Thread_Set_transient( the_thread );
670
671  if ( the_thread->current_priority != new_priority )
672    _Thread_Set_priority( the_thread, new_priority );
673
674  _ISR_Disable( level );
675
676  the_thread->current_state =
677    _States_Clear( STATES_TRANSIENT, the_thread->current_state );
678
679  if ( ! _States_Is_ready( the_thread->current_state ) ) {
680    _ISR_Enable( level );
681    return;
682  }
683
684  _Priority_Add_to_bit_map( &the_thread->Priority_map );
685  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
686
687  _ISR_Flash( level );
688
689  _Thread_Calculate_heir();
690
691  if ( !_Thread_Is_executing_also_the_heir() &&
692       _Modes_Is_preempt(_Thread_Executing->current_modes) )
693    _Context_Switch_necessary = TRUE;
694
695  _ISR_Enable( level );
696}
697
698/*PAGE
699 *
700 * _Thread_Set_priority
701 *
702 * This directive enables and disables several modes of
703 * execution for the requesting thread.
704 *
705 *  Input parameters:
706 *    the_thread   - pointer to thread priority
707 *    new_priority - new priority
708 *
709 *  Output: NONE
710 */
711
712void _Thread_Set_priority(
713  Thread_Control *the_thread,
714  rtems_task_priority       new_priority
715)
716{
717  the_thread->current_priority = new_priority;
718  the_thread->ready            = &_Thread_Ready_chain[ new_priority ];
719
720  _Priority_Initialize_information( &the_thread->Priority_map, new_priority );
721}
722
723/*PAGE
724 *
725 *  _Thread_Change_mode
726 *
727 *  This routine enables and disables several modes of
728 *  execution for the requesting thread.
729 *
730 *  Input parameters:
731 *    mode         - new mode
732 *    mask         - mask
733 *    old_mode_set - address of previous mode
734 *
735 *  Output:
736 *    *old_mode_set - previous mode
737 *     returns TRUE if scheduling necessary
738 *
739 *  INTERRUPT LATENCY:
740 *    only one case
741 */
742
743boolean _Thread_Change_mode(
744  unsigned32  new_mode_set,
745  unsigned32  mask,
746  unsigned32 *old_mode_set
747)
748{
749  rtems_mode   changed;
750  rtems_mode   threads_new_mode_set;
751  Thread_Control *executing;
752  boolean         need_dispatch;
753
754  executing     = _Thread_Executing;
755  *old_mode_set = executing->current_modes;
756
757  _Modes_Change( executing->current_modes,
758                   new_mode_set, mask, &threads_new_mode_set, &changed );
759
760  _Modes_Set_interrupt_level( threads_new_mode_set );
761
762  if ( _Modes_Mask_changed( changed, RTEMS_ASR_MASK ) )
763    _ASR_Swap_signals( &executing->Signal );
764
765  executing->current_modes = threads_new_mode_set;
766  need_dispatch = TRUE;
767
768  if ( !_States_Is_ready( executing->current_state ) ||
769       ( !_Thread_Is_heir( executing ) &&
770         _Modes_Is_preempt(threads_new_mode_set) ) )
771
772     _Context_Switch_necessary = TRUE;
773
774  else if ( !_ASR_Are_signals_pending( &executing->Signal ) )
775
776    need_dispatch = FALSE;
777
778  return need_dispatch;
779}
780
781/*PAGE
782 *
783 *  _Thread_Get
784 *
785 *  NOTE:  If we are not using static inlines, this must be a real
786 *         subroutine call.
787 */
788
789#ifndef USE_INLINES
790
791STATIC INLINE Thread_Control *_Thread_Get (
792  Objects_Id  id,
793  unsigned32 *location
794)
795{
796  if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) {
797     _Thread_Disable_dispatch();
798     *location = OBJECTS_LOCAL;
799     return( _Thread_Executing );
800  }
801
802  return (Thread_Control *) _Objects_Get( &_Thread_Information, id, location );
803}
804#endif
805
Note: See TracBrowser for help on using the repository browser.