source: rtems/cpukit/score/src/thread.c @ 27f0d424

4.104.114.84.95
Last change on this file since 27f0d424 was 27f0d424, checked in by Joel Sherrill <joel.sherrill@…>, on 10/15/96 at 21:38:43

added support for cpu time used field in tcb

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