source: rtems/c/src/exec/score/src/thread.c @ df26b788

4.104.114.84.95
Last change on this file since df26b788 was df26b788, checked in by Joel Sherrill <joel.sherrill@…>, on 02/14/96 at 17:06:57

white space problem

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