source: rtems/c/src/exec/score/src/thread.c @ 0600e86f

4.104.114.84.95
Last change on this file since 0600e86f was 0600e86f, checked in by Joel Sherrill <joel.sherrill@…>, on 08/15/96 at 21:05:21

_Thread_Start_multitasking: added code to initialize the floating point
context of the first thread to execute.

  • Property mode set to 100644
File size: 31.6 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 
522  _Thread_Set_priority( the_thread, priority );
523
524  /*
525   *  Open the object
526   */
527
528  _Objects_Open( information, &the_thread->Object, name );
529
530  /*
531   *  Invoke create extensions
532   */
533
534  if ( !_User_extensions_Thread_create( the_thread ) ) {
535
536    if ( extensions_area )
537      (void) _Workspace_Free( extensions_area );
538
539    if ( fp_area )
540      (void) _Workspace_Free( fp_area );
541
542    _Thread_Stack_Free( the_thread->Start.stack );
543
544    return FALSE;
545  }
546
547  return TRUE;
548   
549}
550
551/*
552 *  _Thread_Start
553 *
554 *  DESCRIPTION:
555 *
556 *  XXX
557 */
558 
559boolean _Thread_Start(
560  Thread_Control       *the_thread,
561  Thread_Start_types    the_prototype,
562  void                 *entry_point,
563  void                 *pointer_argument,
564  unsigned32            numeric_argument
565)
566{
567  if ( _States_Is_dormant( the_thread->current_state ) ) {
568 
569    the_thread->Start.entry_point      = entry_point;
570   
571    the_thread->Start.prototype        = the_prototype;
572    the_thread->Start.pointer_argument = pointer_argument;
573    the_thread->Start.numeric_argument = numeric_argument;
574 
575    _Thread_Load_environment( the_thread );
576 
577    _Thread_Ready( the_thread );
578 
579    _User_extensions_Thread_start( the_thread );
580 
581    return TRUE;
582  }
583 
584  return FALSE;
585 
586}
587
588/*
589 *  _Thread_Restart
590 *
591 *  DESCRIPTION:
592 *
593 *  XXX
594 */
595 
596boolean _Thread_Restart(
597  Thread_Control      *the_thread,
598  void                *pointer_argument,
599  unsigned32           numeric_argument
600)
601{
602  if ( !_States_Is_dormant( the_thread->current_state ) ) {
603 
604    _Thread_Set_transient( the_thread );
605    the_thread->resource_count = 0;
606    the_thread->is_preemptible   = the_thread->Start.is_preemptible;
607    the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
608    the_thread->budget_callout   = the_thread->Start.budget_callout;
609
610    the_thread->Start.pointer_argument = pointer_argument;
611    the_thread->Start.numeric_argument = numeric_argument;
612 
613    if ( !_Thread_queue_Extract_with_proxy( the_thread ) ) {
614 
615      if ( _Watchdog_Is_active( &the_thread->Timer ) )
616        (void) _Watchdog_Remove( &the_thread->Timer );
617    }
618
619    if ( the_thread->current_priority != the_thread->Start.initial_priority ) {
620      the_thread->real_priority = the_thread->Start.initial_priority;
621      _Thread_Set_priority( the_thread, the_thread->Start.initial_priority );
622    }
623 
624    _Thread_Load_environment( the_thread );
625 
626    _Thread_Ready( the_thread );
627 
628    _User_extensions_Thread_restart( the_thread );
629 
630    if ( _Thread_Is_executing ( the_thread ) )
631      _Thread_Restart_self();
632 
633    return TRUE;
634  }
635 
636  return FALSE;
637}
638
639/*
640 *  _Thread_Close
641 *
642 *  DESCRIPTION:
643 *
644 *  XXX
645 */
646 
647void _Thread_Close(
648  Objects_Information  *information,
649  Thread_Control       *the_thread
650)
651{
652  _Objects_Close( information, &the_thread->Object );
653 
654  _Thread_Set_state( the_thread, STATES_TRANSIENT );
655 
656  if ( !_Thread_queue_Extract_with_proxy( the_thread ) ) {
657 
658    if ( _Watchdog_Is_active( &the_thread->Timer ) )
659      (void) _Watchdog_Remove( &the_thread->Timer );
660  }
661
662  _User_extensions_Thread_delete( the_thread );
663 
664#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
665  if ( _Thread_Is_allocated_fp( the_thread ) )
666    _Thread_Deallocate_fp();
667#endif
668  the_thread->fp_context = NULL;
669
670  if ( the_thread->Start.fp_context )
671  (void) _Workspace_Free( the_thread->Start.fp_context );
672
673  _Thread_Stack_Free( the_thread );
674
675  if ( the_thread->extensions )
676    (void) _Workspace_Free( the_thread->extensions );
677
678  the_thread->Start.stack = NULL;
679  the_thread->extensions = NULL;
680}
681
682/*PAGE
683 *
684 *  _Thread_Ready
685 *
686 *  This kernel routine readies the requested thread, the thread chain
687 *  is adjusted.  A new heir thread may be selected.
688 *
689 *  Input parameters:
690 *    the_thread - pointer to thread control block
691 *
692 *  Output parameters:  NONE
693 *
694 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
695 *         This insures the correct heir after a thread restart.
696 *
697 *  INTERRUPT LATENCY:
698 *    ready chain
699 *    select heir
700 */
701
702void _Thread_Ready(
703  Thread_Control *the_thread
704)
705{
706  ISR_Level              level;
707  Thread_Control *heir;
708
709  _ISR_Disable( level );
710
711  the_thread->current_state = STATES_READY;
712
713  _Priority_Add_to_bit_map( &the_thread->Priority_map );
714
715  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
716
717  _ISR_Flash( level );
718
719  _Thread_Calculate_heir();
720
721  heir = _Thread_Heir;
722
723  if ( !_Thread_Is_executing( heir ) && _Thread_Executing->is_preemptible )
724    _Context_Switch_necessary = TRUE;
725
726  _ISR_Enable( level );
727}
728
729/*PAGE
730 *
731 *  _Thread_Clear_state
732 *
733 *  This kernel routine clears the appropriate states in the
734 *  requested thread.  The thread ready chain is adjusted if
735 *  necessary and the Heir thread is set accordingly.
736 *
737 *  Input parameters:
738 *    the_thread - pointer to thread control block
739 *    state      - state set to clear
740 *
741 *  Output parameters:  NONE
742 *
743 *  INTERRUPT LATENCY:
744 *    priority map
745 *    select heir
746 */
747
748
749void _Thread_Clear_state(
750  Thread_Control *the_thread,
751  States_Control  state
752)
753{
754  ISR_Level       level;
755  States_Control  current_state;
756
757  _ISR_Disable( level );
758    current_state = the_thread->current_state;
759   
760    if ( current_state & state ) {
761      current_state =
762      the_thread->current_state = _States_Clear( state, current_state );
763
764      if ( _States_Is_ready( current_state ) ) {
765
766        _Priority_Add_to_bit_map( &the_thread->Priority_map );
767
768        _Chain_Append_unprotected(the_thread->ready, &the_thread->Object.Node);
769
770        _ISR_Flash( level );
771
772        if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
773          _Thread_Heir = the_thread;
774          if ( _Thread_Executing->is_preemptible ||
775               the_thread->current_priority == 0 )
776            _Context_Switch_necessary = TRUE;
777        }
778      }
779  }
780  _ISR_Enable( level );
781}
782
783/*PAGE
784 *
785 * _Thread_Set_state
786 *
787 * This kernel routine sets the requested state in the THREAD.  The
788 * THREAD chain is adjusted if necessary.
789 *
790 * Input parameters:
791 *   the_thread   - pointer to thread control block
792 *   state - state to be set
793 *
794 * Output parameters:  NONE
795 *
796 *  INTERRUPT LATENCY:
797 *    ready chain
798 *    select map
799 */
800
801void _Thread_Set_state(
802  Thread_Control *the_thread,
803  States_Control         state
804)
805{
806  ISR_Level             level;
807  Chain_Control *ready;
808
809  ready = the_thread->ready;
810  _ISR_Disable( level );
811  if ( !_States_Is_ready( the_thread->current_state ) ) {
812    the_thread->current_state =
813       _States_Set( state, the_thread->current_state );
814    _ISR_Enable( level );
815    return;
816  }
817
818  the_thread->current_state = state;
819
820  if ( _Chain_Has_only_one_node( ready ) ) {
821
822    _Chain_Initialize_empty( ready );
823    _Priority_Remove_from_bit_map( &the_thread->Priority_map );
824
825  } else
826    _Chain_Extract_unprotected( &the_thread->Object.Node );
827
828  _ISR_Flash( level );
829
830  if ( _Thread_Is_heir( the_thread ) )
831     _Thread_Calculate_heir();
832
833  if ( _Thread_Is_executing( the_thread ) )
834    _Context_Switch_necessary = TRUE;
835
836  _ISR_Enable( level );
837}
838
839/*PAGE
840 *
841 *  _Thread_Set_transient
842 *
843 *  This kernel routine places the requested thread in the transient state
844 *  which will remove it from the ready queue, if necessary.  No
845 *  rescheduling is necessary because it is assumed that the transient
846 *  state will be cleared before dispatching is enabled.
847 *
848 *  Input parameters:
849 *    the_thread - pointer to thread control block
850 *
851 *  Output parameters:  NONE
852 *
853 *  INTERRUPT LATENCY:
854 *    only case
855 */
856
857void _Thread_Set_transient(
858  Thread_Control *the_thread
859)
860{
861  ISR_Level             level;
862  unsigned32            old_state;
863  Chain_Control *ready;
864
865  ready = the_thread->ready;
866  _ISR_Disable( level );
867
868  old_state = the_thread->current_state;
869  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );
870
871  if ( _States_Is_ready( old_state ) ) {
872    if ( _Chain_Has_only_one_node( ready ) ) {
873
874      _Chain_Initialize_empty( ready );
875      _Priority_Remove_from_bit_map( &the_thread->Priority_map );
876
877    } else
878      _Chain_Extract_unprotected( &the_thread->Object.Node );
879  }
880
881  _ISR_Enable( level );
882
883}
884
885/*PAGE
886 *
887 *  _Thread_Reset_timeslice
888 *
889 *  This routine will remove the running thread from the ready chain
890 *  and place it immediately at the rear of this chain and then the
891 *  timeslice counter is reset.  The heir THREAD will be updated if
892 *  the running is also the currently the heir.
893 *
894 *  Input parameters:   NONE
895 *
896 *  Output parameters:  NONE
897 *
898 *  INTERRUPT LATENCY:
899 *    ready chain
900 *    select heir
901 */
902
903void _Thread_Reset_timeslice( void )
904{
905  ISR_Level       level;
906  Thread_Control *executing;
907  Chain_Control  *ready;
908
909  executing = _Thread_Executing;
910  ready     = executing->ready;
911  _ISR_Disable( level );
912    if ( _Chain_Has_only_one_node( ready ) ) {
913      _ISR_Enable( level );
914      return;
915    }
916    _Chain_Extract_unprotected( &executing->Object.Node );
917    _Chain_Append_unprotected( ready, &executing->Object.Node );
918
919  _ISR_Flash( level );
920
921    if ( _Thread_Is_heir( executing ) )
922      _Thread_Heir = (Thread_Control *) ready->first;
923
924    _Context_Switch_necessary = TRUE;
925
926  _ISR_Enable( level );
927}
928
929/*PAGE
930 *
931 *  _Thread_Tickle_timeslice
932 *
933 *  This scheduler routine determines if timeslicing is enabled
934 *  for the currently executing thread and, if so, updates the
935 *  timeslice count and checks for timeslice expiration.
936 *
937 *  Input parameters:   NONE
938 *
939 *  Output parameters:  NONE
940 */
941
942void _Thread_Tickle_timeslice( void )
943{
944  Thread_Control *executing;
945
946  executing = _Thread_Executing;
947
948  if ( !executing->is_preemptible )
949    return;
950
951  if ( !_States_Is_ready( executing->current_state ) )
952    return;
953
954  switch ( executing->budget_algorithm ) {
955    case THREAD_CPU_BUDGET_ALGORITHM_NONE:
956      break;
957
958    case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
959    case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE:
960      if ( --executing->cpu_time_budget == 0 ) {
961        _Thread_Reset_timeslice();
962        executing->cpu_time_budget = _Thread_Ticks_per_timeslice;
963      }
964      break;
965
966    case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT:
967      if ( --executing->cpu_time_budget == 0 )
968        (*executing->budget_callout)( executing );
969      break;
970  }
971}
972
973/*PAGE
974 *
975 *  _Thread_Yield_processor
976 *
977 *  This kernel routine will remove the running THREAD from the ready chain
978 *  and place it immediatly at the rear of this chain.  Reset timeslice
979 *  and yield the processor functions both use this routine, therefore if
980 *  reset is TRUE and this is the only thread on the chain then the
981 *  timeslice counter is reset.  The heir THREAD will be updated if the
982 *  running is also the currently the heir.
983 *
984 *  Input parameters:   NONE
985 *
986 *  Output parameters:  NONE
987 *
988 *  INTERRUPT LATENCY:
989 *    ready chain
990 *    select heir
991 */
992
993void _Thread_Yield_processor( void )
994{
995  ISR_Level       level;
996  Thread_Control *executing;
997  Chain_Control  *ready;
998
999  executing = _Thread_Executing;
1000  ready     = executing->ready;
1001  _ISR_Disable( level );
1002    if ( !_Chain_Has_only_one_node( ready ) ) {
1003      _Chain_Extract_unprotected( &executing->Object.Node );
1004      _Chain_Append_unprotected( ready, &executing->Object.Node );
1005
1006      _ISR_Flash( level );
1007
1008      if ( _Thread_Is_heir( executing ) )
1009        _Thread_Heir = (Thread_Control *) ready->first;
1010      _Context_Switch_necessary = TRUE;
1011    }
1012    else if ( !_Thread_Is_heir( executing ) )
1013      _Context_Switch_necessary = TRUE;
1014
1015  _ISR_Enable( level );
1016}
1017
1018/*PAGE
1019 *
1020 *  _Thread_Load_environment
1021 *
1022 *  Load starting environment for another thread from its start area in the
1023 *  thread.  Only called from t_restart and t_start.
1024 *
1025 *  Input parameters:
1026 *    the_thread - thread control block pointer
1027 *
1028 *  Output parameters:  NONE
1029 */
1030
1031void _Thread_Load_environment(
1032  Thread_Control *the_thread
1033)
1034{
1035  boolean is_fp = FALSE;
1036
1037  if ( the_thread->Start.fp_context ) {
1038    the_thread->fp_context = the_thread->Start.fp_context;
1039    _Context_Initialize_fp( &the_thread->fp_context );
1040    is_fp = TRUE;
1041  }
1042
1043  the_thread->do_post_task_switch_extension = FALSE;
1044  the_thread->is_preemptible   = the_thread->Start.is_preemptible;
1045  the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
1046  the_thread->budget_callout   = the_thread->Start.budget_callout;
1047
1048  _Context_Initialize(
1049    &the_thread->Registers,
1050    the_thread->Start.Initial_stack.area,
1051    the_thread->Start.Initial_stack.size,
1052    the_thread->Start.isr_level,
1053    _Thread_Handler,
1054    is_fp
1055  );
1056
1057}
1058
1059/*PAGE
1060 *
1061 *  _Thread_Handler
1062 *
1063 *  This routine is the "primal" entry point for all threads.
1064 *  _Context_Initialize() dummies up the thread's initial context
1065 *  to cause the first Context_Switch() to jump to _Thread_Handler().
1066 *
1067 *  This routine is the default thread exitted error handler.  It is
1068 *  returned to when a thread exits.  The configured fatal error handler
1069 *  is invoked to process the exit.
1070 *
1071 *  NOTE:
1072 *
1073 *  On entry, it is assumed all interrupts are blocked and that this
1074 *  routine needs to set the initial isr level.  This may or may not
1075 *  actually be needed by the context switch routine and as a result
1076 *  interrupts may already be at there proper level.  Either way,
1077 *  setting the initial isr level properly here is safe.
1078 * 
1079 *  Currently this is only really needed for the posix port,
1080 *  ref: _Context_Switch in unix/cpu.c
1081 *
1082 *  Input parameters:   NONE
1083 *
1084 *  Output parameters:  NONE
1085 */
1086
1087void _Thread_Handler( void )
1088{
1089  ISR_Level  level;
1090  Thread_Control *executing;
1091 
1092  executing = _Thread_Executing;
1093 
1094  /*
1095   * have to put level into a register for those cpu's that use
1096   * inline asm here
1097   */
1098 
1099  level = executing->Start.isr_level;
1100  _ISR_Set_level(level);
1101
1102  /*
1103   * Take care that 'begin' extensions get to complete before
1104   * 'switch' extensions can run.  This means must keep dispatch
1105   * disabled until all 'begin' extensions complete.
1106   */
1107 
1108  _User_extensions_Thread_begin( executing );
1109 
1110  /*
1111   *  At this point, the dispatch disable level BETTER be 1.
1112   */
1113
1114  _Thread_Enable_dispatch();
1115 
1116  switch ( executing->Start.prototype ) {
1117    case THREAD_START_NUMERIC:
1118      (*executing->Start.entry_point)( executing->Start.numeric_argument );
1119      break;
1120    case THREAD_START_POINTER:
1121      (*executing->Start.entry_point)( executing->Start.pointer_argument );
1122      break;
1123    case THREAD_START_BOTH_POINTER_FIRST:
1124      (*executing->Start.entry_point)(
1125        executing->Start.pointer_argument,
1126        executing->Start.numeric_argument
1127      );
1128      break;
1129    case THREAD_START_BOTH_NUMERIC_FIRST:
1130      (*executing->Start.entry_point)(
1131        executing->Start.numeric_argument,
1132        executing->Start.pointer_argument
1133      );
1134      break;
1135  }
1136
1137  _User_extensions_Thread_exitted( executing );
1138
1139  _Internal_error_Occurred(
1140    INTERNAL_ERROR_CORE,
1141    TRUE,
1142    INTERNAL_ERROR_THREAD_EXITTED
1143  );
1144}
1145
1146/*PAGE
1147 *
1148 *  _Thread_Delay_ended
1149 *
1150 *  This routine processes a thread whose delay period has ended.
1151 *  It is called by the watchdog handler.
1152 *
1153 *  Input parameters:
1154 *    id - thread id
1155 *
1156 *  Output parameters: NONE
1157 */
1158
1159void _Thread_Delay_ended(
1160  Objects_Id  id,
1161  void       *ignored
1162)
1163{
1164  Thread_Control    *the_thread;
1165  Objects_Locations  location;
1166
1167  the_thread = _Thread_Get( id, &location );
1168  switch ( location ) {
1169    case OBJECTS_ERROR:
1170    case OBJECTS_REMOTE:  /* impossible */
1171      break;
1172    case OBJECTS_LOCAL:
1173      _Thread_Unblock( the_thread );
1174      _Thread_Unnest_dispatch();
1175      break;
1176  }
1177}
1178
1179/*PAGE
1180 *
1181 *  _Thread_Change_priority
1182 *
1183 *  This kernel routine changes the priority of the thread.  The
1184 *  thread chain is adjusted if necessary.
1185 *
1186 *  Input parameters:
1187 *    the_thread   - pointer to thread control block
1188 *    new_priority - ultimate priority
1189 *
1190 *  Output parameters:  NONE
1191 *
1192 *  INTERRUPT LATENCY:
1193 *    ready chain
1194 *    select heir
1195 */
1196
1197void _Thread_Change_priority(
1198  Thread_Control   *the_thread,
1199  Priority_Control  new_priority
1200)
1201{
1202  ISR_Level level;
1203
1204  _Thread_Set_transient( the_thread );
1205
1206  if ( the_thread->current_priority != new_priority )
1207    _Thread_Set_priority( the_thread, new_priority );
1208
1209  _ISR_Disable( level );
1210
1211  the_thread->current_state =
1212    _States_Clear( STATES_TRANSIENT, the_thread->current_state );
1213
1214  if ( ! _States_Is_ready( the_thread->current_state ) ) {
1215    _ISR_Enable( level );
1216    return;
1217  }
1218
1219  _Priority_Add_to_bit_map( &the_thread->Priority_map );
1220  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
1221
1222  _ISR_Flash( level );
1223
1224  _Thread_Calculate_heir();
1225
1226  if ( !_Thread_Is_executing_also_the_heir() &&
1227       _Thread_Executing->is_preemptible )
1228    _Context_Switch_necessary = TRUE;
1229
1230  _ISR_Enable( level );
1231}
1232
1233/*PAGE
1234 *
1235 * _Thread_Set_priority
1236 *
1237 * This directive enables and disables several modes of
1238 * execution for the requesting thread.
1239 *
1240 *  Input parameters:
1241 *    the_thread   - pointer to thread priority
1242 *    new_priority - new priority
1243 *
1244 *  Output: NONE
1245 */
1246
1247void _Thread_Set_priority(
1248  Thread_Control   *the_thread,
1249  Priority_Control  new_priority
1250)
1251{
1252  the_thread->current_priority = new_priority;
1253  the_thread->ready            = &_Thread_Ready_chain[ new_priority ];
1254
1255  _Priority_Initialize_information( &the_thread->Priority_map, new_priority );
1256}
1257
1258/*PAGE
1259 *
1260 *  _Thread_Evaluate_mode
1261 *
1262 *  XXX
1263 */
1264
1265boolean _Thread_Evaluate_mode( void )
1266{
1267  Thread_Control     *executing;
1268
1269  executing = _Thread_Executing;
1270
1271  if ( !_States_Is_ready( executing->current_state ) ||
1272       ( !_Thread_Is_heir( executing ) && executing->is_preemptible ) ) {
1273    _Context_Switch_necessary = TRUE;
1274    return TRUE;
1275  }
1276
1277  return FALSE;
1278}
1279
1280/*PAGE
1281 *
1282 *  _Thread_Get
1283 *
1284 *  NOTE:  If we are not using static inlines, this must be a real
1285 *         subroutine call.
1286 *
1287 *  NOTE:  XXX... This routine may be able to be optimized.
1288 */
1289
1290#ifndef USE_INLINES
1291
1292Thread_Control *_Thread_Get (
1293  Objects_Id           id,
1294  Objects_Locations   *location
1295)
1296{
1297  Objects_Classes      the_class;
1298  Objects_Information *information;
1299 
1300  if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) {
1301    _Thread_Disable_dispatch();
1302    *location = OBJECTS_LOCAL;
1303    return( _Thread_Executing );
1304  }
1305 
1306  the_class = _Objects_Get_class( id );
1307 
1308  if ( the_class > OBJECTS_CLASSES_LAST ) {
1309    *location = OBJECTS_ERROR;
1310    return (Thread_Control *) 0;
1311  }
1312 
1313  information = _Objects_Information_table[ the_class ];
1314 
1315  if ( !information || !information->is_thread ) {
1316    *location = OBJECTS_ERROR;
1317    return (Thread_Control *) 0;
1318  }
1319 
1320  return (Thread_Control *) _Objects_Get( information, id, location );
1321}
1322
1323#endif
1324
1325/*PAGE
1326 *
1327 *  _Thread_Idle_body
1328 *
1329 *  This kernel routine is the idle thread.  The idle thread runs any time
1330 *  no other thread is ready to run.  This thread loops forever with
1331 *  interrupts enabled.
1332 *
1333 *  Input parameters:
1334 *    ignored - this parameter is ignored
1335 *
1336 *  Output parameters:  NONE
1337 */
1338 
1339#if (CPU_PROVIDES_IDLE_THREAD_BODY == FALSE)
1340Thread _Thread_Idle_body(
1341  unsigned32 ignored
1342)
1343{
1344  for( ; ; ) ;
1345}
1346#endif
Note: See TracBrowser for help on using the repository browser.