source: rtems/c/src/exec/score/src/threadq.c @ 391f6628

4.104.114.84.95
Last change on this file since 391f6628 was 391f6628, checked in by Joel Sherrill <joel.sherrill@…>, on 02/13/96 at 15:38:37

more comments added and existing ones cleaned up in synchronization paths

  • Property mode set to 100644
File size: 25.7 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      /*
331       *  If the_thread_queue is not synchronized, then it is either
332       *  "nothing happened", "timeout", or "satisfied".   If the_thread
333       *  is the executing thread, then it is in the process of blocking
334       *  and it is the thread which is responsible for the synchronization
335       *  process.
336       *
337       *  If it is not satisfied, then it is "nothing happened" and
338       *  this is the "timeout" transition.  After a request is satisfied,
339       *  a timeout is not allowed to occur.
340       */
341
342      if ( the_thread_queue->sync_state != THREAD_QUEUE_SYNCHRONIZED &&
343           _Thread_Is_executing( the_thread ) ) {
344        if ( the_thread_queue->sync_state != THREAD_QUEUE_SATISFIED )
345          the_thread_queue->sync_state = THREAD_QUEUE_TIMEOUT;
346      } else {
347        the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
348        _Thread_queue_Extract( the_thread->Wait.queue, the_thread );
349      }
350      _Thread_Unnest_dispatch();
351      break;
352  }
353}
354
355/*PAGE
356 *
357 *  _Thread_queue_Enqueue_fifo
358 *
359 *  This routine blocks a thread, places it on a thread, and optionally
360 *  starts a timeout timer.
361 *
362 *  Input parameters:
363 *    the_thread_queue - pointer to threadq
364 *    the_thread       - pointer to the thread to block
365 *    timeout          - interval to wait
366 *
367 *  Output parameters: NONE
368 *
369 *  INTERRUPT LATENCY:
370 *    only case
371 */
372
373void _Thread_queue_Enqueue_fifo (
374  Thread_queue_Control *the_thread_queue,
375  Thread_Control       *the_thread,
376  Watchdog_Interval    timeout
377)
378{
379  ISR_Level            level;
380  Thread_queue_States  sync_state;
381
382  _ISR_Disable( level );
383
384  sync_state = the_thread_queue->sync_state;
385  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
386
387  switch ( sync_state ) {
388    case THREAD_QUEUE_SYNCHRONIZED:
389      /*
390       *  This should never happen.  It indicates that someone did not
391       *  enter a thread queue critical section.
392       */
393      break;
394
395    case THREAD_QUEUE_NOTHING_HAPPENED:
396      _Chain_Append_unprotected(
397        &the_thread_queue->Queues.Fifo,
398        &the_thread->Object.Node
399      );
400      _ISR_Enable( level );
401      return;
402
403    case THREAD_QUEUE_TIMEOUT:
404      the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
405      _ISR_Enable( level );
406      break;
407
408    case THREAD_QUEUE_SATISFIED:
409      if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
410        _Watchdog_Deactivate( &the_thread->Timer );
411        _ISR_Enable( level );
412        (void) _Watchdog_Remove( &the_thread->Timer );
413      } else
414        _ISR_Enable( level );
415      break;
416  }
417
418  /*
419   *  Global objects with thread queue's should not be operated on from an
420   *  ISR.  But the sync code still must allow short timeouts to be processed
421   *  correctly.
422   */
423
424  _Thread_Unblock( the_thread );
425
426  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
427    _Thread_MP_Free_proxy( the_thread );
428
429}
430
431/*PAGE
432 *
433 *  _Thread_queue_Dequeue_fifo
434 *
435 *  This routine removes a thread from the specified threadq.
436 *
437 *  Input parameters:
438 *    the_thread_queue - pointer to threadq
439 *
440 *  Output parameters:
441 *    returns - thread dequeued or NULL
442 *
443 *  INTERRUPT LATENCY:
444 *    check sync
445 *    FIFO
446 */
447
448Thread_Control *_Thread_queue_Dequeue_fifo(
449  Thread_queue_Control *the_thread_queue
450)
451{
452  ISR_Level              level;
453  Thread_Control *the_thread;
454
455  _ISR_Disable( level );
456  if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) {
457
458    the_thread = (Thread_Control *)
459       _Chain_Get_first_unprotected( &the_thread_queue->Queues.Fifo );
460
461    if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
462      _ISR_Enable( level );
463      _Thread_Unblock( the_thread );
464    } else {
465      _Watchdog_Deactivate( &the_thread->Timer );
466      _ISR_Enable( level );
467      (void) _Watchdog_Remove( &the_thread->Timer );
468      _Thread_Unblock( the_thread );
469    }
470
471    if ( !_Objects_Is_local_id( the_thread->Object.id ) )
472      _Thread_MP_Free_proxy( the_thread );
473
474    return the_thread;
475  }
476
477  switch ( the_thread_queue->sync_state ) {
478    case THREAD_QUEUE_SYNCHRONIZED:
479    case THREAD_QUEUE_SATISFIED:
480      _ISR_Enable( level );
481      return NULL;
482
483    case THREAD_QUEUE_NOTHING_HAPPENED:
484    case THREAD_QUEUE_TIMEOUT:
485      the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
486      _ISR_Enable( level );
487      return _Thread_Executing;
488  }
489  return NULL;                /* this is only to prevent warnings */
490}
491
492/*PAGE
493 *
494 *  _Thread_queue_Extract_fifo
495 *
496 *  This routine removes a specific thread from the specified threadq,
497 *  deletes any timeout, and unblocks the thread.
498 *
499 *  Input parameters:
500 *    the_thread_queue - pointer to a threadq header
501 *    the_thread       - pointer to the thread to block
502 *
503 *  Output parameters: NONE
504 *
505 *  INTERRUPT LATENCY:
506 *    EXTRACT_FIFO
507 */
508
509void _Thread_queue_Extract_fifo(
510  Thread_queue_Control *the_thread_queue,
511  Thread_Control       *the_thread
512)
513{
514  ISR_Level level;
515
516  _ISR_Disable( level );
517
518  if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
519    _ISR_Enable( level );
520    return;
521  }
522
523  _Chain_Extract_unprotected( &the_thread->Object.Node );
524
525  if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
526    _ISR_Enable( level );
527  } else {
528    _Watchdog_Deactivate( &the_thread->Timer );
529    _ISR_Enable( level );
530    (void) _Watchdog_Remove( &the_thread->Timer );
531  }
532
533  _Thread_Unblock( the_thread );
534
535  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
536    _Thread_MP_Free_proxy( the_thread );
537 
538}
539
540/*PAGE
541 *
542 *  _Thread_queue_First_fifo
543 *
544 *  This routines returns a pointer to the first thread on the
545 *  specified threadq.
546 *
547 *  Input parameters:
548 *    the_thread_queue - pointer to threadq
549 *
550 *  Output parameters:
551 *    returns - first thread or NULL
552 */
553
554Thread_Control *_Thread_queue_First_fifo(
555  Thread_queue_Control *the_thread_queue
556)
557{
558  if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) )
559    return (Thread_Control *) the_thread_queue->Queues.Fifo.first;
560
561  return NULL;
562}
563
564/*PAGE
565 *
566 *  _Thread_queue_Enqueue_priority
567 *
568 *  This routine blocks a thread, places it on a thread, and optionally
569 *  starts a timeout timer.
570 *
571 *  Input parameters:
572 *    the_thread_queue - pointer to threadq
573 *    thread           - thread to insert
574 *    timeout          - timeout interval in ticks
575 *
576 *  Output parameters: NONE
577 *
578 *  INTERRUPT LATENCY:
579 *    forward less than
580 *    forward equal
581 */
582
583void _Thread_queue_Enqueue_priority(
584  Thread_queue_Control *the_thread_queue,
585  Thread_Control       *the_thread,
586  Watchdog_Interval     timeout
587)
588{
589  Priority_Control     search_priority;
590  Thread_Control      *search_thread;
591  ISR_Level            level;
592  Chain_Control       *header;
593  unsigned32           header_index;
594  Chain_Node          *the_node;
595  Chain_Node          *next_node;
596  Chain_Node          *previous_node;
597  Chain_Node          *search_node;
598  Priority_Control     priority;
599  States_Control       block_state;
600  Thread_queue_States  sync_state;
601
602  _Chain_Initialize_empty( &the_thread->Wait.Block2n );
603
604  priority     = the_thread->current_priority;
605  header_index = _Thread_queue_Header_number( priority );
606  header       = &the_thread_queue->Queues.Priority[ header_index ];
607  block_state  = the_thread_queue->state;
608
609  if ( _Thread_queue_Is_reverse_search( priority ) )
610    goto restart_reverse_search;
611
612restart_forward_search:
613  search_priority = PRIORITY_MINIMUM - 1;
614  _ISR_Disable( level );
615  search_thread = (Thread_Control *) header->first;
616  while ( !_Chain_Is_tail( header, (Chain_Node *)search_thread ) ) {
617    search_priority = search_thread->current_priority;
618    if ( priority <= search_priority )
619      break;
620
621#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
622    search_thread = (Thread_Control *) search_thread->Object.Node.next;
623    if ( _Chain_Is_tail( header, (Chain_Node *)search_thread ) )
624      break;
625    search_priority = search_thread->current_priority;
626    if ( priority <= search_priority )
627      break;
628#endif
629    _ISR_Flash( level );
630    if ( !_States_Are_set( search_thread->current_state, block_state) ) {
631      _ISR_Enable( level );
632      goto restart_forward_search;
633    }
634    search_thread =
635       (Thread_Control *)search_thread->Object.Node.next;
636  }
637
638  if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
639    goto synchronize;
640
641  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
642
643  if ( priority == search_priority )
644    goto equal_priority;
645
646  search_node   = (Chain_Node *) search_thread;
647  previous_node = search_node->previous;
648  the_node      = (Chain_Node *) the_thread;
649
650  the_node->next        = search_node;
651  the_node->previous    = previous_node;
652  previous_node->next   = the_node;
653  search_node->previous = the_node;
654  _ISR_Enable( level );
655  return;
656
657restart_reverse_search:
658  search_priority     = PRIORITY_MAXIMUM + 1;
659
660  _ISR_Disable( level );
661  search_thread = (Thread_Control *) header->last;
662  while ( !_Chain_Is_head( header, (Chain_Node *)search_thread ) ) {
663    search_priority = search_thread->current_priority;
664    if ( priority >= search_priority )
665      break;
666#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
667    search_thread = (Thread_Control *) search_thread->Object.Node.previous;
668    if ( _Chain_Is_head( header, (Chain_Node *)search_thread ) )
669      break;
670    search_priority = search_thread->current_priority;
671    if ( priority >= search_priority )
672      break;
673#endif
674    _ISR_Flash( level );
675    if ( !_States_Are_set( search_thread->current_state, block_state) ) {
676      _ISR_Enable( level );
677      goto restart_reverse_search;
678    }
679    search_thread = (Thread_Control *)
680                         search_thread->Object.Node.previous;
681  }
682
683  if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
684    goto synchronize;
685
686  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
687
688  if ( priority == search_priority )
689    goto equal_priority;
690
691  search_node = (Chain_Node *) search_thread;
692  next_node   = search_node->next;
693  the_node    = (Chain_Node *) the_thread;
694
695  the_node->next      = next_node;
696  the_node->previous  = search_node;
697  search_node->next   = the_node;
698  next_node->previous = the_node;
699  _ISR_Enable( level );
700  return;
701
702equal_priority:               /* add at end of priority group */
703  search_node   = _Chain_Tail( &search_thread->Wait.Block2n );
704  previous_node = search_node->previous;
705  the_node      = (Chain_Node *) the_thread;
706
707  the_node->next        = search_node;
708  the_node->previous    = previous_node;
709  previous_node->next   = the_node;
710  search_node->previous = the_node;
711  _ISR_Enable( level );
712  return;
713
714synchronize:
715
716  sync_state = the_thread_queue->sync_state;
717  the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
718
719  switch ( sync_state ) {
720    case THREAD_QUEUE_SYNCHRONIZED:
721      /*
722       *  This should never happen.  It indicates that someone did not
723       *  enter a thread queue critical section.
724       */
725      break;
726 
727    case THREAD_QUEUE_NOTHING_HAPPENED:
728      /*
729       *  This should never happen.  All of this was dealt with above.
730       */
731      break;
732 
733    case THREAD_QUEUE_TIMEOUT:
734      the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
735      _ISR_Enable( level );
736      break;
737 
738    case THREAD_QUEUE_SATISFIED:
739      if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
740        _Watchdog_Deactivate( &the_thread->Timer );
741        _ISR_Enable( level );
742        (void) _Watchdog_Remove( &the_thread->Timer );
743      } else
744        _ISR_Enable( level );
745      break;
746  }
747 
748  /*
749   *  Global objects with thread queue's should not be operated on from an
750   *  ISR.  But the sync code still must allow short timeouts to be processed
751   *  correctly.
752   */
753 
754  _Thread_Unblock( the_thread );
755 
756  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
757    _Thread_MP_Free_proxy( the_thread );
758}
759
760/*PAGE
761 *
762 *  _Thread_queue_Dequeue_priority
763 *
764 *  This routine removes a thread from the specified PRIORITY based
765 *  threadq, unblocks it, and cancels its timeout timer.
766 *
767 *  Input parameters:
768 *    the_thread_queue - pointer to thread queue
769 *
770 *  Output parameters:
771 *    returns - thread dequeued or NULL
772 *
773 *  INTERRUPT LATENCY:
774 *    only case
775 */
776
777Thread_Control *_Thread_queue_Dequeue_priority(
778  Thread_queue_Control *the_thread_queue
779)
780{
781  unsigned32      index;
782  ISR_Level       level;
783  Thread_Control *the_thread = NULL;  /* just to remove warnings */
784  Thread_Control *new_first_thread;
785  Chain_Node     *new_first_node;
786  Chain_Node     *new_second_node;
787  Chain_Node     *last_node;
788  Chain_Node     *next_node;
789  Chain_Node     *previous_node;
790
791  _ISR_Disable( level );
792  for( index=0 ;
793       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
794       index++ ) {
795    if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) ) {
796      the_thread = (Thread_Control *)
797                    the_thread_queue->Queues.Priority[ index ].first;
798      goto dequeue;
799    }
800  }
801
802  switch ( the_thread_queue->sync_state ) {
803    case THREAD_QUEUE_SYNCHRONIZED:
804    case THREAD_QUEUE_SATISFIED:
805      _ISR_Enable( level );
806      return NULL;
807
808    case THREAD_QUEUE_NOTHING_HAPPENED:
809    case THREAD_QUEUE_TIMEOUT:
810      the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
811      _ISR_Enable( level );
812      return _Thread_Executing;
813  }
814
815dequeue:
816  new_first_node   = the_thread->Wait.Block2n.first;
817  new_first_thread = (Thread_Control *) new_first_node;
818  next_node        = the_thread->Object.Node.next;
819  previous_node    = the_thread->Object.Node.previous;
820
821  if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
822    last_node       = the_thread->Wait.Block2n.last;
823    new_second_node = new_first_node->next;
824
825    previous_node->next      = new_first_node;
826    next_node->previous      = new_first_node;
827    new_first_node->next     = next_node;
828    new_first_node->previous = previous_node;
829
830    if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
831                                                /* > two threads on 2-n */
832      new_second_node->previous =
833                _Chain_Head( &new_first_thread->Wait.Block2n );
834
835      new_first_thread->Wait.Block2n.first = new_second_node;
836      new_first_thread->Wait.Block2n.last  = last_node;
837
838      last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
839    }
840  } else {
841    previous_node->next = next_node;
842    next_node->previous = previous_node;
843  }
844
845  if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
846    _ISR_Enable( level );
847    _Thread_Unblock( the_thread );
848  } else {
849    _Watchdog_Deactivate( &the_thread->Timer );
850    _ISR_Enable( level );
851    (void) _Watchdog_Remove( &the_thread->Timer );
852    _Thread_Unblock( the_thread );
853  }
854
855  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
856    _Thread_MP_Free_proxy( the_thread );
857  return( the_thread );
858}
859
860/*PAGE
861 *
862 *  _Thread_queue_Extract_priority
863 *
864 *  This routine removes a specific thread from the specified threadq,
865 *  deletes any timeout, and unblocks the thread.
866 *
867 *  Input parameters:
868 *    the_thread_queue - pointer to a threadq header
869 *    the_thread       - pointer to a thread control block
870 *
871 *  Output parameters: NONE
872 *
873 *  INTERRUPT LATENCY:
874 *    EXTRACT_PRIORITY
875 */
876
877void _Thread_queue_Extract_priority(
878  Thread_queue_Control *the_thread_queue,
879  Thread_Control       *the_thread
880)
881{
882  ISR_Level              level;
883  Chain_Node     *the_node;
884  Chain_Node     *next_node;
885  Chain_Node     *previous_node;
886  Thread_Control *new_first_thread;
887  Chain_Node     *new_first_node;
888  Chain_Node     *new_second_node;
889  Chain_Node     *last_node;
890
891  the_node = (Chain_Node *) the_thread;
892  _ISR_Disable( level );
893  if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
894    next_node     = the_node->next;
895    previous_node = the_node->previous;
896
897    if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
898      new_first_node   = the_thread->Wait.Block2n.first;
899      new_first_thread = (Thread_Control *) new_first_node;
900      last_node        = the_thread->Wait.Block2n.last;
901      new_second_node  = new_first_node->next;
902
903      previous_node->next      = new_first_node;
904      next_node->previous      = new_first_node;
905      new_first_node->next     = next_node;
906      new_first_node->previous = previous_node;
907
908      if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
909                                          /* > two threads on 2-n */
910        new_second_node->previous =
911                  _Chain_Head( &new_first_thread->Wait.Block2n );
912        new_first_thread->Wait.Block2n.first = new_second_node;
913
914        new_first_thread->Wait.Block2n.last = last_node;
915        last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
916      }
917    } else {
918      previous_node->next = next_node;
919      next_node->previous = previous_node;
920    }
921
922    if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
923      _ISR_Enable( level );
924      _Thread_Unblock( the_thread );
925    } else {
926      _Watchdog_Deactivate( &the_thread->Timer );
927      _ISR_Enable( level );
928      (void) _Watchdog_Remove( &the_thread->Timer );
929      _Thread_Unblock( the_thread );
930    }
931
932    if ( !_Objects_Is_local_id( the_thread->Object.id ) )
933      _Thread_MP_Free_proxy( the_thread );
934  }
935  else
936    _ISR_Enable( level );
937}
938
939/*PAGE
940 *
941 *  _Thread_queue_First_priority
942 *
943 *  This routines returns a pointer to the first thread on the
944 *  specified threadq.
945 *
946 *  Input parameters:
947 *    the_thread_queue - pointer to thread queue
948 *
949 *  Output parameters:
950 *    returns - first thread or NULL
951 */
952
953Thread_Control *_Thread_queue_First_priority (
954  Thread_queue_Control *the_thread_queue
955)
956{
957  unsigned32 index;
958
959  for( index=0 ;
960       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
961       index++ ) {
962    if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) )
963      return (Thread_Control *)
964        the_thread_queue->Queues.Priority[ index ].first;
965  }
966  return NULL;
967}
Note: See TracBrowser for help on using the repository browser.