source: rtems/cpukit/score/src/thread.c @ 63edbb3f

4.104.114.84.95
Last change on this file since 63edbb3f was 63edbb3f, checked in by Joel Sherrill <joel.sherrill@…>, on 08/22/95 at 16:57:18

Fixed missing RCS Ids

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