source: rtems/cpukit/score/src/threadqextractpriority.c @ e3f6d35

4.10
Last change on this file since e3f6d35 was e3f6d35, checked in by Gedare Bloom <gedare@…>, on Jan 2, 2020 at 10:45:30 PM

cpukit/score: avoid NULL and races in priority mutex

The PIP modifications from #3359 introduced new data structures
to track priority inheritance. Prioritized mutexes without PIP
share some of the code paths, and may result in NULL pointer
accesses. This patch checks for NULL, and also adds ISR critical
sections to an uncovered corner case during thread restarts.

Closes #3829.

  • Property mode set to 100644
File size: 3.5 KB
Line 
1/*
2 *  Thread Queue Handler
3 *
4 *
5 *  COPYRIGHT (c) 1989-2008.
6 *  On-Line Applications Research Corporation (OAR).
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *  $Id$
13 */
14
15#if HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <rtems/system.h>
20#include <rtems/score/chain.h>
21#include <rtems/score/coremutex.h>
22#include <rtems/score/isr.h>
23#include <rtems/score/object.h>
24#include <rtems/score/states.h>
25#include <rtems/score/thread.h>
26#include <rtems/score/threadq.h>
27#include <rtems/score/tqdata.h>
28
29/*PAGE
30 *
31 *  _Thread_queue_Extract_priority
32 *
33 *  This routine removes a specific thread from the specified threadq,
34 *  deletes any timeout, and unblocks the thread.
35 *
36 *  Input parameters:
37 *    the_thread_queue - pointer to a threadq header
38 *    the_thread       - pointer to a thread control block
39 *    requeuing        - true if requeuing and should not alter timeout or state
40 *
41 *  Output parameters: NONE
42 *
43 *  INTERRUPT LATENCY:
44 *    EXTRACT_PRIORITY
45 */
46
47bool _Thread_queue_Extract_priority_helper(
48  Thread_queue_Control *the_thread_queue __attribute__((unused)),
49  Thread_Control       *the_thread,
50  bool                  requeuing
51)
52{
53  ISR_Level       level;
54  Chain_Node     *the_node;
55  Chain_Node     *next_node;
56  Chain_Node     *previous_node;
57  Thread_Control *new_first_thread;
58  Chain_Node     *new_first_node;
59  Chain_Node     *new_second_node;
60  Chain_Node     *last_node;
61  CORE_mutex_Control *mutex;
62
63  the_node = (Chain_Node *) the_thread;
64  _ISR_Disable( level );
65  if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
66    _ISR_Enable( level );
67    return false;
68  }
69
70  /*
71   *  The thread was actually waiting on a thread queue so let's remove it.
72   */
73
74  next_node     = the_node->next;
75  previous_node = the_node->previous;
76
77  if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
78    new_first_node   = the_thread->Wait.Block2n.first;
79    new_first_thread = (Thread_Control *) new_first_node;
80    last_node        = the_thread->Wait.Block2n.last;
81    new_second_node  = new_first_node->next;
82
83    previous_node->next      = new_first_node;
84    next_node->previous      = new_first_node;
85    new_first_node->next     = next_node;
86    new_first_node->previous = previous_node;
87
88    if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
89                                        /* > two threads on 2-n */
90      new_second_node->previous =
91                _Chain_Head( &new_first_thread->Wait.Block2n );
92      new_first_thread->Wait.Block2n.first = new_second_node;
93
94      new_first_thread->Wait.Block2n.last = last_node;
95      last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
96    }
97  } else {
98    previous_node->next = next_node;
99    next_node->previous = previous_node;
100  }
101
102  /*
103   *  If we are not supposed to touch timers or the thread's state, return.
104   */
105
106  if ( requeuing ) {
107    _ISR_Enable( level );
108    return true;
109  }
110
111  mutex = _Thread_Dequeue_priority_node( &the_thread->Priority_node );
112  if ( mutex != NULL ) {
113    _Thread_Evaluate_priority( mutex->holder );
114  }
115
116  if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
117    _ISR_Enable( level );
118  } else {
119    _Watchdog_Deactivate( &the_thread->Timer );
120    _ISR_Enable( level );
121    (void) _Watchdog_Remove( &the_thread->Timer );
122  }
123  _Thread_Unblock( the_thread );
124
125#if defined(RTEMS_MULTIPROCESSING)
126  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
127    _Thread_MP_Free_proxy( the_thread );
128#endif
129
130  return true;
131}
Note: See TracBrowser for help on using the repository browser.