diff --git a/mbed-util/critical.h b/mbed-util/critical.h new file mode 100644 index 0000000..dc82cd5 --- /dev/null +++ b/mbed-util/critical.h @@ -0,0 +1,37 @@ +/* + * PackageLicenseDeclared: Apache-2.0 + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MBED_UTIL_CRITICAL_H__ +#define __MBED_UTIL_CRITICAL_H__ + +#ifdef __cplusplus + namespace mbed { + namespace util { + extern "C" { +#endif + +void critical_section_enter(); +void critical_section_exit(); + +#ifdef __cplusplus +} // extern "C" +} // namspace util +} // namespace mbed +#endif + + +#endif // __MBED_UTIL_CRITICAL_H__ diff --git a/source/critical.c b/source/critical.c new file mode 100644 index 0000000..803ce51 --- /dev/null +++ b/source/critical.c @@ -0,0 +1,46 @@ +/* + * PackageLicenseDeclared: Apache-2.0 + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include // uint32_t, UINT32_MAX +#include // NULL +#include "cmsis-core/core_generic.h" //__disable_irq, __enable_irq + +// Module include +#include "mbed-util/critical.h" + +static volatile uint32_t interruptEnableCounter = 0; +static volatile uint32_t critical_primask = 0; +const uint32_t invalid = 0xFFFFFFFEUL; +void critical_section_enter() +{ + /* sample the primask */ + if (!interruptEnableCounter) { + critical_primask = __get_PRIMASK(); + } + __disable_irq(); + /* not allowed to overflow the interruptEnableCounter. */ + if (interruptEnableCounter == UINT32_MAX) { + /* Generate a fault */ + ((void(*)(void))&invalid)(); + } + interruptEnableCounter++; +} + +void critical_section_exit() +{ + if (interruptEnableCounter) interruptEnableCounter--; + if (!interruptEnableCounter && !critical_primask) __enable_irq(); +} diff --git a/test/critical.cpp b/test/critical.cpp new file mode 100644 index 0000000..be66025 --- /dev/null +++ b/test/critical.cpp @@ -0,0 +1,55 @@ +/* + * PackageLicenseDeclared: Apache-2.0 + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmsis-core/core_generic.h" // __get_PRIMASK +#include "mbed/test_env.h" // MBED_HOSTTEST_* definitions +// Module include +#include "mbed-util/critical.h" + +void app_start(int argc, char *argv[]) +{ + MBED_HOSTTEST_TIMEOUT(5); + MBED_HOSTTEST_SELECT(default); + MBED_HOSTTEST_DESCRIPTION(mbed-util critical section test); + MBED_HOSTTEST_START("MBED_UTIL_CRITICAL"); + bool pass = false; + do { + // Check the current primask + uint32_t primask; + if ((primask = __get_PRIMASK()) != 0) break; + + // Test a single critical section + mbed::util::critical_section_enter(); + if ((primask = __get_PRIMASK()) == 0) break; + mbed::util::critical_section_exit(); + if ((primask = __get_PRIMASK()) != 0) break; + + // Test multiple nested critical sections + for (int i = 0; i < 16; i++) { + mbed::util::critical_section_enter(); + } + if ((primask = __get_PRIMASK()) == 0) break; + for (int i = 0; i < 16; i++) { + mbed::util::critical_section_exit(); + } + if ((primask = __get_PRIMASK()) != 0) break; + + pass = true; + } while (0); + + MBED_HOSTTEST_RESULT(pass); +}