source: rtems/c/src/exec/score/src/thread.c @ 3235ad9

4.104.114.84.9
Last change on this file since 3235ad9 was 3235ad9, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 23, 1995 at 7:30:23 PM

Support for variable length names added to Object Handler. This supports
both fixed length "raw" names and strings from the API's point of view.

Both inline and macro implementations were tested.

  • Property mode set to 100644
File size: 19.2 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/config.h>
18#include <rtems/context.h>
19#include <rtems/fatal.h>
20#include <rtems/init.h>
21#include <rtems/intthrd.h>
22#include <rtems/isr.h>
23#include <rtems/modes.h>
24#include <rtems/object.h>
25#include <rtems/priority.h>
26#include <rtems/states.h>
27#include <rtems/thread.h>
28#include <rtems/userext.h>
29#include <rtems/wkspace.h>
30
31/*PAGE
32 *
33 *  _Thread_Handler_initialization
34 *
35 *  This routine initializes all thread manager related data structures.
36 *
37 *  Input parameters:
38 *    maximum_tasks       - number of tasks to initialize
39 *    ticks_per_timeslice - clock ticks per quantum
40 *
41 *  Output parameters:  NONE
42 */
43
44void _Thread_Handler_initialization(
45  unsigned32   maximum_tasks,
46  unsigned32   ticks_per_timeslice,
47  unsigned32   maximum_proxies
48)
49{
50  unsigned32 index;
51
52  _Context_Switch_necessary = FALSE;
53  _Thread_Executing         = NULL;
54  _Thread_Heir              = NULL;
55  _Thread_Allocated_fp      = NULL;
56
57  _Thread_Ticks_remaining_in_timeslice = ticks_per_timeslice;
58  _Thread_Ticks_per_timeslice          = ticks_per_timeslice;
59
60  _Objects_Initialize_information(
61    &_Thread_Information,
62    OBJECTS_RTEMS_TASKS,
63    TRUE,
64    maximum_tasks,
65    sizeof( Thread_Control ),
66    FALSE,
67    RTEMS_MAXIMUM_NAME_LENGTH
68  );
69
70  _Thread_Ready_chain = _Workspace_Allocate_or_fatal_error(
71    (RTEMS_MAXIMUM_PRIORITY + 1) * sizeof(Chain_Control)
72  );
73
74  for ( index=0; index <= RTEMS_MAXIMUM_PRIORITY ; index++ )
75    _Chain_Initialize_empty( &_Thread_Ready_chain[ index ] );
76
77  _Thread_MP_Handler_initialization( maximum_proxies );
78}
79
80/*PAGE
81 *
82 *  _Thread_Start_multitasking
83 *
84 *  This kernel routine readies the requested thread, the thread chain
85 *  is adjusted.  A new heir thread may be selected.
86 *
87 *  Input parameters:
88 *    system_thread - pointer to system initialization thread control block
89 *    idle_thread   - pointer to idle thread control block
90 *
91 *  Output parameters:  NONE
92 *
93 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
94 *         This insures the correct heir after a thread restart.
95 *
96 *  INTERRUPT LATENCY:
97 *    ready chain
98 *    select heir
99 */
100
101void _Thread_Start_multitasking(
102  Thread_Control *system_thread,
103  Thread_Control *idle_thread
104)
105{
106
107   _Thread_Executing  =
108   _Thread_Heir       =
109   _Thread_MP_Receive = system_thread;
110
111   /*
112    *  Scheduling will not work "correctly" until the above
113    *  statements have been executed.
114    */
115
116   _Thread_Ready( system_thread );
117   _Thread_Ready( idle_thread );
118
119   _Context_Switch_necessary = FALSE;
120
121   _Context_Switch( &_Thread_BSP_context, &system_thread->Registers );
122
123}
124
125/*PAGE
126 *
127 *  _Thread_Dispatch
128 *
129 *  This kernel routine determines if a dispatch is needed, and if so
130 *  dispatches to the heir thread.  Once the heir is running an attempt
131 *  is made to dispatch any ASRs.
132 *
133 *  ALTERNATE ENTRY POINTS:
134 *    void _Thread_Enable_dispatch();
135 *
136 *  Input parameters:  NONE
137 *
138 *  Output parameters:  NONE
139 *
140 *  INTERRUPT LATENCY:
141 *    dispatch thread
142 *    no dispatch thread
143 */
144
145#if ( CPU_INLINE_ENABLE_DISPATCH == FALSE )
146void _Thread_Enable_dispatch( void )
147{
148  if ( --_Thread_Dispatch_disable_level )
149    return;
150  _Thread_Dispatch();
151}
152#endif
153
154void _Thread_Dispatch( void )
155{
156  Thread_Control  *executing;
157  Thread_Control  *heir;
158  ISR_Level               level;
159  rtems_signal_set  signal_set;
160  rtems_mode           previous_mode;
161
162  executing   = _Thread_Executing;
163  _ISR_Disable( level );
164  while ( _Context_Switch_necessary == TRUE ) {
165    heir = _Thread_Heir;
166    _Thread_Dispatch_disable_level = 1;
167    _Context_Switch_necessary = FALSE;
168    _Thread_Executing = heir;
169    _ISR_Enable( level );
170
171    _User_extensions_Task_switch( executing, heir );
172
173    _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
174
175    /*
176     *  If the CPU has hardware floating point, then we must address saving
177     *  and restoring it as part of the context switch.
178     *
179     *  The second conditional compilation section selects the algorithm used
180     *  to context switch between floating point tasks.  The deferred algorithm
181     *  can be significantly better in a system with few floating point tasks
182     *  because it reduces the total number of save and restore FP context
183     *  operations.  However, this algorithm can not be used on all CPUs due
184     *  to unpredictable use of FP registers by some compilers for integer
185     *  operations.
186     */
187
188#if ( CPU_HARDWARE_FP == TRUE )
189#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
190    if ( (heir->fp_context != NULL) && !_Thread_Is_allocated_fp( heir ) ) {
191      if ( _Thread_Allocated_fp != NULL )
192        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
193      _Context_Restore_fp( &heir->fp_context );
194      _Thread_Allocated_fp = heir;
195    }
196#else
197    if ( executing->fp_context != NULL )
198      _Context_Save_fp( &executing->fp_context );
199
200    if ( heir->fp_context != NULL )
201      _Context_Restore_fp( &heir->fp_context );
202#endif
203#endif
204
205    _Context_Switch( &executing->Registers, &heir->Registers );
206
207    executing = _Thread_Executing;
208    _ISR_Disable( level );
209  }
210
211  _Thread_Dispatch_disable_level = 0;
212
213  if ( _ASR_Are_signals_pending( &executing->Signal ) ) {
214    signal_set                       = executing->Signal.signals_posted;
215    executing->Signal.signals_posted = 0;
216    _ISR_Enable( level );
217
218    executing->Signal.nest_level += 1;
219    if (_Thread_Change_mode( executing->Signal.mode_set,
220                                RTEMS_ALL_MODE_MASKS, &previous_mode ))
221        _Thread_Dispatch();
222
223    (*executing->Signal.handler)( signal_set );
224
225    executing->Signal.nest_level -= 1;
226    if (_Thread_Change_mode( previous_mode,
227                                RTEMS_ALL_MODE_MASKS, &previous_mode ))
228        _Thread_Dispatch();
229  }
230  else
231    _ISR_Enable( level );
232}
233
234/*PAGE
235 *
236 *  _Thread_Ready
237 *
238 *  This kernel routine readies the requested thread, the thread chain
239 *  is adjusted.  A new heir thread may be selected.
240 *
241 *  Input parameters:
242 *    the_thread - pointer to thread control block
243 *
244 *  Output parameters:  NONE
245 *
246 *  NOTE:  This routine uses the "blocking" heir selection mechanism.
247 *         This insures the correct heir after a thread restart.
248 *
249 *  INTERRUPT LATENCY:
250 *    ready chain
251 *    select heir
252 */
253
254void _Thread_Ready(
255  Thread_Control *the_thread
256)
257{
258  ISR_Level              level;
259  Thread_Control *heir;
260
261  _ISR_Disable( level );
262
263  the_thread->current_state = STATES_READY;
264
265  _Priority_Add_to_bit_map( &the_thread->Priority_map );
266
267  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
268
269  _ISR_Flash( level );
270
271  _Thread_Calculate_heir();
272
273  heir = _Thread_Heir;
274
275  if ( !_Thread_Is_executing( heir ) &&
276        _Modes_Is_preempt( _Thread_Executing->current_modes ) )
277    _Context_Switch_necessary = TRUE;
278
279  _ISR_Enable( level );
280}
281
282/*PAGE
283 *
284 *  _Thread_Clear_state
285 *
286 *  This kernel routine clears the appropriate states in the
287 *  requested thread.  The thread ready chain is adjusted if
288 *  necessary and the Heir thread is set accordingly.
289 *
290 *  Input parameters:
291 *    the_thread - pointer to thread control block
292 *    state      - state set to clear
293 *
294 *  Output parameters:  NONE
295 *
296 *  INTERRUPT LATENCY:
297 *    priority map
298 *    select heir
299 */
300
301void _Thread_Clear_state(
302  Thread_Control *the_thread,
303  States_Control  state
304)
305{
306  ISR_Level level;
307
308  _ISR_Disable( level );
309    the_thread->current_state =
310      _States_Clear( state, the_thread->current_state );
311
312    if ( _States_Is_ready( the_thread->current_state ) ) {
313
314      _Priority_Add_to_bit_map( &the_thread->Priority_map );
315
316      _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
317
318      _ISR_Flash( level );
319
320      if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
321        _Thread_Heir = the_thread;
322        if ( _Modes_Is_preempt( _Thread_Executing->current_modes ) ||
323             the_thread->current_priority == 0 )
324          _Context_Switch_necessary = TRUE;
325      }
326    }
327  _ISR_Enable( level );
328}
329
330/*PAGE
331 *
332 * _Thread_Set_state
333 *
334 * This kernel routine sets the requested state in the THREAD.  The
335 * THREAD chain is adjusted if necessary.
336 *
337 * Input parameters:
338 *   the_thread   - pointer to thread control block
339 *   state - state to be set
340 *
341 * Output parameters:  NONE
342 *
343 *  INTERRUPT LATENCY:
344 *    ready chain
345 *    select map
346 */
347
348void _Thread_Set_state(
349  Thread_Control *the_thread,
350  States_Control         state
351)
352{
353  ISR_Level             level;
354  Chain_Control *ready;
355
356  ready = the_thread->ready;
357  _ISR_Disable( level );
358  if ( !_States_Is_ready( the_thread->current_state ) ) {
359    the_thread->current_state =
360       _States_Set( state, the_thread->current_state );
361    _ISR_Enable( level );
362    return;
363  }
364
365  the_thread->current_state = state;
366
367  if ( _Chain_Has_only_one_node( ready ) ) {
368
369    _Chain_Initialize_empty( ready );
370    _Priority_Remove_from_bit_map( &the_thread->Priority_map );
371
372  } else
373    _Chain_Extract_unprotected( &the_thread->Object.Node );
374
375  _ISR_Flash( level );
376
377  if ( _Thread_Is_heir( the_thread ) )
378     _Thread_Calculate_heir();
379
380  if ( _Thread_Is_executing( the_thread ) )
381    _Context_Switch_necessary = TRUE;
382
383  _ISR_Enable( level );
384}
385
386/*PAGE
387 *
388 *  _Thread_Set_transient
389 *
390 *  This kernel routine places the requested thread in the transient state
391 *  which will remove it from the ready queue, if necessary.  No
392 *  rescheduling is necessary because it is assumed that the transient
393 *  state will be cleared before dispatching is enabled.
394 *
395 *  Input parameters:
396 *    the_thread - pointer to thread control block
397 *
398 *  Output parameters:  NONE
399 *
400 *  INTERRUPT LATENCY:
401 *    only case
402 */
403
404void _Thread_Set_transient(
405  Thread_Control *the_thread
406)
407{
408  ISR_Level             level;
409  unsigned32            old_state;
410  Chain_Control *ready;
411
412  ready = the_thread->ready;
413  _ISR_Disable( level );
414
415  old_state = the_thread->current_state;
416  the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state );
417
418  if ( _States_Is_ready( old_state ) ) {
419    if ( _Chain_Has_only_one_node( ready ) ) {
420
421      _Chain_Initialize_empty( ready );
422      _Priority_Remove_from_bit_map( &the_thread->Priority_map );
423
424    } else
425      _Chain_Extract_unprotected( &the_thread->Object.Node );
426  }
427
428  _ISR_Enable( level );
429
430}
431
432/*PAGE
433 *
434 *  _Thread_Reset_timeslice
435 *
436 *  This routine will remove the running thread from the ready chain
437 *  and place it immediately at the rear of this chain and then the
438 *  timeslice counter is reset.  The heir THREAD will be updated if
439 *  the running is also the currently the heir.
440 *
441 *  Input parameters:   NONE
442 *
443 *  Output parameters:  NONE
444 *
445 *  INTERRUPT LATENCY:
446 *    ready chain
447 *    select heir
448 */
449
450void _Thread_Reset_timeslice( void )
451{
452  ISR_Level              level;
453  Thread_Control *executing;
454  Chain_Control  *ready;
455
456  executing = _Thread_Executing;
457  ready     = executing->ready;
458  _ISR_Disable( level );
459    if ( _Chain_Has_only_one_node( ready ) ) {
460      _Thread_Ticks_remaining_in_timeslice = _Thread_Ticks_per_timeslice;
461      _ISR_Enable( level );
462      return;
463    }
464    _Chain_Extract_unprotected( &executing->Object.Node );
465    _Chain_Append_unprotected( ready, &executing->Object.Node );
466
467  _ISR_Flash( level );
468
469    if ( _Thread_Is_heir( executing ) )
470      _Thread_Heir = (Thread_Control *) ready->first;
471
472    _Context_Switch_necessary = TRUE;
473
474  _ISR_Enable( level );
475}
476
477/*PAGE
478 *
479 *  _Thread_Tickle_timeslice
480 *
481 *  This scheduler routine determines if timeslicing is enabled
482 *  for the currently executing thread and, if so, updates the
483 *  timeslice count and checks for timeslice expiration.
484 *
485 *  Input parameters:   NONE
486 *
487 *  Output parameters:  NONE
488 */
489
490void _Thread_Tickle_timeslice( void )
491{
492  if ( ( _Modes_Is_timeslice(_Thread_Executing->current_modes) )  &&
493       ( _States_Is_ready( _Thread_Executing->current_state ) ) &&
494       ( --_Thread_Ticks_remaining_in_timeslice == 0 ) ) {
495      _Thread_Reset_timeslice();
496  }
497}
498
499/*PAGE
500 *
501 *  _Thread_Yield_processor
502 *
503 *  This kernel routine will remove the running THREAD from the ready chain
504 *  and place it immediatly at the rear of this chain.  Reset timeslice
505 *  and yield the processor functions both use this routine, therefore if
506 *  reset is TRUE and this is the only thread on the chain then the
507 *  timeslice counter is reset.  The heir THREAD will be updated if the
508 *  running is also the currently the heir.
509 *
510 *  Input parameters:   NONE
511 *
512 *  Output parameters:  NONE
513 *
514 *  INTERRUPT LATENCY:
515 *    ready chain
516 *    select heir
517 */
518
519void _Thread_Yield_processor( void )
520{
521  ISR_Level       level;
522  Thread_Control *executing;
523  Chain_Control  *ready;
524
525  executing = _Thread_Executing;
526  ready     = executing->ready;
527  _ISR_Disable( level );
528    if ( !_Chain_Has_only_one_node( ready ) ) {
529      _Chain_Extract_unprotected( &executing->Object.Node );
530      _Chain_Append_unprotected( ready, &executing->Object.Node );
531
532      _ISR_Flash( level );
533
534      if ( _Thread_Is_heir( executing ) )
535        _Thread_Heir = (Thread_Control *) ready->first;
536      _Context_Switch_necessary = TRUE;
537    }
538    else if ( !_Thread_Is_heir( executing ) )
539      _Context_Switch_necessary = TRUE;
540
541  _ISR_Enable( level );
542}
543
544/*PAGE
545 *
546 *  _Thread_Load_environment
547 *
548 *  Load starting environment for another thread from its start area in the
549 *  thread.  Only called from t_restart and t_start.
550 *
551 *  Input parameters:
552 *    the_thread - thread control block pointer
553 *
554 *  Output parameters:  NONE
555 */
556
557void _Thread_Load_environment(
558  Thread_Control *the_thread
559)
560{
561  if ( the_thread->Start.fp_context ) {
562    the_thread->fp_context = the_thread->Start.fp_context;
563    _Context_Initialize_fp( &the_thread->fp_context );
564  }
565
566  _Context_Initialize(
567    &the_thread->Registers,
568    the_thread->Start.Initial_stack.area,
569    the_thread->Start.Initial_stack.size,
570    _Modes_Get_interrupt_level( the_thread->Start.initial_modes ),
571    _Thread_Handler
572  );
573
574}
575
576/*PAGE
577 *
578 *  _Thread_Handler
579 *
580 *  This routine is the default thread exitted error handler.  It is
581 *  returned to when a thread exits.  The configured fatal error handler
582 *  is invoked to process the exit.
583 *
584 *  Input parameters:   NONE
585 *
586 *  Output parameters:  NONE
587 */
588
589void _Thread_Handler( void )
590{
591  Thread_Control *executing;
592
593  executing = _Thread_Executing;
594
595  /*
596   * Take care that 'begin' extensions get to complete before
597   * 'switch' extensions can run.  This means must keep dispatch
598   * disabled until all 'begin' extensions complete.
599   */
600 
601  _User_extensions_Task_begin( executing );
602 
603  /*
604   *  At this point, the dispatch disable level BETTER be 1.
605   */
606
607  _Thread_Enable_dispatch();
608 
609  (*executing->Start.entry_point)( executing->Start.initial_argument );
610
611  _User_extensions_Task_exitted( executing );
612
613  rtems_fatal_error_occurred( RTEMS_TASK_EXITTED );
614}
615
616/*PAGE
617 *
618 *  _Thread_Delay_ended
619 *
620 *  This routine processes a thread whose delay period has ended.
621 *  It is called by the watchdog handler.
622 *
623 *  Input parameters:
624 *    id - thread id
625 *
626 *  Output parameters: NONE
627 */
628
629void _Thread_Delay_ended(
630  Objects_Id  id,
631  void       *ignored
632)
633{
634  Thread_Control    *the_thread;
635  Objects_Locations  location;
636
637  the_thread = _Thread_Get( id, &location );
638  switch ( location ) {
639    case OBJECTS_ERROR:
640    case OBJECTS_REMOTE:  /* impossible */
641      break;
642    case OBJECTS_LOCAL:
643      _Thread_Unblock( the_thread );
644      _Thread_Unnest_dispatch();
645      break;
646  }
647}
648
649/*PAGE
650 *
651 *  _Thread_Change_priority
652 *
653 *  This kernel routine changes the priority of the thread.  The
654 *  thread chain is adjusted if necessary.
655 *
656 *  Input parameters:
657 *    the_thread   - pointer to thread control block
658 *    new_priority - ultimate priority
659 *
660 *  Output parameters:  NONE
661 *
662 *  INTERRUPT LATENCY:
663 *    ready chain
664 *    select heir
665 */
666
667void _Thread_Change_priority(
668  Thread_Control *the_thread,
669  rtems_task_priority       new_priority
670)
671{
672  ISR_Level level;
673
674  _Thread_Set_transient( the_thread );
675
676  if ( the_thread->current_priority != new_priority )
677    _Thread_Set_priority( the_thread, new_priority );
678
679  _ISR_Disable( level );
680
681  the_thread->current_state =
682    _States_Clear( STATES_TRANSIENT, the_thread->current_state );
683
684  if ( ! _States_Is_ready( the_thread->current_state ) ) {
685    _ISR_Enable( level );
686    return;
687  }
688
689  _Priority_Add_to_bit_map( &the_thread->Priority_map );
690  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
691
692  _ISR_Flash( level );
693
694  _Thread_Calculate_heir();
695
696  if ( !_Thread_Is_executing_also_the_heir() &&
697       _Modes_Is_preempt(_Thread_Executing->current_modes) )
698    _Context_Switch_necessary = TRUE;
699
700  _ISR_Enable( level );
701}
702
703/*PAGE
704 *
705 * _Thread_Set_priority
706 *
707 * This directive enables and disables several modes of
708 * execution for the requesting thread.
709 *
710 *  Input parameters:
711 *    the_thread   - pointer to thread priority
712 *    new_priority - new priority
713 *
714 *  Output: NONE
715 */
716
717void _Thread_Set_priority(
718  Thread_Control *the_thread,
719  rtems_task_priority       new_priority
720)
721{
722  the_thread->current_priority = new_priority;
723  the_thread->ready            = &_Thread_Ready_chain[ new_priority ];
724
725  _Priority_Initialize_information( &the_thread->Priority_map, new_priority );
726}
727
728/*PAGE
729 *
730 *  _Thread_Change_mode
731 *
732 *  This routine enables and disables several modes of
733 *  execution for the requesting thread.
734 *
735 *  Input parameters:
736 *    mode         - new mode
737 *    mask         - mask
738 *    old_mode_set - address of previous mode
739 *
740 *  Output:
741 *    *old_mode_set - previous mode
742 *     returns TRUE if scheduling necessary
743 *
744 *  INTERRUPT LATENCY:
745 *    only one case
746 */
747
748boolean _Thread_Change_mode(
749  unsigned32  new_mode_set,
750  unsigned32  mask,
751  unsigned32 *old_mode_set
752)
753{
754  rtems_mode   changed;
755  rtems_mode   threads_new_mode_set;
756  Thread_Control *executing;
757  boolean         need_dispatch;
758
759  executing     = _Thread_Executing;
760  *old_mode_set = executing->current_modes;
761
762  _Modes_Change( executing->current_modes,
763                   new_mode_set, mask, &threads_new_mode_set, &changed );
764
765  _Modes_Set_interrupt_level( threads_new_mode_set );
766
767  if ( _Modes_Mask_changed( changed, RTEMS_ASR_MASK ) )
768    _ASR_Swap_signals( &executing->Signal );
769
770  executing->current_modes = threads_new_mode_set;
771  need_dispatch = TRUE;
772
773  if ( !_States_Is_ready( executing->current_state ) ||
774       ( !_Thread_Is_heir( executing ) &&
775         _Modes_Is_preempt(threads_new_mode_set) ) )
776
777     _Context_Switch_necessary = TRUE;
778
779  else if ( !_ASR_Are_signals_pending( &executing->Signal ) )
780
781    need_dispatch = FALSE;
782
783  return need_dispatch;
784}
785
786/*PAGE
787 *
788 *  _Thread_Get
789 *
790 *  NOTE:  If we are not using static inlines, this must be a real
791 *         subroutine call.
792 */
793
794#ifndef USE_INLINES
795
796STATIC INLINE Thread_Control *_Thread_Get (
797  Objects_Id         id,
798  Objects_Locations *location
799)
800{
801  if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) {
802     _Thread_Disable_dispatch();
803     *location = OBJECTS_LOCAL;
804     return( _Thread_Executing );
805  }
806
807  return (Thread_Control *) _Objects_Get( &_Thread_Information, id, location );
808}
809#endif
810
Note: See TracBrowser for help on using the repository browser.