source: rtems/cpukit/score/src/thread.c @ adf98bd

4.104.114.84.95
Last change on this file since adf98bd was adf98bd, checked in by Joel Sherrill <joel.sherrill@…>, on 02/21/96 at 14:44:11

Removed the internal thread objects and dispersed its contents to
the thread handler (IDLE), MPCI object (SYSI now MP Receive)
and initialize_executive_early (IO initialization). The SYSI task
no longer exists in a single processor configuration. This reduces
single processor Workspace requirements by a TCB and a stack which
is often larger than the minimum stack size. Moving the IO initialization
plus accompanying BSP hooks eliminated an initialization ordering problem
in which a global task could be created before the MPCI was initialized.

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