Skip to content

Commit 07a394e

Browse files
author
Steven Cartmell
committed
Add Critical Section HAL API specification
- Define header functions for Critical Section HAL API - hal_critical_section_enter() - hal_critical_section_exit() - Add weak default implementation for HAL API. The default implementation matches the previous behaviour stored in mbed_critical: - The first call to enter a critical section stores the state of interrupts before disabling and each successive call re-disables interrupts. - The last call (non-nested) will restore the IRQ state that was set on the enter to the critical section. Nested calls are ignored. - Add function 'core_util_in_critical_section' to User facing API to determine if the program is currently in a critical section, instead of depending on 'core_util_interrupts_enabled'.
1 parent af9e073 commit 07a394e

File tree

4 files changed

+164
-41
lines changed

4 files changed

+164
-41
lines changed

hal/critical_section_api.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/** \addtogroup hal */
2+
/** @{*/
3+
/* mbed Microcontroller Library
4+
* Copyright (c) 2006-2017 ARM Limited
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
#ifndef MBED_CRITICAL_SECTION_API_H
19+
#define MBED_CRITICAL_SECTION_API_H
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
25+
/**
26+
* \defgroup hal_critical Critical Section HAL functions
27+
* @{
28+
*/
29+
30+
/**
31+
* Mark the start of a critical section
32+
*
33+
* This function is called directly by core_util_critical_section_enter on
34+
* first entrance to a critical section.
35+
*
36+
* The default behavior of this function is to save the current state of
37+
* interrupts before disabling them.
38+
*
39+
* The function is only called once per critical section by
40+
* core_util_critical_section_enter. When implementing this function for a
41+
* platform you must store any state that you intend to alter within this
42+
* function so it can be restored when exiting the critical section.
43+
*
44+
*/
45+
void hal_critical_section_enter(void);
46+
47+
/** Mark the end of a critical section
48+
*
49+
* This function is called directly by core_util_critical_section_exit on the
50+
* final exit from a critical section.
51+
*
52+
* The default behavior of this function is to restore the state of interrupts
53+
* as they were prior to entering this critical section.
54+
*
55+
* This function is only called once per critical section. When implemented
56+
* for a specific platform it must restore any state that was saved upon
57+
* entering the current critical section.
58+
*
59+
*/
60+
void hal_critical_section_exit(void);
61+
62+
/**@}*/
63+
64+
#ifdef __cplusplus
65+
}
66+
#endif
67+
68+
#endif // MBED_CRITICAL_SECTION_API_H
69+
70+
/** @}*/

hal/mbed_critical_section_api.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "cmsis.h"
17+
#include "hal/critical_section_api.h"
18+
#include "platform/mbed_assert.h"
19+
#include "platform/mbed_toolchain.h"
20+
21+
#include <stdbool.h>
22+
23+
static volatile bool critical_interrupts_enabled = false;
24+
25+
static bool are_interrupts_enabled(void)
26+
{
27+
#if defined(__CORTEX_A9)
28+
return ((__get_CPSR() & 0x80) == 0);
29+
#else
30+
return ((__get_PRIMASK() & 0x1) == 0);
31+
#endif
32+
}
33+
34+
35+
MBED_WEAK void hal_critical_section_enter(void)
36+
{
37+
critical_interrupts_enabled = are_interrupts_enabled();
38+
39+
#ifndef FEATURE_UVISOR
40+
// If we are in a nested critical section and interrupts are still enabled
41+
// something has gone wrong.
42+
MBED_ASSERT(!are_interrupts_enabled());
43+
#else
44+
#warning "core_util_critical_section_enter needs fixing to work from unprivileged code"
45+
#endif /* FEATURE_UVISOR */
46+
47+
__disable_irq();
48+
}
49+
50+
51+
MBED_WEAK void hal_critical_section_exit()
52+
{
53+
// FIXME
54+
#ifndef FEATURE_UVISOR
55+
// Interrupts must be disabled on invoking an exit from a critical section
56+
MBED_ASSERT(!are_interrupts_enabled());
57+
#else
58+
#warning "core_util_critical_section_exit needs fixing to work from unprivileged code"
59+
#endif /* FEATURE_UVISOR */
60+
61+
// Restore the IRQs to their state prior to entering the critical section
62+
if (critical_interrupts_enabled == true) {
63+
__enable_irq();
64+
}
65+
}

platform/mbed_critical.c

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717

1818
/* Declare __STDC_LIMIT_MACROS so stdint.h defines UINT32_MAX when using C++ */
1919
#define __STDC_LIMIT_MACROS
20-
#include "platform/mbed_critical.h"
20+
#include "hal/critical_section_api.h"
2121

2222
#include "cmsis.h"
2323
#include "platform/mbed_assert.h"
24+
#include "platform/mbed_critical.h"
2425
#include "platform/mbed_toolchain.h"
2526

26-
static volatile uint32_t interrupt_enable_counter = 0;
27-
static volatile bool critical_interrupts_disabled = false;
27+
static volatile uint32_t critical_section_reentrancy_counter = 0;
2828

2929
bool core_util_are_interrupts_enabled(void)
3030
{
@@ -51,53 +51,34 @@ bool core_util_is_isr_active(void)
5151
#endif
5252
}
5353

54-
MBED_WEAK void core_util_critical_section_enter(void)
54+
bool core_util_in_critical_section(void)
5555
{
56-
bool interrupts_disabled = !core_util_are_interrupts_enabled();
57-
__disable_irq();
56+
return (critical_section_reentrancy_counter != 0);
57+
}
5858

59-
/* Save the interrupt disabled state as it was prior to any nested critical section lock use */
60-
if (!interrupt_enable_counter) {
61-
critical_interrupts_disabled = interrupts_disabled;
62-
}
59+
void core_util_critical_section_enter(void)
60+
{
61+
// If the reentrancy counter overflows something has gone badly wrong.
62+
MBED_ASSERT(critical_section_reentrancy_counter < UINT32_MAX);
6363

64-
/* If the interrupt_enable_counter overflows or we are in a nested critical section and interrupts
65-
are enabled, then something has gone badly wrong thus assert an error.
66-
*/
67-
MBED_ASSERT(interrupt_enable_counter < UINT32_MAX);
68-
// FIXME
69-
#ifndef FEATURE_UVISOR
70-
if (interrupt_enable_counter > 0) {
71-
MBED_ASSERT(interrupts_disabled);
64+
if (critical_section_reentrancy_counter == 0) {
65+
hal_critical_section_enter();
7266
}
73-
#else
74-
#warning "core_util_critical_section_enter needs fixing to work from unprivileged code"
75-
#endif /* FEATURE_UVISOR */
76-
interrupt_enable_counter++;
67+
68+
critical_section_reentrancy_counter++;
7769
}
7870

79-
MBED_WEAK void core_util_critical_section_exit(void)
71+
void core_util_critical_section_exit(void)
8072
{
81-
/* If critical_section_enter has not previously been called, do nothing */
82-
if (interrupt_enable_counter) {
83-
84-
// FIXME
85-
#ifndef FEATURE_UVISOR
86-
bool interrupts_disabled = !core_util_are_interrupts_enabled(); /* get the current interrupt disabled state */
87-
88-
MBED_ASSERT(interrupts_disabled); /* Interrupts must be disabled on invoking an exit from a critical section */
89-
#else
90-
#warning "core_util_critical_section_exit needs fixing to work from unprivileged code"
91-
#endif /* FEATURE_UVISOR */
73+
// If critical_section_enter has not previously been called, do nothing
74+
if (critical_section_reentrancy_counter == 0) {
75+
return;
76+
}
9277

93-
interrupt_enable_counter--;
78+
critical_section_reentrancy_counter--;
9479

95-
/* Only re-enable interrupts if we are exiting the last of the nested critical sections and
96-
interrupts were enabled on entry to the first critical section.
97-
*/
98-
if (!interrupt_enable_counter && !critical_interrupts_disabled) {
99-
__enable_irq();
100-
}
80+
if (critical_section_reentrancy_counter == 0) {
81+
hal_critical_section_exit();
10182
}
10283
}
10384

platform/mbed_critical.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ void core_util_critical_section_enter(void);
8282
*/
8383
void core_util_critical_section_exit(void);
8484

85+
/**
86+
* Determine if we are currently in a critical section
87+
*
88+
* @return true if in a critical section, false otherwise.
89+
*/
90+
bool core_util_in_critical_section(void);
91+
8592
/**
8693
* Atomic compare and set. It compares the contents of a memory location to a
8794
* given value and, only if they are the same, modifies the contents of that

0 commit comments

Comments
 (0)