source: rtems-libbsd/rtemsbsd/include/machine/rtems-bsd-muteximpl.h @ eae664e

55-freebsd-126-freebsd-12
Last change on this file since eae664e was eae664e, checked in by Sebastian Huber <sebastian.huber@…>, on 03/12/18 at 13:38:46

mutex: Use panic() after ISR lock release

Using panic() with interrupts disabled could lead to an additional error
(INTERNAL_ERROR_BAD_THREAD_DISPATCH_ENVIRONMENT) due to a potentially
blocking output.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_machine
5 *
6 * @brief Implementation of a mutex with a simple priority inheritance
7 * protocol.
8 */
9
10/*
11 * Copyright (c) 2014, 2018 embedded brains GmbH.  All rights reserved.
12 *
13 *  embedded brains GmbH
14 *  Dornierstr. 4
15 *  82178 Puchheim
16 *  Germany
17 *  <rtems@embedded-brains.de>
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 *    notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 *    notice, this list of conditions and the following disclaimer in the
26 *    documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEXIMPL_H_
42#define _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEXIMPL_H_
43
44#include <machine/rtems-bsd-mutex.h>
45#include <machine/rtems-bsd-support.h>
46
47#include <sys/types.h>
48#include <sys/lock.h>
49#include <sys/systm.h>
50
51#include <inttypes.h>
52
53#include <rtems/score/threadimpl.h>
54#include <rtems/score/threadqimpl.h>
55
56#ifdef __cplusplus
57extern "C" {
58#endif /* __cplusplus */
59
60#define RTEMS_BSD_MUTEX_TQ_OPERATIONS \
61    &_Thread_queue_Operations_priority_inherit
62
63static inline void
64rtems_bsd_mutex_init(struct lock_object *lock, rtems_bsd_mutex *m,
65    struct lock_class *class, const char *name, const char *type, int flags)
66{
67        _Thread_queue_Initialize(&m->queue, name);
68        m->nest_level = 0;
69
70        lock_init(lock, class, name, type, flags);
71}
72
73void rtems_bsd_mutex_lock_more(struct lock_object *lock, rtems_bsd_mutex *m,
74    Thread_Control *owner, Thread_Control *executing,
75    Thread_queue_Context *queue_context);
76
77#define rtems_bsd_mutex_isr_disable(isr_level, queue_context)   \
78do {                                                            \
79        _ISR_Local_disable(isr_level);                          \
80        _ISR_lock_ISR_disable_profile(                          \
81              &(queue_context)->Lock_context.Lock_context)      \
82} while (0)
83
84static inline void
85rtems_bsd_mutex_acquire_critical(rtems_bsd_mutex *m,
86    Thread_queue_Context *queue_context)
87{
88
89        _Thread_queue_Queue_acquire_critical(&m->queue.Queue,
90            &m->queue.Lock_stats, &queue_context->Lock_context.Lock_context);
91#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
92        m->queue.owner = _SMP_lock_Who_am_I();
93#endif
94}
95
96static inline void
97rtems_bsd_mutex_release(rtems_bsd_mutex *m, ISR_Level isr_level,
98    Thread_queue_Context *queue_context)
99{
100
101#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
102        _Assert( _Thread_queue_Is_lock_owner( &m->queue ) );
103        m->queue.owner = SMP_LOCK_NO_OWNER;
104#endif
105        _Thread_queue_Queue_release_critical(&m->queue.Queue,
106            &queue_context->Lock_context.Lock_context);
107        _ISR_Local_enable(isr_level);
108}
109
110static inline void
111rtems_bsd_mutex_set_isr_level(Thread_queue_Context *queue_context,
112    ISR_Level isr_level)
113{
114
115        _ISR_lock_Context_set_level(&queue_context->Lock_context.Lock_context,
116            isr_level);
117}
118
119static inline void
120rtems_bsd_mutex_lock(struct lock_object *lock, rtems_bsd_mutex *m)
121{
122        ISR_Level isr_level;
123        Thread_queue_Context queue_context;
124        Thread_Control *executing;
125        Thread_Control *owner;
126
127        _Thread_queue_Context_initialize(&queue_context);
128        rtems_bsd_mutex_isr_disable(isr_level, &queue_context);
129        executing = _Thread_Executing;
130        rtems_bsd_mutex_acquire_critical(m, &queue_context);
131
132        owner = m->queue.Queue.owner;
133
134        if (__predict_true(owner == NULL)) {
135                m->queue.Queue.owner = executing;
136                _Thread_Resource_count_increment(executing);
137                rtems_bsd_mutex_release(m, isr_level, &queue_context);
138        } else {
139                rtems_bsd_mutex_set_isr_level(&queue_context, isr_level);
140                rtems_bsd_mutex_lock_more(lock, m, owner, executing,
141                    &queue_context);
142        }
143}
144
145static inline int
146rtems_bsd_mutex_trylock(struct lock_object *lock, rtems_bsd_mutex *m)
147{
148        int success;
149        ISR_Level isr_level;
150        Thread_queue_Context queue_context;
151        Thread_Control *executing;
152        Thread_Control *owner;
153
154        _Thread_queue_Context_initialize(&queue_context);
155        rtems_bsd_mutex_isr_disable(isr_level, &queue_context);
156        executing = _Thread_Executing;
157        rtems_bsd_mutex_acquire_critical(m, &queue_context);
158
159        owner = m->queue.Queue.owner;
160
161        if (owner == NULL) {
162                m->queue.Queue.owner = executing;
163                _Thread_Resource_count_increment(executing);
164                success = 1;
165        } else if (owner == executing) {
166                if ((lock->lo_flags & LO_RECURSABLE) == 0) {
167                        rtems_bsd_mutex_release(m, isr_level, &queue_context);
168                        panic("mutex trylock: %s: not LO_RECURSABLE\n",
169                            m->queue.Queue.name);
170                }
171
172                ++m->nest_level;
173                success = 1;
174        } else {
175                success = 0;
176        }
177
178        rtems_bsd_mutex_release(m, isr_level, &queue_context);
179
180        return (success);
181}
182
183static inline void
184rtems_bsd_mutex_unlock(rtems_bsd_mutex *m)
185{
186        ISR_Level isr_level;
187        Thread_queue_Context queue_context;
188        Thread_Control *owner;
189        Thread_Control *executing;
190        int nest_level;
191
192        _Thread_queue_Context_initialize(&queue_context);
193        rtems_bsd_mutex_isr_disable(isr_level, &queue_context);
194        rtems_bsd_mutex_acquire_critical(m, &queue_context);
195
196        nest_level = m->nest_level;
197        owner = m->queue.Queue.owner;
198        executing = _Thread_Executing;
199
200        if (__predict_false(owner != executing)) {
201                rtems_bsd_mutex_release(m, isr_level, &queue_context);
202                panic("mutex unlock: %s: owner 0x%08" PRIx32
203                    " != executing 0x%08" PRIx32 "\n", m->queue.Queue.name,
204                    owner->Object.id, executing->Object.id);
205        }
206
207        if (__predict_true(nest_level == 0)) {
208                Thread_queue_Heads *heads;
209
210                heads = m->queue.Queue.heads;
211                m->queue.Queue.owner = NULL;
212                _Thread_Resource_count_decrement(owner);
213
214                if (__predict_true(heads == NULL)) {
215                        rtems_bsd_mutex_release(m, isr_level, &queue_context);
216                } else {
217                        rtems_bsd_mutex_set_isr_level(&queue_context, isr_level);
218                        _Thread_queue_Surrender(&m->queue.Queue, heads, owner,
219                            &queue_context, RTEMS_BSD_MUTEX_TQ_OPERATIONS);
220                }
221        } else {
222                m->nest_level = nest_level - 1;
223                rtems_bsd_mutex_release(m, isr_level, &queue_context);
224        }
225}
226
227static inline Thread_Control *
228rtems_bsd_mutex_owner(const rtems_bsd_mutex *m)
229{
230
231        return (m->queue.Queue.owner);
232}
233
234static inline int
235rtems_bsd_mutex_owned(const rtems_bsd_mutex *m)
236{
237
238        return (rtems_bsd_mutex_owner(m) == _Thread_Get_executing());
239}
240
241static inline int
242rtems_bsd_mutex_recursed(const rtems_bsd_mutex *m)
243{
244
245        return (m->nest_level != 0);
246}
247
248static inline const char *
249rtems_bsd_mutex_name(const rtems_bsd_mutex *m)
250{
251
252        return (m->queue.Queue.name);
253}
254
255static inline void
256rtems_bsd_mutex_destroy(struct lock_object *lock, rtems_bsd_mutex *m)
257{
258        BSD_ASSERT(m->queue.Queue.heads == NULL);
259
260        if (rtems_bsd_mutex_owned(m)) {
261                m->nest_level = 0;
262                rtems_bsd_mutex_unlock(m);
263        }
264
265        _Thread_queue_Destroy(&m->queue);
266        lock_destroy(lock);
267}
268
269#ifdef __cplusplus
270}
271#endif /* __cplusplus */
272
273#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_MUTEXIMPL_H_ */
Note: See TracBrowser for help on using the repository browser.