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

4.104.114.84.95
Last change on this file since 9700578 was 9700578, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 30, 1995 at 9:54:45 PM

SPARC port passes all tests

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