source: rtems/cpukit/score/src/thread.c @ 3a5dbdc

4.104.114.84.95
Last change on this file since 3a5dbdc was 3a5dbdc, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 31, 1995 at 10:22:38 PM

Switched to events for mp receive server and eliminated the special
blocking mechanism for it.

  • 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     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             the_thread->current_priority == 0 )
321          _Context_Switch_necessary = TRUE;
322      }
323    }
324  _ISR_Enable( level );
325}
326
327/*PAGE
328 *
329 * _Thread_Set_state
330 *
331 * This kernel routine sets the requested state in the THREAD.  The
332 * THREAD chain is adjusted if necessary.
333 *
334 * Input parameters:
335 *   the_thread   - pointer to thread control block
336 *   state - state to be set
337 *
338 * Output parameters:  NONE
339 *
340 *  INTERRUPT LATENCY:
341 *    ready chain
342 *    select map
343 */
344
345void _Thread_Set_state(
346  Thread_Control *the_thread,
347  States_Control         state
348)
349{
350  ISR_Level             level;
351  Chain_Control *ready;
352
353  ready = the_thread->ready;
354  _ISR_Disable( level );
355  if ( !_States_Is_ready( the_thread->current_state ) ) {
356    the_thread->current_state =
357       _States_Set( state, the_thread->current_state );
358    _ISR_Enable( level );
359    return;
360  }
361
362  the_thread->current_state = state;
363
364  if ( _Chain_Has_only_one_node( ready ) ) {
365
366    _Chain_Initialize_empty( ready );
367    _Priority_Remove_from_bit_map( &the_thread->Priority_map );
368
369  } else
370    _Chain_Extract_unprotected( &the_thread->Object.Node );
371
372  _ISR_Flash( level );
373
374  if ( _Thread_Is_heir( the_thread ) )
375     _Thread_Calculate_heir();
376
377  if ( _Thread_Is_executing( the_thread ) )
378    _Context_Switch_necessary = TRUE;
379
380  _ISR_Enable( level );
381}
382
383/*PAGE
384 *
385 *  _Thread_Set_transient
386 *
387 *  This kernel routine places the requested thread in the transient state
388 *  which will remove it from the ready queue, if necessary.  No
389 *  rescheduling is necessary because it is assumed that the transient
390 *  state will be cleared before dispatching is enabled.
391 *
392 *  Input parameters:
393 *    the_thread - pointer to thread control block
394 *
395 *  Output parameters:  NONE
396 *
397 *  INTERRUPT LATENCY:
398 *    only case
399 */
400
401void _Thread_Set_transient(
402  Thread_Control *the_thread
403)
404{
405  ISR_Level             level;
406  unsigned32            old_state;
407  Chain_Control *ready;
408
409  ready = the_thread->ready;
410  _ISR_Disable( level );
411
412  old_state = the_thread->current_state;
413  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );
414
415  if ( _States_Is_ready( old_state ) ) {
416    if ( _Chain_Has_only_one_node( ready ) ) {
417
418      _Chain_Initialize_empty( ready );
419      _Priority_Remove_from_bit_map( &the_thread->Priority_map );
420
421    } else
422      _Chain_Extract_unprotected( &the_thread->Object.Node );
423  }
424
425  _ISR_Enable( level );
426
427}
428
429/*PAGE
430 *
431 *  _Thread_Reset_timeslice
432 *
433 *  This routine will remove the running thread from the ready chain
434 *  and place it immediately at the rear of this chain and then the
435 *  timeslice counter is reset.  The heir THREAD will be updated if
436 *  the running is also the currently the heir.
437 *
438 *  Input parameters:   NONE
439 *
440 *  Output parameters:  NONE
441 *
442 *  INTERRUPT LATENCY:
443 *    ready chain
444 *    select heir
445 */
446
447void _Thread_Reset_timeslice( void )
448{
449  ISR_Level              level;
450  Thread_Control *executing;
451  Chain_Control  *ready;
452
453  executing = _Thread_Executing;
454  ready     = executing->ready;
455  _ISR_Disable( level );
456    if ( _Chain_Has_only_one_node( ready ) ) {
457      _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
458      _ISR_Enable( level );
459      return;
460    }
461    _Chain_Extract_unprotected( &executing->Object.Node );
462    _Chain_Append_unprotected( ready, &executing->Object.Node );
463
464  _ISR_Flash( level );
465
466    if ( _Thread_Is_heir( executing ) )
467      _Thread_Heir = (Thread_Control *) ready->first;
468
469    _Context_Switch_necessary = TRUE;
470
471  _ISR_Enable( level );
472}
473
474/*PAGE
475 *
476 *  _Thread_Tickle_timeslice
477 *
478 *  This scheduler routine determines if timeslicing is enabled
479 *  for the currently executing thread and, if so, updates the
480 *  timeslice count and checks for timeslice expiration.
481 *
482 *  Input parameters:   NONE
483 *
484 *  Output parameters:  NONE
485 */
486
487void _Thread_Tickle_timeslice( void )
488{
489  if ( ( _Modes_Is_timeslice(_Thread_Executing->current_modes) )  &&
490       ( _States_Is_ready( _Thread_Executing->current_state ) ) &&
491       ( --_Thread_Ticks_remaining_in_timeslice == 0 ) ) {
492      _Thread_Reset_timeslice();
493  }
494}
495
496/*PAGE
497 *
498 *  _Thread_Yield_processor
499 *
500 *  This kernel routine will remove the running THREAD from the ready chain
501 *  and place it immediatly at the rear of this chain.  Reset timeslice
502 *  and yield the processor functions both use this routine, therefore if
503 *  reset is TRUE and this is the only thread on the chain then the
504 *  timeslice counter is reset.  The heir THREAD will be updated if the
505 *  running is also the currently the heir.
506 *
507 *  Input parameters:   NONE
508 *
509 *  Output parameters:  NONE
510 *
511 *  INTERRUPT LATENCY:
512 *    ready chain
513 *    select heir
514 */
515
516void _Thread_Yield_processor( void )
517{
518  ISR_Level       level;
519  Thread_Control *executing;
520  Chain_Control  *ready;
521
522  executing = _Thread_Executing;
523  ready     = executing->ready;
524  _ISR_Disable( level );
525    if ( !_Chain_Has_only_one_node( ready ) ) {
526      _Chain_Extract_unprotected( &executing->Object.Node );
527      _Chain_Append_unprotected( ready, &executing->Object.Node );
528
529      _ISR_Flash( level );
530
531      if ( _Thread_Is_heir( executing ) )
532        _Thread_Heir = (Thread_Control *) ready->first;
533      _Context_Switch_necessary = TRUE;
534    }
535    else if ( !_Thread_Is_heir( executing ) )
536      _Context_Switch_necessary = TRUE;
537
538  _ISR_Enable( level );
539}
540
541/*PAGE
542 *
543 *  _Thread_Load_environment
544 *
545 *  Load starting environment for another thread from its start area in the
546 *  thread.  Only called from t_restart and t_start.
547 *
548 *  Input parameters:
549 *    the_thread - thread control block pointer
550 *
551 *  Output parameters:  NONE
552 */
553
554void _Thread_Load_environment(
555  Thread_Control *the_thread
556)
557{
558  if ( the_thread->Start.fp_context ) {
559    the_thread->fp_context = the_thread->Start.fp_context;
560    _Context_Initialize_fp( &the_thread->fp_context );
561  }
562
563  _Context_Initialize(
564    &the_thread->Registers,
565    the_thread->Start.Initial_stack.area,
566    the_thread->Start.Initial_stack.size,
567    _Modes_Get_interrupt_level( the_thread->Start.initial_modes ),
568    _Thread_Handler
569  );
570
571}
572
573/*PAGE
574 *
575 *  _Thread_Handler
576 *
577 *  This routine is the default thread exitted error handler.  It is
578 *  returned to when a thread exits.  The configured fatal error handler
579 *  is invoked to process the exit.
580 *
581 *  Input parameters:   NONE
582 *
583 *  Output parameters:  NONE
584 */
585
586void _Thread_Handler( void )
587{
588  Thread_Control *executing;
589
590  executing = _Thread_Executing;
591
592  /*
593   * Take care that 'begin' extensions get to complete before
594   * 'switch' extensions can run.  This means must keep dispatch
595   * disabled until all 'begin' extensions complete.
596   */
597 
598  _User_extensions_Task_begin( executing );
599 
600  /*
601   *  At this point, the dispatch disable level BETTER be 1.
602   */
603
604  _Thread_Enable_dispatch();
605 
606  (*executing->Start.entry_point)( executing->Start.initial_argument );
607
608  _User_extensions_Task_exitted( executing );
609
610  rtems_fatal_error_occurred( RTEMS_TASK_EXITTED );
611}
612
613/*PAGE
614 *
615 *  _Thread_Delay_ended
616 *
617 *  This routine processes a thread whose delay period has ended.
618 *  It is called by the watchdog handler.
619 *
620 *  Input parameters:
621 *    id - thread id
622 *
623 *  Output parameters: NONE
624 */
625
626void _Thread_Delay_ended(
627  Objects_Id  id,
628  void       *ignored
629)
630{
631  Thread_Control *the_thread;
632  Objects_Locations      location;
633
634  the_thread = _Thread_Get( id, &location );
635  switch ( location ) {
636    case OBJECTS_ERROR:
637    case OBJECTS_REMOTE:  /* impossible */
638      break;
639    case OBJECTS_LOCAL:
640      _Thread_Unblock( the_thread );
641      _Thread_Unnest_dispatch();
642      break;
643  }
644}
645
646/*PAGE
647 *
648 *  _Thread_Change_priority
649 *
650 *  This kernel routine changes the priority of the thread.  The
651 *  thread chain is adjusted if necessary.
652 *
653 *  Input parameters:
654 *    the_thread   - pointer to thread control block
655 *    new_priority - ultimate priority
656 *
657 *  Output parameters:  NONE
658 *
659 *  INTERRUPT LATENCY:
660 *    ready chain
661 *    select heir
662 */
663
664void _Thread_Change_priority(
665  Thread_Control *the_thread,
666  rtems_task_priority       new_priority
667)
668{
669  ISR_Level level;
670
671  _Thread_Set_transient( the_thread );
672
673  if ( the_thread->current_priority != new_priority )
674    _Thread_Set_priority( the_thread, new_priority );
675
676  _ISR_Disable( level );
677
678  the_thread->current_state =
679    _States_Clear( STATES_TRANSIENT, the_thread->current_state );
680
681  if ( ! _States_Is_ready( the_thread->current_state ) ) {
682    _ISR_Enable( level );
683    return;
684  }
685
686  _Priority_Add_to_bit_map( &the_thread->Priority_map );
687  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
688
689  _ISR_Flash( level );
690
691  _Thread_Calculate_heir();
692
693  if ( !_Thread_Is_executing_also_the_heir() &&
694       _Modes_Is_preempt(_Thread_Executing->current_modes) )
695    _Context_Switch_necessary = TRUE;
696
697  _ISR_Enable( level );
698}
699
700/*PAGE
701 *
702 * _Thread_Set_priority
703 *
704 * This directive enables and disables several modes of
705 * execution for the requesting thread.
706 *
707 *  Input parameters:
708 *    the_thread   - pointer to thread priority
709 *    new_priority - new priority
710 *
711 *  Output: NONE
712 */
713
714void _Thread_Set_priority(
715  Thread_Control *the_thread,
716  rtems_task_priority       new_priority
717)
718{
719  the_thread->current_priority = new_priority;
720  the_thread->ready            = &_Thread_Ready_chain[ new_priority ];
721
722  _Priority_Initialize_information( &the_thread->Priority_map, new_priority );
723}
724
725/*PAGE
726 *
727 *  _Thread_Change_mode
728 *
729 *  This routine enables and disables several modes of
730 *  execution for the requesting thread.
731 *
732 *  Input parameters:
733 *    mode         - new mode
734 *    mask         - mask
735 *    old_mode_set - address of previous mode
736 *
737 *  Output:
738 *    *old_mode_set - previous mode
739 *     returns TRUE if scheduling necessary
740 *
741 *  INTERRUPT LATENCY:
742 *    only one case
743 */
744
745boolean _Thread_Change_mode(
746  unsigned32  new_mode_set,
747  unsigned32  mask,
748  unsigned32 *old_mode_set
749)
750{
751  rtems_mode   changed;
752  rtems_mode   threads_new_mode_set;
753  Thread_Control *executing;
754  boolean         need_dispatch;
755
756  executing     = _Thread_Executing;
757  *old_mode_set = executing->current_modes;
758
759  _Modes_Change( executing->current_modes,
760                   new_mode_set, mask, &threads_new_mode_set, &changed );
761
762  _Modes_Set_interrupt_level( threads_new_mode_set );
763
764  if ( _Modes_Mask_changed( changed, RTEMS_ASR_MASK ) )
765    _ASR_Swap_signals( &executing->Signal );
766
767  executing->current_modes = threads_new_mode_set;
768  need_dispatch = TRUE;
769
770  if ( !_States_Is_ready( executing->current_state ) ||
771       ( !_Thread_Is_heir( executing ) &&
772         _Modes_Is_preempt(threads_new_mode_set) ) )
773
774     _Context_Switch_necessary = TRUE;
775
776  else if ( !_ASR_Are_signals_pending( &executing->Signal ) )
777
778    need_dispatch = FALSE;
779
780  return need_dispatch;
781}
782
783/*PAGE
784 *
785 *  _Thread_Get
786 *
787 *  NOTE:  If we are not using static inlines, this must be a real
788 *         subroutine call.
789 */
790
791#ifndef USE_INLINES
792
793STATIC INLINE Thread_Control *_Thread_Get (
794  Objects_Id  id,
795  unsigned32 *location
796)
797{
798  if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) {
799     _Thread_Disable_dispatch();
800     *location = OBJECTS_LOCAL;
801     return( _Thread_Executing );
802  }
803
804  return (Thread_Control *) _Objects_Get( &_Thread_Information, id, location );
805}
806#endif
807
Note: See TracBrowser for help on using the repository browser.