source: rtems/cpukit/score/src/threadq.c @ 107ce47b

4.104.114.84.95
Last change on this file since 107ce47b was 107ce47b, checked in by Joel Sherrill <joel.sherrill@…>, on 02/09/96 at 14:30:42

new isr synchronization algorithm using a single enumerated set of states.

  • Property mode set to 100644
File size: 25.2 KB
Line 
1/*
2 *  Thread Queue 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/chain.h>
18#include <rtems/score/isr.h>
19#include <rtems/score/object.h>
20#include <rtems/score/states.h>
21#include <rtems/score/thread.h>
22#include <rtems/score/threadq.h>
23#include <rtems/score/tqdata.h>
24
25/*PAGE
26 *
27 *  _Thread_queue_Initialize
28 *
29 *  This routine initializes the specified threadq.
30 *
31 *  Input parameters:
32 *    the_thread_queue      - pointer to a threadq header
33 *    the_class             - class of the object to which this belongs
34 *    discipline            - queueing discipline
35 *    state                 - state of waiting threads
36 *    proxy_extract_callout - MP specific callout
37 *    timeout_status        - return on a timeout
38 *
39 *  Output parameters: NONE
40 */
41
42void _Thread_queue_Initialize(
43  Thread_queue_Control         *the_thread_queue,
44  Objects_Classes               the_class,
45  Thread_queue_Disciplines      the_discipline,
46  States_Control                state,
47  Thread_queue_Extract_callout  proxy_extract_callout,
48  unsigned32                    timeout_status
49)
50{
51  unsigned32 index;
52
53  _Thread_queue_Extract_table[ the_class ] = proxy_extract_callout;
54
55  the_thread_queue->state          = state;
56  the_thread_queue->discipline     = the_discipline;
57  the_thread_queue->timeout_status = timeout_status;
58  the_thread_queue->sync_state     = THREAD_QUEUE_SYNCHRONIZED;
59
60  switch ( the_discipline ) {
61    case THREAD_QUEUE_DISCIPLINE_FIFO:
62      _Chain_Initialize_empty( &the_thread_queue->Queues.Fifo );
63      break;
64    case THREAD_QUEUE_DISCIPLINE_PRIORITY:
65      for( index=0 ;
66           index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
67           index++)
68        _Chain_Initialize_empty( &the_thread_queue->Queues.Priority[index] );
69      break;
70  }
71
72}
73
74/*PAGE
75 *
76 *  _Thread_queue_Enqueue
77 *
78 *  This routine blocks a thread, places it on a thread, and optionally
79 *  starts a timeout timer.
80 *
81 *  Input parameters:
82 *    the_thread_queue - pointer to threadq
83 *    timeout          - interval to wait
84 *
85 *  Output parameters: NONE
86 *
87 *  INTERRUPT LATENCY:
88 *    only case
89 */
90
91void _Thread_queue_Enqueue(
92  Thread_queue_Control *the_thread_queue,
93  Watchdog_Interval     timeout
94)
95{
96  Thread_Control *the_thread;
97
98  the_thread = _Thread_Executing;
99
100  if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet )
101    the_thread = _Thread_MP_Allocate_proxy( the_thread_queue->state );
102  else
103    _Thread_Set_state( the_thread, the_thread_queue->state );
104
105  if ( timeout ) {
106    _Watchdog_Initialize(
107       &the_thread->Timer,
108       _Thread_queue_Timeout,
109       the_thread->Object.id,
110       NULL
111    );
112
113    _Watchdog_Insert_ticks( &the_thread->Timer, timeout );
114  }
115
116  switch( the_thread_queue->discipline ) {
117    case THREAD_QUEUE_DISCIPLINE_FIFO:
118      _Thread_queue_Enqueue_fifo( the_thread_queue, the_thread, timeout );
119      break;
120    case THREAD_QUEUE_DISCIPLINE_PRIORITY:
121      _Thread_queue_Enqueue_priority( the_thread_queue, the_thread, timeout );
122      break;
123  }
124}
125
126/*PAGE
127 *
128 *  _Thread_queue_Dequeue
129 *
130 *  This routine removes a thread from the specified threadq.  If the
131 *  threadq discipline is FIFO, it unblocks a thread, and cancels its
132 *  timeout timer.  Priority discipline is processed elsewhere.
133 *
134 *  Input parameters:
135 *    the_thread_queue - pointer to threadq
136 *
137 *  Output parameters:
138 *    returns - thread dequeued or NULL
139 *
140 *  INTERRUPT LATENCY:
141 *    check sync
142 */
143
144Thread_Control *_Thread_queue_Dequeue(
145  Thread_queue_Control *the_thread_queue
146)
147{
148  Thread_Control *the_thread;
149
150  switch ( the_thread_queue->discipline ) {
151    case THREAD_QUEUE_DISCIPLINE_FIFO:
152      the_thread = _Thread_queue_Dequeue_fifo( the_thread_queue );
153      break;
154    case THREAD_QUEUE_DISCIPLINE_PRIORITY:
155      the_thread = _Thread_queue_Dequeue_priority( the_thread_queue );
156      break;
157    default:              /* this is only to prevent warnings */
158      the_thread = NULL;
159      break;
160  }
161
162  return( the_thread );
163}
164
165/*PAGE
166 *
167 *  _Thread_queue_Extract_with_proxy
168 *
169 *  This routine extracts the_thread from the_thread_queue
170 *  and insures that if there is a proxy for this task on
171 *  another node, it is also dealt with.
172 *
173 *  XXX
174 */
175 
176boolean _Thread_queue_Extract_with_proxy(
177  Thread_Control       *the_thread
178)
179{
180  States_Control                state;
181  Objects_Classes               the_class;
182  Thread_queue_Extract_callout  proxy_extract_callout;
183
184  state = the_thread->current_state;
185
186  if ( _States_Is_waiting_on_thread_queue( state ) ) {
187    if ( _States_Is_waiting_for_rpc_reply( state ) &&
188         _States_Is_locally_blocked( state ) ) {
189
190      the_class = _Objects_Get_class( the_thread->Wait.id );
191
192      proxy_extract_callout = _Thread_queue_Extract_table[ the_class ];
193
194      if ( proxy_extract_callout )
195        (*proxy_extract_callout)( the_thread );
196    }
197    _Thread_queue_Extract( the_thread->Wait.queue, the_thread );
198
199    return TRUE;
200  }
201  return FALSE;
202}
203
204/*PAGE
205 *
206 *  _Thread_queue_Extract
207 *
208 *  This routine removes a specific thread from the specified threadq,
209 *  deletes any timeout, and unblocks the thread.
210 *
211 *  Input parameters:
212 *    the_thread_queue - pointer to a threadq header
213 *    the_thread       - pointer to a thread control block
214 *
215 *  Output parameters: NONE
216 *
217 *  INTERRUPT LATENCY: NONE
218 */
219
220void _Thread_queue_Extract(
221  Thread_queue_Control *the_thread_queue,
222  Thread_Control       *the_thread
223)
224{
225  switch ( the_thread_queue->discipline ) {
226    case THREAD_QUEUE_DISCIPLINE_FIFO:
227      _Thread_queue_Extract_fifo( the_thread_queue, the_thread );
228      break;
229    case THREAD_QUEUE_DISCIPLINE_PRIORITY:
230      _Thread_queue_Extract_priority( the_thread_queue, the_thread );
231      break;
232   }
233}
234
235/*PAGE
236 *
237 *  _Thread_queue_Flush
238 *
239 *  This kernel routine flushes the given thread queue.
240 *
241 *  Input parameters:
242 *    the_thread_queue       - pointer to threadq to be flushed
243 *    remote_extract_callout - pointer to routine which extracts a remote thread
244 *    status                 - status to return to the thread
245 *
246 *  Output parameters:  NONE
247 */
248
249void _Thread_queue_Flush(
250  Thread_queue_Control       *the_thread_queue,
251  Thread_queue_Flush_callout  remote_extract_callout,
252  unsigned32                  status
253)
254{
255  Thread_Control *the_thread;
256
257  while ( (the_thread = _Thread_queue_Dequeue( the_thread_queue )) ) {
258    if ( _Objects_Is_local_id( the_thread->Object.id ) )
259      the_thread->Wait.return_code = status;
260    else
261      ( *remote_extract_callout )( the_thread );
262  }
263}
264
265/*PAGE
266 *
267 *  _Thread_queue_First
268 *
269 *  This routines returns a pointer to the first thread on the
270 *  specified threadq.
271 *
272 *  Input parameters:
273 *    the_thread_queue - pointer to thread queue
274 *
275 *  Output parameters:
276 *    returns - first thread or NULL
277 */
278
279Thread_Control *_Thread_queue_First(
280  Thread_queue_Control *the_thread_queue
281)
282{
283  Thread_Control *the_thread;
284
285  switch ( the_thread_queue->discipline ) {
286    case THREAD_QUEUE_DISCIPLINE_FIFO:
287      the_thread = _Thread_queue_First_fifo( the_thread_queue );
288      break;
289    case THREAD_QUEUE_DISCIPLINE_PRIORITY:
290      the_thread = _Thread_queue_First_priority( the_thread_queue );
291      break;
292    default:              /* this is only to prevent warnings */
293      the_thread = NULL;
294      break;
295  }
296
297  return the_thread;
298}
299
300/*PAGE
301 *
302 *  _Thread_queue_Timeout
303 *
304 *  This routine processes a thread which timeouts while waiting on
305 *  a thread queue. It is called by the watchdog handler.
306 *
307 *  Input parameters:
308 *    id - thread id
309 *
310 *  Output parameters: NONE
311 */
312
313void _Thread_queue_Timeout(
314  Objects_Id  id,
315  void       *ignored
316)
317{
318  Thread_Control       *the_thread;
319  Thread_queue_Control *the_thread_queue;
320  Objects_Locations     location;
321
322  the_thread = _Thread_Get( id, &location );
323  switch ( location ) {
324    case OBJECTS_ERROR:
325    case OBJECTS_REMOTE:  /* impossible */
326      break;
327    case OBJECTS_LOCAL:
328      the_thread_queue = the_thread->Wait.queue;
329
330      if ( the_thread_queue->sync_state != THREAD_QUEUE_SYNCHRONIZED &&
331           _Thread_Is_executing( the_thread ) ) {
332        if ( the_thread_queue->sync_state != THREAD_QUEUE_SATISFIED )
333          the_thread_queue->sync_state = THREAD_QUEUE_TIMEOUT;
334      } else {
335        the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
336        _Thread_queue_Extract( the_thread->Wait.queue, the_thread );
337      }
338      _Thread_Unnest_dispatch();
339      break;
340  }
341}
342
343/*PAGE
344 *
345 *  _Thread_queue_Enqueue_fifo
346 *
347 *  This routine blocks a thread, places it on a thread, and optionally
348 *  starts a timeout timer.
349 *
350 *  Input parameters:
351 *    the_thread_queue - pointer to threadq
352 *    the_thread       - pointer to the thread to block
353 *    timeout          - interval to wait
354 *
355 *  Output parameters: NONE
356 *
357 *  INTERRUPT LATENCY:
358 *    only case
359 */
360
361void _Thread_queue_Enqueue_fifo (
362  Thread_queue_Control *the_thread_queue,
363  Thread_Control       *the_thread,
364  Watchdog_Interval    timeout
365)
366{
367  ISR_Level            level;
368  Thread_queue_States  sync_state;
369
370  _ISR_Disable( level );
371
372  sync_state = the_thread_queue->sync_state;
373  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
374
375  switch ( sync_state ) {
376    case THREAD_QUEUE_SYNCHRONIZED:
377      /*
378       *  This should never happen.  It indicates that someone did not
379       *  enter a thread queue critical section.
380       */
381      break;
382
383    case THREAD_QUEUE_NOTHING_HAPPENED:
384      _Chain_Append_unprotected(
385        &the_thread_queue->Queues.Fifo,
386        &the_thread->Object.Node
387      );
388      _ISR_Enable( level );
389      return;
390
391    case THREAD_QUEUE_TIMEOUT:
392      the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
393      _ISR_Enable( level );
394      break;
395
396    case THREAD_QUEUE_SATISFIED:
397      if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
398        _Watchdog_Deactivate( &the_thread->Timer );
399        _ISR_Enable( level );
400        (void) _Watchdog_Remove( &the_thread->Timer );
401      } else
402        _ISR_Enable( level );
403      break;
404  }
405
406  /*
407   *  Global objects with thread queue's should not be operated on from an
408   *  ISR.  But the sync code still must allow short timeouts to be processed
409   *  correctly.
410   */
411
412  _Thread_Unblock( the_thread );
413
414  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
415    _Thread_MP_Free_proxy( the_thread );
416
417}
418
419/*PAGE
420 *
421 *  _Thread_queue_Dequeue_fifo
422 *
423 *  This routine removes a thread from the specified threadq.
424 *
425 *  Input parameters:
426 *    the_thread_queue - pointer to threadq
427 *
428 *  Output parameters:
429 *    returns - thread dequeued or NULL
430 *
431 *  INTERRUPT LATENCY:
432 *    check sync
433 *    FIFO
434 */
435
436Thread_Control *_Thread_queue_Dequeue_fifo(
437  Thread_queue_Control *the_thread_queue
438)
439{
440  ISR_Level              level;
441  Thread_Control *the_thread;
442
443  _ISR_Disable( level );
444  if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) {
445
446    the_thread = (Thread_Control *)
447       _Chain_Get_first_unprotected( &the_thread_queue->Queues.Fifo );
448
449    if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
450      _ISR_Enable( level );
451      _Thread_Unblock( the_thread );
452    } else {
453      _Watchdog_Deactivate( &the_thread->Timer );
454      _ISR_Enable( level );
455      (void) _Watchdog_Remove( &the_thread->Timer );
456      _Thread_Unblock( the_thread );
457    }
458
459    if ( !_Objects_Is_local_id( the_thread->Object.id ) )
460      _Thread_MP_Free_proxy( the_thread );
461
462    return the_thread;
463  }
464
465  switch ( the_thread_queue->sync_state ) {
466    case THREAD_QUEUE_SYNCHRONIZED:
467    case THREAD_QUEUE_SATISFIED:
468      _ISR_Enable( level );
469      return NULL;
470
471    case THREAD_QUEUE_NOTHING_HAPPENED:
472    case THREAD_QUEUE_TIMEOUT:
473      the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
474      _ISR_Enable( level );
475      return _Thread_Executing;
476  }
477  return NULL;                /* this is only to prevent warnings */
478}
479
480/*PAGE
481 *
482 *  _Thread_queue_Extract_fifo
483 *
484 *  This routine removes a specific thread from the specified threadq,
485 *  deletes any timeout, and unblocks the thread.
486 *
487 *  Input parameters:
488 *    the_thread_queue - pointer to a threadq header
489 *    the_thread       - pointer to the thread to block
490 *
491 *  Output parameters: NONE
492 *
493 *  INTERRUPT LATENCY:
494 *    EXTRACT_FIFO
495 */
496
497void _Thread_queue_Extract_fifo(
498  Thread_queue_Control *the_thread_queue,
499  Thread_Control       *the_thread
500)
501{
502  ISR_Level level;
503
504  _ISR_Disable( level );
505
506  if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
507    _ISR_Enable( level );
508    return;
509  }
510
511  _Chain_Extract_unprotected( &the_thread->Object.Node );
512
513  if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
514    _ISR_Enable( level );
515  } else {
516    _Watchdog_Deactivate( &the_thread->Timer );
517    _ISR_Enable( level );
518    (void) _Watchdog_Remove( &the_thread->Timer );
519  }
520
521  _Thread_Unblock( the_thread );
522
523  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
524    _Thread_MP_Free_proxy( the_thread );
525 
526}
527
528/*PAGE
529 *
530 *  _Thread_queue_First_fifo
531 *
532 *  This routines returns a pointer to the first thread on the
533 *  specified threadq.
534 *
535 *  Input parameters:
536 *    the_thread_queue - pointer to threadq
537 *
538 *  Output parameters:
539 *    returns - first thread or NULL
540 */
541
542Thread_Control *_Thread_queue_First_fifo(
543  Thread_queue_Control *the_thread_queue
544)
545{
546  if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) )
547    return (Thread_Control *) the_thread_queue->Queues.Fifo.first;
548
549  return NULL;
550}
551
552/*PAGE
553 *
554 *  _Thread_queue_Enqueue_priority
555 *
556 *  This routine blocks a thread, places it on a thread, and optionally
557 *  starts a timeout timer.
558 *
559 *  Input parameters:
560 *    the_thread_queue - pointer to threadq
561 *    thread           - thread to insert
562 *    timeout          - timeout interval in ticks
563 *
564 *  Output parameters: NONE
565 *
566 *  INTERRUPT LATENCY:
567 *    forward less than
568 *    forward equal
569 */
570
571void _Thread_queue_Enqueue_priority(
572  Thread_queue_Control *the_thread_queue,
573  Thread_Control       *the_thread,
574  Watchdog_Interval     timeout
575)
576{
577  Priority_Control     search_priority;
578  Thread_Control      *search_thread;
579  ISR_Level            level;
580  Chain_Control       *header;
581  unsigned32           header_index;
582  Chain_Node          *the_node;
583  Chain_Node          *next_node;
584  Chain_Node          *previous_node;
585  Chain_Node          *search_node;
586  Priority_Control     priority;
587  States_Control       block_state;
588  Thread_queue_States  sync_state;
589
590  _Chain_Initialize_empty( &the_thread->Wait.Block2n );
591
592  priority     = the_thread->current_priority;
593  header_index = _Thread_queue_Header_number( priority );
594  header       = &the_thread_queue->Queues.Priority[ header_index ];
595  block_state  = the_thread_queue->state;
596
597  if ( _Thread_queue_Is_reverse_search( priority ) )
598    goto restart_reverse_search;
599
600restart_forward_search:
601  search_priority = PRIORITY_MINIMUM - 1;
602  _ISR_Disable( level );
603  search_thread = (Thread_Control *) header->first;
604  while ( !_Chain_Is_tail( header, (Chain_Node *)search_thread ) ) {
605    search_priority = search_thread->current_priority;
606    if ( priority <= search_priority )
607      break;
608
609#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
610    search_thread = (Thread_Control *) search_thread->Object.Node.next;
611    if ( _Chain_Is_tail( header, (Chain_Node *)search_thread ) )
612      break;
613    search_priority = search_thread->current_priority;
614    if ( priority <= search_priority )
615      break;
616#endif
617    _ISR_Flash( level );
618    if ( !_States_Are_set( search_thread->current_state, block_state) ) {
619      _ISR_Enable( level );
620      goto restart_forward_search;
621    }
622    search_thread =
623       (Thread_Control *)search_thread->Object.Node.next;
624  }
625
626  if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
627    goto synchronize;
628
629  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
630
631  if ( priority == search_priority )
632    goto equal_priority;
633
634  search_node   = (Chain_Node *) search_thread;
635  previous_node = search_node->previous;
636  the_node      = (Chain_Node *) the_thread;
637
638  the_node->next        = search_node;
639  the_node->previous    = previous_node;
640  previous_node->next   = the_node;
641  search_node->previous = the_node;
642  _ISR_Enable( level );
643  return;
644
645restart_reverse_search:
646  search_priority     = PRIORITY_MAXIMUM + 1;
647
648  _ISR_Disable( level );
649  search_thread = (Thread_Control *) header->last;
650  while ( !_Chain_Is_head( header, (Chain_Node *)search_thread ) ) {
651    search_priority = search_thread->current_priority;
652    if ( priority >= search_priority )
653      break;
654#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
655    search_thread = (Thread_Control *) search_thread->Object.Node.previous;
656    if ( _Chain_Is_head( header, (Chain_Node *)search_thread ) )
657      break;
658    search_priority = search_thread->current_priority;
659    if ( priority >= search_priority )
660      break;
661#endif
662    _ISR_Flash( level );
663    if ( !_States_Are_set( search_thread->current_state, block_state) ) {
664      _ISR_Enable( level );
665      goto restart_reverse_search;
666    }
667    search_thread = (Thread_Control *)
668                         search_thread->Object.Node.previous;
669  }
670
671  if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
672    goto synchronize;
673
674  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
675
676  if ( priority == search_priority )
677    goto equal_priority;
678
679  search_node = (Chain_Node *) search_thread;
680  next_node   = search_node->next;
681  the_node    = (Chain_Node *) the_thread;
682
683  the_node->next      = next_node;
684  the_node->previous  = search_node;
685  search_node->next   = the_node;
686  next_node->previous = the_node;
687  _ISR_Enable( level );
688  return;
689
690equal_priority:               /* add at end of priority group */
691  search_node   = _Chain_Tail( &search_thread->Wait.Block2n );
692  previous_node = search_node->previous;
693  the_node      = (Chain_Node *) the_thread;
694
695  the_node->next        = search_node;
696  the_node->previous    = previous_node;
697  previous_node->next   = the_node;
698  search_node->previous = the_node;
699  _ISR_Enable( level );
700  return;
701
702synchronize:
703
704  sync_state = the_thread_queue->sync_state;
705  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
706
707  switch ( sync_state ) {
708    case THREAD_QUEUE_SYNCHRONIZED:
709      /*
710       *  This should never happen.  It indicates that someone did not
711       *  enter a thread queue critical section.
712       */
713      break;
714 
715    case THREAD_QUEUE_NOTHING_HAPPENED:
716      /*
717       *  All of this was dealt with above.  This should never happen.
718       */
719      break;
720 
721    case THREAD_QUEUE_TIMEOUT:
722      the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
723      _ISR_Enable( level );
724      break;
725 
726    case THREAD_QUEUE_SATISFIED:
727      if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
728        _Watchdog_Deactivate( &the_thread->Timer );
729        _ISR_Enable( level );
730        (void) _Watchdog_Remove( &the_thread->Timer );
731      } else
732        _ISR_Enable( level );
733      break;
734  }
735 
736  /*
737   *  Global objects with thread queue's should not be operated on from an
738   *  ISR.  But the sync code still must allow short timeouts to be processed
739   *  correctly.
740   */
741 
742  _Thread_Unblock( the_thread );
743 
744  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
745    _Thread_MP_Free_proxy( the_thread );
746}
747
748/*PAGE
749 *
750 *  _Thread_queue_Dequeue_priority
751 *
752 *  This routine removes a thread from the specified PRIORITY based
753 *  threadq, unblocks it, and cancels its timeout timer.
754 *
755 *  Input parameters:
756 *    the_thread_queue - pointer to thread queue
757 *
758 *  Output parameters:
759 *    returns - thread dequeued or NULL
760 *
761 *  INTERRUPT LATENCY:
762 *    only case
763 */
764
765Thread_Control *_Thread_queue_Dequeue_priority(
766  Thread_queue_Control *the_thread_queue
767)
768{
769  unsigned32      index;
770  ISR_Level       level;
771  Thread_Control *the_thread = NULL;  /* just to remove warnings */
772  Thread_Control *new_first_thread;
773  Chain_Node     *new_first_node;
774  Chain_Node     *new_second_node;
775  Chain_Node     *last_node;
776  Chain_Node     *next_node;
777  Chain_Node     *previous_node;
778
779  _ISR_Disable( level );
780  for( index=0 ;
781       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
782       index++ ) {
783    if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) ) {
784      the_thread = (Thread_Control *)
785                    the_thread_queue->Queues.Priority[ index ].first;
786      goto dequeue;
787    }
788  }
789
790  switch ( the_thread_queue->sync_state ) {
791    case THREAD_QUEUE_SYNCHRONIZED:
792    case THREAD_QUEUE_SATISFIED:
793      _ISR_Enable( level );
794      return NULL;
795
796    case THREAD_QUEUE_NOTHING_HAPPENED:
797    case THREAD_QUEUE_TIMEOUT:
798      the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
799      _ISR_Enable( level );
800      return _Thread_Executing;
801  }
802
803dequeue:
804  new_first_node   = the_thread->Wait.Block2n.first;
805  new_first_thread = (Thread_Control *) new_first_node;
806  next_node        = the_thread->Object.Node.next;
807  previous_node    = the_thread->Object.Node.previous;
808
809  if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
810    last_node       = the_thread->Wait.Block2n.last;
811    new_second_node = new_first_node->next;
812
813    previous_node->next      = new_first_node;
814    next_node->previous      = new_first_node;
815    new_first_node->next     = next_node;
816    new_first_node->previous = previous_node;
817
818    if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
819                                                /* > two threads on 2-n */
820      new_second_node->previous =
821                _Chain_Head( &new_first_thread->Wait.Block2n );
822
823      new_first_thread->Wait.Block2n.first = new_second_node;
824      new_first_thread->Wait.Block2n.last  = last_node;
825
826      last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
827    }
828  } else {
829    previous_node->next = next_node;
830    next_node->previous = previous_node;
831  }
832
833  if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
834    _ISR_Enable( level );
835    _Thread_Unblock( the_thread );
836  } else {
837    _Watchdog_Deactivate( &the_thread->Timer );
838    _ISR_Enable( level );
839    (void) _Watchdog_Remove( &the_thread->Timer );
840    _Thread_Unblock( the_thread );
841  }
842
843  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
844    _Thread_MP_Free_proxy( the_thread );
845  return( the_thread );
846}
847
848/*PAGE
849 *
850 *  _Thread_queue_Extract_priority
851 *
852 *  This routine removes a specific thread from the specified threadq,
853 *  deletes any timeout, and unblocks the thread.
854 *
855 *  Input parameters:
856 *    the_thread_queue - pointer to a threadq header
857 *    the_thread       - pointer to a thread control block
858 *
859 *  Output parameters: NONE
860 *
861 *  INTERRUPT LATENCY:
862 *    EXTRACT_PRIORITY
863 */
864
865void _Thread_queue_Extract_priority(
866  Thread_queue_Control *the_thread_queue,
867  Thread_Control       *the_thread
868)
869{
870  ISR_Level              level;
871  Chain_Node     *the_node;
872  Chain_Node     *next_node;
873  Chain_Node     *previous_node;
874  Thread_Control *new_first_thread;
875  Chain_Node     *new_first_node;
876  Chain_Node     *new_second_node;
877  Chain_Node     *last_node;
878
879  the_node = (Chain_Node *) the_thread;
880  _ISR_Disable( level );
881  if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
882    next_node     = the_node->next;
883    previous_node = the_node->previous;
884
885    if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
886      new_first_node   = the_thread->Wait.Block2n.first;
887      new_first_thread = (Thread_Control *) new_first_node;
888      last_node        = the_thread->Wait.Block2n.last;
889      new_second_node  = new_first_node->next;
890
891      previous_node->next      = new_first_node;
892      next_node->previous      = new_first_node;
893      new_first_node->next     = next_node;
894      new_first_node->previous = previous_node;
895
896      if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
897                                          /* > two threads on 2-n */
898        new_second_node->previous =
899                  _Chain_Head( &new_first_thread->Wait.Block2n );
900        new_first_thread->Wait.Block2n.first = new_second_node;
901
902        new_first_thread->Wait.Block2n.last = last_node;
903        last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
904      }
905    } else {
906      previous_node->next = next_node;
907      next_node->previous = previous_node;
908    }
909
910    if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
911      _ISR_Enable( level );
912      _Thread_Unblock( the_thread );
913    } else {
914      _Watchdog_Deactivate( &the_thread->Timer );
915      _ISR_Enable( level );
916      (void) _Watchdog_Remove( &the_thread->Timer );
917      _Thread_Unblock( the_thread );
918    }
919
920    if ( !_Objects_Is_local_id( the_thread->Object.id ) )
921      _Thread_MP_Free_proxy( the_thread );
922  }
923  else
924    _ISR_Enable( level );
925}
926
927/*PAGE
928 *
929 *  _Thread_queue_First_priority
930 *
931 *  This routines returns a pointer to the first thread on the
932 *  specified threadq.
933 *
934 *  Input parameters:
935 *    the_thread_queue - pointer to thread queue
936 *
937 *  Output parameters:
938 *    returns - first thread or NULL
939 */
940
941Thread_Control *_Thread_queue_First_priority (
942  Thread_queue_Control *the_thread_queue
943)
944{
945  unsigned32 index;
946
947  for( index=0 ;
948       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
949       index++ ) {
950    if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) )
951      return (Thread_Control *)
952        the_thread_queue->Queues.Priority[ index ].first;
953  }
954  return NULL;
955}
Note: See TracBrowser for help on using the repository browser.