source: rtems/cpukit/score/src/thread.c @ 7aa4671

4.104.114.84.95
Last change on this file since 7aa4671 was 7aa4671, checked in by Joel Sherrill <joel.sherrill@…>, on 06/05/96 at 21:12:06

added cpu_time_budget field to Thread_Control and removed the global variable
_Thread_Ticks_remaining_in_timeslice.

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