source: rtems/cpukit/score/src/thread.c @ 8faca06

4.104.114.84.95
Last change on this file since 8faca06 was 8faca06, checked in by Joel Sherrill <joel.sherrill@…>, on 04/22/96 at 16:46:36

thread.c: added support for optional user provided stack allocator

wkspace.c: made initialization routine a regular subroutine

  • Property mode set to 100644
File size: 28.4 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/score/apiext.h>
18#include <rtems/score/context.h>
19#include <rtems/score/interr.h>
20#include <rtems/score/isr.h>
21#include <rtems/score/object.h>
22#include <rtems/score/priority.h>
23#include <rtems/score/states.h>
24#include <rtems/score/sysstate.h>
25#include <rtems/score/thread.h>
26#include <rtems/score/threadq.h>
27#include <rtems/score/userext.h>
28#include <rtems/score/wkspace.h>
29
30/*PAGE
31 *
32 *  _Thread_Handler_initialization
33 *
34 *  This routine initializes all thread manager related data structures.
35 *
36 *  Input parameters:
37 *    ticks_per_timeslice - clock ticks per quantum
38 *    maximum_proxies     - number of proxies to initialize
39 *
40 *  Output parameters:  NONE
41 */
42
43char *_Thread_Idle_name = "IDLE";
44
45void _Thread_Handler_initialization(
46  unsigned32   ticks_per_timeslice,
47  unsigned32   maximum_extensions,
48  unsigned32   maximum_proxies
49)
50{
51  unsigned32      index;
52
53  /*
54   * BOTH stacks hooks must be set or both must be NULL.
55   * Do not allow mixture.
56   */
57
58  if ( !( ( _CPU_Table.stack_allocate_hook == 0 )
59       == ( _CPU_Table.stack_free_hook == 0 ) ) )
60    _Internal_error_Occurred(
61      INTERNAL_ERROR_CORE,
62      TRUE,
63      INTERNAL_ERROR_BAD_STACK_HOOK
64    );
65
66  _Context_Switch_necessary = FALSE;
67  _Thread_Executing         = NULL;
68  _Thread_Heir              = NULL;
69  _Thread_Allocated_fp      = NULL;
70
71  _Thread_Maximum_extensions = maximum_extensions;
72
73  _Thread_Ticks_remaining_in_timeslice = ticks_per_timeslice;
74  _Thread_Ticks_per_timeslice          = ticks_per_timeslice;
75
76  _Thread_Ready_chain = _Workspace_Allocate_or_fatal_error(
77    (PRIORITY_MAXIMUM + 1) * sizeof(Chain_Control)
78  );
79
80  for ( index=0; index <= PRIORITY_MAXIMUM ; index++ )
81    _Chain_Initialize_empty( &_Thread_Ready_chain[ index ] );
82
83  _Thread_MP_Handler_initialization( maximum_proxies );
84
85  /*
86   *  Initialize this class of objects.
87   */
88 
89  _Objects_Initialize_information(
90    &_Thread_Internal_information,
91    OBJECTS_INTERNAL_THREADS,
92    FALSE,
93    ( _System_state_Is_multiprocessing ) ?  2 : 1,
94    sizeof( Thread_Control ),
95    TRUE,
96    8,
97    TRUE
98  );
99
100}
101
102/*PAGE
103 *
104 *  _Thread_Create_idle
105 */
106
107void _Thread_Create_idle( void )
108{
109  void *idle;
110
111  /*
112   *  The entire workspace is zeroed during its initialization.  Thus, all
113   *  fields not explicitly assigned were explicitly zeroed by
114   *  _Workspace_Initialization.
115   */
116 
117  _Thread_Idle = _Thread_Internal_allocate();
118 
119  /*
120   *  Initialize the IDLE task.
121   */
122 
123#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
124  idle = _CPU_Thread_Idle_body;
125#else
126  idle = _Thread_Idle_body;
127#endif
128 
129  if ( _CPU_Table.idle_task )
130    idle = _CPU_Table.idle_task;
131 
132  _Thread_Initialize(
133    &_Thread_Internal_information,
134    _Thread_Idle,
135    NULL,        /* allocate the stack */
136    THREAD_IDLE_STACK_SIZE,
137    CPU_IDLE_TASK_IS_FP,
138    PRIORITY_MAXIMUM,
139    TRUE,        /* preemptable */
140    FALSE,       /* not timesliced */
141    0,           /* all interrupts enabled */
142    _Thread_Idle_name
143  );
144 
145  /*
146   *  WARNING!!! This is necessary to "kick" start the system and
147   *             MUST be done before _Thread_Start is invoked.
148   */
149 
150  _Thread_Heir      =
151  _Thread_Executing = _Thread_Idle;
152 
153  _Thread_Start(
154    _Thread_Idle,
155    THREAD_START_NUMERIC,
156    idle,
157    NULL,
158    0
159  );
160 
161}
162
163/*PAGE
164 *
165 *  _Thread_Start_multitasking
166 *
167 *  This kernel routine readies the requested thread, the thread chain
168 *  is adjusted.  A new heir thread may be selected.
169 *
170 *  Input parameters:
171 *    system_thread - pointer to system initialization thread control block
172 *    idle_thread   - pointer to idle thread control block
173 *
174 *  Output parameters:  NONE
175 *
176 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
177 *         This insures the correct heir after a thread restart.
178 *
179 *  INTERRUPT LATENCY:
180 *    ready chain
181 *    select heir
182 */
183
184void _Thread_Start_multitasking( void )
185{
186  /*
187   *  The system is now multitasking and completely initialized. 
188   *  This system thread now either "goes away" in a single processor
189   *  system or "turns into" the server thread in an MP system.
190   */
191
192  _System_state_Set( SYSTEM_STATE_UP );
193
194  _Context_Switch_necessary = FALSE;
195
196  _Thread_Executing = _Thread_Heir;
197
198  _Context_Switch( &_Thread_BSP_context, &_Thread_Executing->Registers );
199}
200
201/*PAGE
202 *
203 *  _Thread_Dispatch
204 *
205 *  This kernel routine determines if a dispatch is needed, and if so
206 *  dispatches to the heir thread.  Once the heir is running an attempt
207 *  is made to dispatch any ASRs.
208 *
209 *  ALTERNATE ENTRY POINTS:
210 *    void _Thread_Enable_dispatch();
211 *
212 *  Input parameters:  NONE
213 *
214 *  Output parameters:  NONE
215 *
216 *  INTERRUPT LATENCY:
217 *    dispatch thread
218 *    no dispatch thread
219 */
220
221#if ( CPU_INLINE_ENABLE_DISPATCH == FALSE )
222void _Thread_Enable_dispatch( void )
223{
224  if ( --_Thread_Dispatch_disable_level )
225    return;
226  _Thread_Dispatch();
227}
228#endif
229
230void _Thread_Dispatch( void )
231{
232  Thread_Control   *executing;
233  Thread_Control   *heir;
234  ISR_Level         level;
235
236  executing   = _Thread_Executing;
237  _ISR_Disable( level );
238  while ( _Context_Switch_necessary == TRUE ) {
239    heir = _Thread_Heir;
240    _Thread_Dispatch_disable_level = 1;
241    _Context_Switch_necessary = FALSE;
242    _Thread_Executing = heir;
243    _ISR_Enable( level );
244
245    _User_extensions_Thread_switch( executing, heir );
246
247    _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
248
249    /*
250     *  If the CPU has hardware floating point, then we must address saving
251     *  and restoring it as part of the context switch.
252     *
253     *  The second conditional compilation section selects the algorithm used
254     *  to context switch between floating point tasks.  The deferred algorithm
255     *  can be significantly better in a system with few floating point tasks
256     *  because it reduces the total number of save and restore FP context
257     *  operations.  However, this algorithm can not be used on all CPUs due
258     *  to unpredictable use of FP registers by some compilers for integer
259     *  operations.
260     */
261
262#if ( CPU_HARDWARE_FP == TRUE )
263#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
264    if ( (heir->fp_context != NULL) && !_Thread_Is_allocated_fp( heir ) ) {
265      if ( _Thread_Allocated_fp != NULL )
266        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
267      _Context_Restore_fp( &heir->fp_context );
268      _Thread_Allocated_fp = heir;
269    }
270#else
271    if ( executing->fp_context != NULL )
272      _Context_Save_fp( &executing->fp_context );
273
274    if ( heir->fp_context != NULL )
275      _Context_Restore_fp( &heir->fp_context );
276#endif
277#endif
278
279    _Context_Switch( &executing->Registers, &heir->Registers );
280
281    executing = _Thread_Executing;
282
283    _ISR_Disable( level );
284  }
285
286  _Thread_Dispatch_disable_level = 0;
287
288  _ISR_Enable( level );
289
290  if ( executing->do_post_task_switch_extension ) {
291    executing->do_post_task_switch_extension = FALSE;
292    _API_extensions_Run_postswitch();
293  }
294 
295}
296
297/*PAGE
298 *
299 *  _Thread_Stack_Allocate
300 *
301 *  Allocate the requested stack space for the thread.
302 *  return the actual size allocated after any adjustment
303 *  or return zero if the allocation failed.
304 *  Set the Start.stack field to the address of the stack
305 */
306
307static unsigned32 _Thread_Stack_Allocate(
308  Thread_Control *the_thread,
309  unsigned32 stack_size)
310{
311  void *stack_addr = 0;
312 
313  if ( !_Stack_Is_enough( stack_size ) )
314    stack_size = STACK_MINIMUM_SIZE;
315 
316  /*
317   * Call ONLY the CPU table stack allocate hook, _or_ the
318   * the RTEMS workspace allocate.  This is so the stack free
319   * routine can call the correct deallocation routine.
320   */
321  if ( _CPU_Table.stack_allocate_hook )
322  {
323    stack_addr = (*_CPU_Table.stack_allocate_hook)( stack_size );
324  } else {
325    stack_size = _Stack_Adjust_size( stack_size );
326    stack_addr = _Workspace_Allocate( stack_size );
327  }
328 
329  if ( !stack_addr )
330      stack_size = 0;
331 
332  the_thread->Start.stack = stack_addr;
333 
334  return stack_size;
335}
336
337/*
338 *  _Thread_Stack_Free
339 *
340 *  Deallocate the Thread's stack.
341 */
342
343static void _Thread_Stack_Free(void *stack_addr)
344{
345    /*
346     * Call ONLY the CPU table stack free hook, or the
347     * the RTEMS workspace free.  This is so the free
348     * routine properly matches the allocation of the stack.
349     */
350    if ( _CPU_Table.stack_free_hook )
351        (*_CPU_Table.stack_free_hook)( stack_addr );
352    else
353        _Workspace_Free( stack_addr );
354}
355
356/*PAGE
357 *
358 *  _Thread_Initialize
359 *
360 *  XXX
361 */
362
363boolean _Thread_Initialize(
364  Objects_Information *information,
365  Thread_Control      *the_thread,
366  void                *stack_area,    /* NULL if to be allocated */
367  unsigned32           stack_size,    /* insure it is >= min */
368  boolean              is_fp,         /* TRUE if thread uses FP */
369  Priority_Control     priority,
370  boolean              is_preemptible,
371  boolean              is_timeslice,
372  unsigned32           isr_level,
373  Objects_Name         name
374 
375)
376{
377  unsigned32           actual_stack_size;
378  void                *stack;
379  void                *fp_area;
380  void                *extensions_area;
381
382  /*
383   *  Allocate and Initialize the stack for this thread.
384   */
385
386  if ( !_Stack_Is_enough( stack_size ) )
387    actual_stack_size = STACK_MINIMUM_SIZE;
388  else
389    actual_stack_size = stack_size;
390
391  actual_stack_size = _Stack_Adjust_size( actual_stack_size );
392  stack             = stack_area;
393
394  if ( !stack ) {
395    actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size );
396 
397    if ( !actual_stack_size )
398      return FALSE;                     /* stack allocation failed */
399
400    stack = the_thread->Start.stack;
401  } else
402    the_thread->Start.stack = NULL;
403
404  _Stack_Initialize(
405     &the_thread->Start.Initial_stack,
406     stack,
407     actual_stack_size
408  );
409
410  /*
411   *  Allocate the floating point area for this thread
412   */
413 
414  if ( is_fp ) {
415
416    fp_area = _Workspace_Allocate( CONTEXT_FP_SIZE );
417    if ( !fp_area ) {
418      if ( the_thread->Start.stack )
419        (void) _Thread_Stack_Free( the_thread->Start.stack );
420      return FALSE;
421    }
422    fp_area = _Context_Fp_start( fp_area, 0 );
423
424  } else
425    fp_area = NULL;
426
427  the_thread->fp_context       = fp_area;
428  the_thread->Start.fp_context = fp_area;
429 
430
431  /*
432   *  Allocate the extensions area for this thread
433   */
434
435  if ( _Thread_Maximum_extensions ) {
436    extensions_area = _Workspace_Allocate(
437      (_Thread_Maximum_extensions + 1) * sizeof( void * )
438    );
439
440    if ( !extensions_area ) {
441      if ( fp_area )
442        (void) _Workspace_Free( fp_area );
443
444      if ( the_thread->Start.stack )
445        (void) _Thread_Stack_Free( the_thread->Start.stack );
446
447      return FALSE;
448    }
449  } else
450    extensions_area = NULL;
451 
452  the_thread->extensions = extensions_area;
453
454  /*
455   *  General initialization
456   */
457
458  the_thread->Start.is_preemptible = is_preemptible;
459  the_thread->Start.is_timeslice   = is_timeslice;
460  the_thread->Start.isr_level      = isr_level;
461
462  the_thread->current_state          = STATES_DORMANT;
463  the_thread->resource_count         = 0;
464  the_thread->real_priority          = priority;
465  the_thread->Start.initial_priority = priority;
466 
467  _Thread_Set_priority( the_thread, priority );
468
469  /*
470   *  Open the object
471   */
472
473  _Objects_Open( information, &the_thread->Object, name );
474
475  /*
476   *  Invoke create extensions
477   */
478
479  if ( !_User_extensions_Thread_create( the_thread ) ) {
480
481    if ( extensions_area )
482      (void) _Workspace_Free( extensions_area );
483
484    if ( fp_area )
485      (void) _Workspace_Free( fp_area );
486
487    if ( the_thread->Start.stack )
488      (void) _Thread_Stack_Free( the_thread->Start.stack );
489
490    return FALSE;
491  }
492
493  return TRUE;
494   
495}
496
497/*
498 *  _Thread_Start
499 *
500 *  DESCRIPTION:
501 *
502 *  XXX
503 */
504 
505boolean _Thread_Start(
506  Thread_Control       *the_thread,
507  Thread_Start_types    the_prototype,
508  void                 *entry_point,
509  void                 *pointer_argument,
510  unsigned32            numeric_argument
511)
512{
513  if ( _States_Is_dormant( the_thread->current_state ) ) {
514 
515    the_thread->Start.entry_point      = entry_point;
516   
517    the_thread->Start.prototype        = the_prototype;
518    the_thread->Start.pointer_argument = pointer_argument;
519    the_thread->Start.numeric_argument = numeric_argument;
520 
521    _Thread_Load_environment( the_thread );
522 
523    _Thread_Ready( the_thread );
524 
525    _User_extensions_Thread_start( the_thread );
526 
527    return TRUE;
528  }
529 
530  return FALSE;
531 
532}
533
534/*
535 *  _Thread_Restart
536 *
537 *  DESCRIPTION:
538 *
539 *  XXX
540 */
541 
542boolean _Thread_Restart(
543  Thread_Control      *the_thread,
544  void                *pointer_argument,
545  unsigned32           numeric_argument
546)
547{
548  if ( !_States_Is_dormant( the_thread->current_state ) ) {
549 
550    _Thread_Set_transient( the_thread );
551    the_thread->resource_count = 0;
552    the_thread->is_preemptible = the_thread->Start.is_preemptible;
553    the_thread->is_timeslice   = the_thread->Start.is_timeslice;
554
555    the_thread->Start.pointer_argument = pointer_argument;
556    the_thread->Start.numeric_argument = numeric_argument;
557 
558    if ( !_Thread_queue_Extract_with_proxy( the_thread ) ) {
559 
560      if ( _Watchdog_Is_active( &the_thread->Timer ) )
561        (void) _Watchdog_Remove( &the_thread->Timer );
562    }
563
564    if ( the_thread->current_priority != the_thread->Start.initial_priority ) {
565      the_thread->real_priority = the_thread->Start.initial_priority;
566      _Thread_Set_priority( the_thread, the_thread->Start.initial_priority );
567    }
568 
569    _Thread_Load_environment( the_thread );
570 
571    _Thread_Ready( the_thread );
572 
573    _User_extensions_Thread_restart( the_thread );
574 
575    if ( _Thread_Is_executing ( the_thread ) )
576      _Thread_Restart_self();
577 
578    return TRUE;
579  }
580 
581  return FALSE;
582}
583
584/*
585 *  _Thread_Close
586 *
587 *  DESCRIPTION:
588 *
589 *  XXX
590 */
591 
592void _Thread_Close(
593  Objects_Information  *information,
594  Thread_Control       *the_thread
595)
596{
597  _Objects_Close( information, &the_thread->Object );
598 
599  _Thread_Set_state( the_thread, STATES_TRANSIENT );
600 
601  if ( !_Thread_queue_Extract_with_proxy( the_thread ) ) {
602 
603    if ( _Watchdog_Is_active( &the_thread->Timer ) )
604      (void) _Watchdog_Remove( &the_thread->Timer );
605  }
606
607  _User_extensions_Thread_delete( the_thread );
608 
609#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
610  if ( _Thread_Is_allocated_fp( the_thread ) )
611    _Thread_Deallocate_fp();
612#endif
613  the_thread->fp_context = NULL;
614
615  if ( the_thread->Start.fp_context )
616  (void) _Workspace_Free( the_thread->Start.fp_context );
617
618  if ( the_thread->Start.stack )
619    (void) _Workspace_Free( the_thread->Start.stack );
620
621  if ( the_thread->extensions )
622    (void) _Workspace_Free( the_thread->extensions );
623
624  the_thread->Start.stack = NULL;
625  the_thread->extensions = NULL;
626}
627
628/*PAGE
629 *
630 *  _Thread_Ready
631 *
632 *  This kernel routine readies the requested thread, the thread chain
633 *  is adjusted.  A new heir thread may be selected.
634 *
635 *  Input parameters:
636 *    the_thread - pointer to thread control block
637 *
638 *  Output parameters:  NONE
639 *
640 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
641 *         This insures the correct heir after a thread restart.
642 *
643 *  INTERRUPT LATENCY:
644 *    ready chain
645 *    select heir
646 */
647
648void _Thread_Ready(
649  Thread_Control *the_thread
650)
651{
652  ISR_Level              level;
653  Thread_Control *heir;
654
655  _ISR_Disable( level );
656
657  the_thread->current_state = STATES_READY;
658
659  _Priority_Add_to_bit_map( &the_thread->Priority_map );
660
661  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
662
663  _ISR_Flash( level );
664
665  _Thread_Calculate_heir();
666
667  heir = _Thread_Heir;
668
669  if ( !_Thread_Is_executing( heir ) && _Thread_Executing->is_preemptible )
670    _Context_Switch_necessary = TRUE;
671
672  _ISR_Enable( level );
673}
674
675/*PAGE
676 *
677 *  _Thread_Clear_state
678 *
679 *  This kernel routine clears the appropriate states in the
680 *  requested thread.  The thread ready chain is adjusted if
681 *  necessary and the Heir thread is set accordingly.
682 *
683 *  Input parameters:
684 *    the_thread - pointer to thread control block
685 *    state      - state set to clear
686 *
687 *  Output parameters:  NONE
688 *
689 *  INTERRUPT LATENCY:
690 *    priority map
691 *    select heir
692 */
693
694void _Thread_Clear_state(
695  Thread_Control *the_thread,
696  States_Control  state
697)
698{
699  ISR_Level level;
700
701  _ISR_Disable( level );
702    the_thread->current_state =
703      _States_Clear( state, the_thread->current_state );
704
705    if ( _States_Is_ready( the_thread->current_state ) ) {
706
707      _Priority_Add_to_bit_map( &the_thread->Priority_map );
708
709      _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
710
711      _ISR_Flash( level );
712
713      if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
714        _Thread_Heir = the_thread;
715        if ( _Thread_Executing->is_preemptible ||
716             the_thread->current_priority == 0 )
717          _Context_Switch_necessary = TRUE;
718      }
719    }
720  _ISR_Enable( level );
721}
722
723/*PAGE
724 *
725 * _Thread_Set_state
726 *
727 * This kernel routine sets the requested state in the THREAD.  The
728 * THREAD chain is adjusted if necessary.
729 *
730 * Input parameters:
731 *   the_thread   - pointer to thread control block
732 *   state - state to be set
733 *
734 * Output parameters:  NONE
735 *
736 *  INTERRUPT LATENCY:
737 *    ready chain
738 *    select map
739 */
740
741void _Thread_Set_state(
742  Thread_Control *the_thread,
743  States_Control         state
744)
745{
746  ISR_Level             level;
747  Chain_Control *ready;
748
749  ready = the_thread->ready;
750  _ISR_Disable( level );
751  if ( !_States_Is_ready( the_thread->current_state ) ) {
752    the_thread->current_state =
753       _States_Set( state, the_thread->current_state );
754    _ISR_Enable( level );
755    return;
756  }
757
758  the_thread->current_state = state;
759
760  if ( _Chain_Has_only_one_node( ready ) ) {
761
762    _Chain_Initialize_empty( ready );
763    _Priority_Remove_from_bit_map( &the_thread->Priority_map );
764
765  } else
766    _Chain_Extract_unprotected( &the_thread->Object.Node );
767
768  _ISR_Flash( level );
769
770  if ( _Thread_Is_heir( the_thread ) )
771     _Thread_Calculate_heir();
772
773  if ( _Thread_Is_executing( the_thread ) )
774    _Context_Switch_necessary = TRUE;
775
776  _ISR_Enable( level );
777}
778
779/*PAGE
780 *
781 *  _Thread_Set_transient
782 *
783 *  This kernel routine places the requested thread in the transient state
784 *  which will remove it from the ready queue, if necessary.  No
785 *  rescheduling is necessary because it is assumed that the transient
786 *  state will be cleared before dispatching is enabled.
787 *
788 *  Input parameters:
789 *    the_thread - pointer to thread control block
790 *
791 *  Output parameters:  NONE
792 *
793 *  INTERRUPT LATENCY:
794 *    only case
795 */
796
797void _Thread_Set_transient(
798  Thread_Control *the_thread
799)
800{
801  ISR_Level             level;
802  unsigned32            old_state;
803  Chain_Control *ready;
804
805  ready = the_thread->ready;
806  _ISR_Disable( level );
807
808  old_state = the_thread->current_state;
809  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );
810
811  if ( _States_Is_ready( old_state ) ) {
812    if ( _Chain_Has_only_one_node( ready ) ) {
813
814      _Chain_Initialize_empty( ready );
815      _Priority_Remove_from_bit_map( &the_thread->Priority_map );
816
817    } else
818      _Chain_Extract_unprotected( &the_thread->Object.Node );
819  }
820
821  _ISR_Enable( level );
822
823}
824
825/*PAGE
826 *
827 *  _Thread_Reset_timeslice
828 *
829 *  This routine will remove the running thread from the ready chain
830 *  and place it immediately at the rear of this chain and then the
831 *  timeslice counter is reset.  The heir THREAD will be updated if
832 *  the running is also the currently the heir.
833 *
834 *  Input parameters:   NONE
835 *
836 *  Output parameters:  NONE
837 *
838 *  INTERRUPT LATENCY:
839 *    ready chain
840 *    select heir
841 */
842
843void _Thread_Reset_timeslice( void )
844{
845  ISR_Level              level;
846  Thread_Control *executing;
847  Chain_Control  *ready;
848
849  executing = _Thread_Executing;
850  ready     = executing->ready;
851  _ISR_Disable( level );
852    if ( _Chain_Has_only_one_node( ready ) ) {
853      _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
854      _ISR_Enable( level );
855      return;
856    }
857    _Chain_Extract_unprotected( &executing->Object.Node );
858    _Chain_Append_unprotected( ready, &executing->Object.Node );
859
860  _ISR_Flash( level );
861
862    if ( _Thread_Is_heir( executing ) )
863      _Thread_Heir = (Thread_Control *) ready->first;
864
865    _Context_Switch_necessary = TRUE;
866
867  _ISR_Enable( level );
868}
869
870/*PAGE
871 *
872 *  _Thread_Tickle_timeslice
873 *
874 *  This scheduler routine determines if timeslicing is enabled
875 *  for the currently executing thread and, if so, updates the
876 *  timeslice count and checks for timeslice expiration.
877 *
878 *  Input parameters:   NONE
879 *
880 *  Output parameters:  NONE
881 */
882
883void _Thread_Tickle_timeslice( void )
884{
885  if ( !_Thread_Executing->is_timeslice  ||
886       !_Thread_Executing->is_preemptible ||
887       !_States_Is_ready( _Thread_Executing->current_state ) )
888    return;
889
890  if ( --_Thread_Ticks_remaining_in_timeslice == 0 ) {
891      _Thread_Reset_timeslice();
892  }
893}
894
895/*PAGE
896 *
897 *  _Thread_Yield_processor
898 *
899 *  This kernel routine will remove the running THREAD from the ready chain
900 *  and place it immediatly at the rear of this chain.  Reset timeslice
901 *  and yield the processor functions both use this routine, therefore if
902 *  reset is TRUE and this is the only thread on the chain then the
903 *  timeslice counter is reset.  The heir THREAD will be updated if the
904 *  running is also the currently the heir.
905 *
906 *  Input parameters:   NONE
907 *
908 *  Output parameters:  NONE
909 *
910 *  INTERRUPT LATENCY:
911 *    ready chain
912 *    select heir
913 */
914
915void _Thread_Yield_processor( void )
916{
917  ISR_Level       level;
918  Thread_Control *executing;
919  Chain_Control  *ready;
920
921  executing = _Thread_Executing;
922  ready     = executing->ready;
923  _ISR_Disable( level );
924    if ( !_Chain_Has_only_one_node( ready ) ) {
925      _Chain_Extract_unprotected( &executing->Object.Node );
926      _Chain_Append_unprotected( ready, &executing->Object.Node );
927
928      _ISR_Flash( level );
929
930      if ( _Thread_Is_heir( executing ) )
931        _Thread_Heir = (Thread_Control *) ready->first;
932      _Context_Switch_necessary = TRUE;
933    }
934    else if ( !_Thread_Is_heir( executing ) )
935      _Context_Switch_necessary = TRUE;
936
937  _ISR_Enable( level );
938}
939
940/*PAGE
941 *
942 *  _Thread_Load_environment
943 *
944 *  Load starting environment for another thread from its start area in the
945 *  thread.  Only called from t_restart and t_start.
946 *
947 *  Input parameters:
948 *    the_thread - thread control block pointer
949 *
950 *  Output parameters:  NONE
951 */
952
953void _Thread_Load_environment(
954  Thread_Control *the_thread
955)
956{
957  boolean is_fp = FALSE;
958
959  if ( the_thread->Start.fp_context ) {
960    the_thread->fp_context = the_thread->Start.fp_context;
961    _Context_Initialize_fp( &the_thread->fp_context );
962    is_fp = TRUE;
963  }
964
965  the_thread->do_post_task_switch_extension = FALSE;
966  the_thread->is_preemptible = the_thread->Start.is_preemptible;
967  the_thread->is_timeslice   = the_thread->Start.is_timeslice;
968
969  _Context_Initialize(
970    &the_thread->Registers,
971    the_thread->Start.Initial_stack.area,
972    the_thread->Start.Initial_stack.size,
973    the_thread->Start.isr_level,
974    _Thread_Handler,
975    is_fp
976  );
977
978}
979
980/*PAGE
981 *
982 *  _Thread_Handler
983 *
984 *  This routine is the default thread exitted error handler.  It is
985 *  returned to when a thread exits.  The configured fatal error handler
986 *  is invoked to process the exit.
987 *
988 *  Input parameters:   NONE
989 *
990 *  Output parameters:  NONE
991 */
992
993void _Thread_Handler( void )
994{
995  Thread_Control *executing;
996
997  executing = _Thread_Executing;
998
999  /*
1000   * Take care that 'begin' extensions get to complete before
1001   * 'switch' extensions can run.  This means must keep dispatch
1002   * disabled until all 'begin' extensions complete.
1003   */
1004 
1005  _User_extensions_Thread_begin( executing );
1006 
1007  /*
1008   *  At this point, the dispatch disable level BETTER be 1.
1009   */
1010
1011  _Thread_Enable_dispatch();
1012 
1013  switch ( executing->Start.prototype ) {
1014    case THREAD_START_NUMERIC:
1015      (*executing->Start.entry_point)( executing->Start.numeric_argument );
1016      break;
1017    case THREAD_START_POINTER:
1018      (*executing->Start.entry_point)( executing->Start.pointer_argument );
1019      break;
1020    case THREAD_START_BOTH_POINTER_FIRST:
1021      (*executing->Start.entry_point)(
1022        executing->Start.pointer_argument,
1023        executing->Start.numeric_argument
1024      );
1025      break;
1026    case THREAD_START_BOTH_NUMERIC_FIRST:
1027      (*executing->Start.entry_point)(
1028        executing->Start.numeric_argument,
1029        executing->Start.pointer_argument
1030      );
1031      break;
1032  }
1033
1034  _User_extensions_Thread_exitted( executing );
1035
1036  _Internal_error_Occurred(
1037    INTERNAL_ERROR_CORE,
1038    TRUE,
1039    INTERNAL_ERROR_THREAD_EXITTED
1040  );
1041}
1042
1043/*PAGE
1044 *
1045 *  _Thread_Delay_ended
1046 *
1047 *  This routine processes a thread whose delay period has ended.
1048 *  It is called by the watchdog handler.
1049 *
1050 *  Input parameters:
1051 *    id - thread id
1052 *
1053 *  Output parameters: NONE
1054 */
1055
1056void _Thread_Delay_ended(
1057  Objects_Id  id,
1058  void       *ignored
1059)
1060{
1061  Thread_Control    *the_thread;
1062  Objects_Locations  location;
1063
1064  the_thread = _Thread_Get( id, &location );
1065  switch ( location ) {
1066    case OBJECTS_ERROR:
1067    case OBJECTS_REMOTE:  /* impossible */
1068      break;
1069    case OBJECTS_LOCAL:
1070      _Thread_Unblock( the_thread );
1071      _Thread_Unnest_dispatch();
1072      break;
1073  }
1074}
1075
1076/*PAGE
1077 *
1078 *  _Thread_Change_priority
1079 *
1080 *  This kernel routine changes the priority of the thread.  The
1081 *  thread chain is adjusted if necessary.
1082 *
1083 *  Input parameters:
1084 *    the_thread   - pointer to thread control block
1085 *    new_priority - ultimate priority
1086 *
1087 *  Output parameters:  NONE
1088 *
1089 *  INTERRUPT LATENCY:
1090 *    ready chain
1091 *    select heir
1092 */
1093
1094void _Thread_Change_priority(
1095  Thread_Control   *the_thread,
1096  Priority_Control  new_priority
1097)
1098{
1099  ISR_Level level;
1100
1101  _Thread_Set_transient( the_thread );
1102
1103  if ( the_thread->current_priority != new_priority )
1104    _Thread_Set_priority( the_thread, new_priority );
1105
1106  _ISR_Disable( level );
1107
1108  the_thread->current_state =
1109    _States_Clear( STATES_TRANSIENT, the_thread->current_state );
1110
1111  if ( ! _States_Is_ready( the_thread->current_state ) ) {
1112    _ISR_Enable( level );
1113    return;
1114  }
1115
1116  _Priority_Add_to_bit_map( &the_thread->Priority_map );
1117  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
1118
1119  _ISR_Flash( level );
1120
1121  _Thread_Calculate_heir();
1122
1123  if ( !_Thread_Is_executing_also_the_heir() &&
1124       _Thread_Executing->is_preemptible )
1125    _Context_Switch_necessary = TRUE;
1126
1127  _ISR_Enable( level );
1128}
1129
1130/*PAGE
1131 *
1132 * _Thread_Set_priority
1133 *
1134 * This directive enables and disables several modes of
1135 * execution for the requesting thread.
1136 *
1137 *  Input parameters:
1138 *    the_thread   - pointer to thread priority
1139 *    new_priority - new priority
1140 *
1141 *  Output: NONE
1142 */
1143
1144void _Thread_Set_priority(
1145  Thread_Control   *the_thread,
1146  Priority_Control  new_priority
1147)
1148{
1149  the_thread->current_priority = new_priority;
1150  the_thread->ready            = &_Thread_Ready_chain[ new_priority ];
1151
1152  _Priority_Initialize_information( &the_thread->Priority_map, new_priority );
1153}
1154
1155/*PAGE
1156 *
1157 *  _Thread_Evaluate_mode
1158 *
1159 *  XXX
1160 */
1161
1162boolean _Thread_Evaluate_mode( void )
1163{
1164  Thread_Control     *executing;
1165
1166  executing = _Thread_Executing;
1167
1168  if ( !_States_Is_ready( executing->current_state ) ||
1169       ( !_Thread_Is_heir( executing ) && executing->is_preemptible ) ) {
1170    _Context_Switch_necessary = TRUE;
1171    return TRUE;
1172  }
1173
1174  return FALSE;
1175}
1176
1177/*PAGE
1178 *
1179 *  _Thread_Get
1180 *
1181 *  NOTE:  If we are not using static inlines, this must be a real
1182 *         subroutine call.
1183 *
1184 *  NOTE:  XXX... This routine may be able to be optimized.
1185 */
1186
1187#ifndef USE_INLINES
1188
1189Thread_Control *_Thread_Get (
1190  Objects_Id           id,
1191  Objects_Locations   *location
1192)
1193{
1194  Objects_Classes      the_class;
1195  Objects_Information *information;
1196 
1197  if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) {
1198    _Thread_Disable_dispatch();
1199    *location = OBJECTS_LOCAL;
1200    return( _Thread_Executing );
1201  }
1202 
1203  the_class = _Objects_Get_class( id );
1204 
1205  if ( the_class > OBJECTS_CLASSES_LAST ) {
1206    *location = OBJECTS_ERROR;
1207    return (Thread_Control *) 0;
1208  }
1209 
1210  information = _Objects_Information_table[ the_class ];
1211 
1212  if ( !information || !information->is_thread ) {
1213    *location = OBJECTS_ERROR;
1214    return (Thread_Control *) 0;
1215  }
1216 
1217  return (Thread_Control *) _Objects_Get( information, id, location );
1218}
1219
1220#endif
1221
1222/*PAGE
1223 *
1224 *  _Thread_Idle_body
1225 *
1226 *  This kernel routine is the idle thread.  The idle thread runs any time
1227 *  no other thread is ready to run.  This thread loops forever with
1228 *  interrupts enabled.
1229 *
1230 *  Input parameters:
1231 *    ignored - this parameter is ignored
1232 *
1233 *  Output parameters:  NONE
1234 */
1235 
1236#if (CPU_PROVIDES_IDLE_THREAD_BODY == FALSE)
1237Thread _Thread_Idle_body(
1238  unsigned32 ignored
1239)
1240{
1241  for( ; ; ) ;
1242}
1243#endif
Note: See TracBrowser for help on using the repository browser.