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

4.10
Last change on this file since e3f6d35 was b50468c, checked in by Gedare Bloom <gedare@…>, on 12/21/17 at 18:04:50

score: add Inherited_priorities priority queue and functions

Adds enqueue, dequeue, requeue, evaluate, and release functions
for the thread priority node priority queue of inherited priorities.
Add calls to these functions as needed to maintain the priority
queue due to blocking, unblocking, and priority changes.

Closes #3359.

  • Property mode set to 100644
File size: 6.5 KB
Line 
1/*
2 *  Mutex Handler
3 *
4 *  DESCRIPTION:
5 *
6 *  This package is the implementation of the Mutex Handler.
7 *  This handler provides synchronization and mutual exclusion capabilities.
8 *
9 *  COPYRIGHT (c) 1989-2006.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.com/license/LICENSE.
15 *
16 *  $Id$
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <rtems/system.h>
24#include <rtems/score/isr.h>
25#include <rtems/score/coremutex.h>
26#include <rtems/score/states.h>
27#include <rtems/score/thread.h>
28#include <rtems/score/threadq.h>
29
30/*
31 *  _CORE_mutex_Surrender
32 *
33 *  DESCRIPTION:
34 *
35 *  This routine frees a unit to the mutex.  If a task was blocked waiting for
36 *  a unit from this mutex, then that task will be readied and the unit
37 *  given to that task.  Otherwise, the unit will be returned to the mutex.
38 *
39 *  Input parameters:
40 *    the_mutex            - the mutex to be flushed
41 *    id                   - id of parent mutex
42 *    api_mutex_mp_support - api dependent MP support actions
43 *
44 *  Output parameters:
45 *    CORE_MUTEX_STATUS_SUCCESSFUL - if successful
46 *    core error code              - if unsuccessful
47 */
48
49CORE_mutex_Status _CORE_mutex_Surrender(
50  CORE_mutex_Control                *the_mutex,
51#if defined(RTEMS_MULTIPROCESSING)
52  Objects_Id                         id,
53  CORE_mutex_API_mp_support_callout  api_mutex_mp_support
54#else
55  Objects_Id                         id __attribute__((unused)),
56  CORE_mutex_API_mp_support_callout  api_mutex_mp_support __attribute__((unused))
57#endif
58)
59{
60  Thread_Control *the_thread;
61  Thread_Control *holder;
62#ifdef __RTEMS_STRICT_ORDER_MUTEX__
63  Chain_Node *first_node;
64#endif
65  holder    = the_mutex->holder;
66
67  /*
68   *  The following code allows a thread (or ISR) other than the thread
69   *  which acquired the mutex to release that mutex.  This is only
70   *  allowed when the mutex in quetion is FIFO or simple Priority
71   *  discipline.  But Priority Ceiling or Priority Inheritance mutexes
72   *  must be released by the thread which acquired them.
73   */
74
75  if ( the_mutex->Attributes.only_owner_release ) {
76    if ( !_Thread_Is_executing( holder ) )
77      return CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE;
78  }
79
80  /* XXX already unlocked -- not right status */
81
82  if ( !the_mutex->nest_count )
83    return CORE_MUTEX_STATUS_SUCCESSFUL;
84
85  the_mutex->nest_count--;
86
87  if ( the_mutex->nest_count != 0 ) {
88    /*
89     *  All error checking is on the locking side, so if the lock was
90     *  allowed to acquired multiple times, then we should just deal with
91     *  that.  The RTEMS_DEBUG is just a validation.
92     */
93    #if defined(RTEMS_DEBUG)
94      switch ( the_mutex->Attributes.lock_nesting_behavior ) {
95        case CORE_MUTEX_NESTING_ACQUIRES:
96          return CORE_MUTEX_STATUS_SUCCESSFUL;
97        case CORE_MUTEX_NESTING_IS_ERROR:
98          /* should never occur */
99          return CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED;
100        case CORE_MUTEX_NESTING_BLOCKS:
101          /* Currently no API exercises this behavior. */
102          break;
103      }
104    #else
105      /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */
106      return CORE_MUTEX_STATUS_SUCCESSFUL;
107    #endif
108  }
109
110  /*
111   *  Formally release the mutex before possibly transferring it to a
112   *  blocked thread.
113   */
114  if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ||
115       _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ){
116#ifdef __RTEMS_STRICT_ORDER_MUTEX__
117    /*Check whether the holder release the mutex in LIFO order
118      if not return error code*/
119    if(holder->lock_mutex.first != &the_mutex->queue.lock_queue){
120      the_mutex->nest_count++;
121      return CORE_MUTEX_RELEASE_NOT_ORDER;
122    }
123    first_node = _Chain_Get_first_unprotected(&holder->lock_mutex);
124#endif
125    holder->resource_count--;
126  }
127  if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) {
128    _Thread_Release_inherited_priority( the_mutex );
129  }
130  the_mutex->holder    = NULL;
131  the_mutex->holder_id = 0;
132
133  /*
134   *  Whether or not someone is waiting for the mutex, an
135   *  inherited priority must be lowered if this is the last
136   *  mutex (i.e. resource) this task has.
137   */
138  if ( _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
139#ifdef __RTEMS_STRICT_ORDER_MUTEX__
140    if(the_mutex->queue.priority_before != holder->Priority_node.current_priority)
141      _Thread_Change_priority(holder,the_mutex->queue.priority_before,true);
142#endif
143    if ( holder->resource_count == 0 &&
144         holder->Priority_node.real_priority != holder->Priority_node.current_priority ) {
145      _Thread_Change_priority( holder, holder->Priority_node.real_priority, true );
146    }
147  }
148
149  /*
150   *  Now we check if another thread was waiting for this mutex.  If so,
151   *  transfer the mutex to that thread.
152   */
153  if ( ( the_thread = _Thread_queue_Dequeue( &the_mutex->Wait_queue ) ) ) {
154
155#if defined(RTEMS_MULTIPROCESSING)
156    if ( !_Objects_Is_local_id( the_thread->Object.id ) ) {
157
158      the_mutex->holder     = NULL;
159      the_mutex->holder_id  = the_thread->Object.id;
160      the_mutex->nest_count = 1;
161
162      ( *api_mutex_mp_support)( the_thread, id );
163
164    } else
165#endif
166    {
167
168      the_mutex->holder     = the_thread;
169      the_mutex->holder_id  = the_thread->Object.id;
170      the_mutex->nest_count = 1;
171
172      switch ( the_mutex->Attributes.discipline ) {
173        case CORE_MUTEX_DISCIPLINES_FIFO:
174        case CORE_MUTEX_DISCIPLINES_PRIORITY:
175          break;
176        case CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT:
177#ifdef __RTEMS_STRICT_ORDER_MUTEX__
178          _Chain_Prepend_unprotected(&the_thread->lock_mutex,&the_mutex->queue.lock_queue);
179          the_mutex->queue.priority_before = the_thread->Priority_node.current_priority;
180#endif
181          the_thread->resource_count++;
182          break;
183        case CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING:
184#ifdef __RTEMS_STRICT_ORDER_MUTEX__
185          _Chain_Prepend_unprotected(&the_thread->lock_mutex,&the_mutex->queue.lock_queue);
186          the_mutex->queue.priority_before = the_thread->Priority_node.current_priority;
187#endif
188          the_thread->resource_count++;
189          if (the_mutex->Attributes.priority_ceiling <
190              the_thread->Priority_node.current_priority){
191              _Thread_Change_priority(
192                the_thread,
193                the_mutex->Attributes.priority_ceiling,
194                false
195              );
196          }
197          break;
198      }
199    }
200  } else
201    the_mutex->lock = CORE_MUTEX_UNLOCKED;
202
203  return CORE_MUTEX_STATUS_SUCCESSFUL;
204}
Note: See TracBrowser for help on using the repository browser.