source: rtems/c/src/exec/score/src/thread.c @ 94b3ec59

4.104.114.84.95
Last change on this file since 94b3ec59 was 94b3ec59, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 13, 1996 at 10:14:48 PM

changed post task extension from user set to api set and added flag
in each thread which must be set when the post switch extension is to be run.

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