mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_critical.h Source File

mbed_critical.h

00001 
00002 /*
00003  * Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
00004  * SPDX-License-Identifier: Apache-2.0
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00007  * not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  * http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00014  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 #ifndef __MBED_UTIL_CRITICAL_H__
00020 #define __MBED_UTIL_CRITICAL_H__
00021 
00022 #include <stdbool.h>
00023 #include <stdint.h>
00024 #include <stddef.h>
00025 
00026 #ifdef __cplusplus
00027 extern "C" {
00028 #endif
00029 
00030 /** \addtogroup platform */
00031 /** @{*/
00032 /**
00033  * \defgroup platform_critical critical section function
00034  * @{
00035  */
00036 
00037 /** Determine the current interrupts enabled state
00038   *
00039   * This function can be called to determine whether or not interrupts are currently enabled.
00040   * @note
00041   * NOTE:
00042   * This function works for both cortex-A and cortex-M, although the underlying implementation
00043   * differs.
00044   * @return true if interrupts are enabled, false otherwise
00045   */
00046 bool core_util_are_interrupts_enabled(void);
00047 
00048 /** Determine if this code is executing from an interrupt
00049   *
00050   * This function can be called to determine if the code is running on interrupt context.
00051   * @note
00052   * NOTE:
00053   * This function works for both cortex-A and cortex-M, although the underlying implementation
00054   * differs.
00055   * @return true if in an isr, false otherwise
00056   */
00057 bool core_util_is_isr_active(void);
00058 
00059 /** Mark the start of a critical section
00060   *
00061   * This function should be called to mark the start of a critical section of code.
00062   * @note
00063   * NOTES:
00064   * 1) The use of this style of critical section is targetted at C based implementations.
00065   * 2) These critical sections can be nested.
00066   * 3) The interrupt enable state on entry to the first critical section (of a nested set, or single
00067   *    section) will be preserved on exit from the section.
00068   * 4) This implementation will currently only work on code running in privileged mode.
00069   */
00070 void core_util_critical_section_enter(void);
00071 
00072 /** Mark the end of a critical section
00073   *
00074   * This function should be called to mark the end of a critical section of code.
00075   * @note
00076   * NOTES:
00077   * 1) The use of this style of critical section is targetted at C based implementations.
00078   * 2) These critical sections can be nested.
00079   * 3) The interrupt enable state on entry to the first critical section (of a nested set, or single
00080   *    section) will be preserved on exit from the section.
00081   * 4) This implementation will currently only work on code running in privileged mode.
00082   */
00083 void core_util_critical_section_exit(void);
00084 
00085 /**
00086  * Determine if we are currently in a critical section
00087  *
00088  * @return true if in a critical section, false otherwise.
00089  */
00090 bool core_util_in_critical_section(void);
00091 
00092 /**
00093  * A lock-free, primitive atomic flag.
00094  *
00095  * Emulate C11's atomic_flag. The flag is initially in an indeterminate state
00096  * unless explicitly initialized with CORE_UTIL_ATOMIC_FLAG_INIT.
00097  */
00098 typedef struct core_util_atomic_flag {
00099     uint8_t _flag;
00100 } core_util_atomic_flag;
00101 
00102 /**
00103  * Initializer for a core_util_atomic_flag.
00104  *
00105  * Example:
00106  * ~~~
00107  *     core_util_atomic_flag in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
00108  * ~~~
00109  */
00110 #define CORE_UTIL_ATOMIC_FLAG_INIT { 0 }
00111 
00112 /**
00113  * Atomic test and set.
00114  *
00115  * Atomically tests then sets the flag to true, returning the previous value.
00116  *
00117  * @param  flagPtr Target flag being tested and set.
00118  * @return         The previous value.
00119  */
00120 bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr);
00121 
00122 /**
00123  * Atomic clear.
00124  *
00125  * @param  flagPtr Target flag being cleared.
00126  */
00127 void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr);
00128 
00129 /**
00130  * Atomic compare and set. It compares the contents of a memory location to a
00131  * given value and, only if they are the same, modifies the contents of that
00132  * memory location to a given new value. This is done as a single atomic
00133  * operation. The atomicity guarantees that the new value is calculated based on
00134  * up-to-date information; if the value had been updated by another thread in
00135  * the meantime, the write would fail due to a mismatched expectedCurrentValue.
00136  *
00137  * Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
00138  * you to the article on compare-and swap].
00139  *
00140  * @param  ptr                  The target memory location.
00141  * @param[in,out] expectedCurrentValue A pointer to some location holding the
00142  *                              expected current value of the data being set atomically.
00143  *                              The computed 'desiredValue' should be a function of this current value.
00144  *                              @note: This is an in-out parameter. In the
00145  *                              failure case of atomic_cas (where the
00146  *                              destination isn't set), the pointee of expectedCurrentValue is
00147  *                              updated with the current value.
00148  * @param[in] desiredValue      The new value computed based on '*expectedCurrentValue'.
00149  *
00150  * @return                      true if the memory location was atomically
00151  *                              updated with the desired value (after verifying
00152  *                              that it contained the expectedCurrentValue),
00153  *                              false otherwise. In the failure case,
00154  *                              exepctedCurrentValue is updated with the new
00155  *                              value of the target memory location.
00156  *
00157  * pseudocode:
00158  * function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
00159  *     if *p != *old {
00160  *         *old = *p
00161  *         return false
00162  *     }
00163  *     *p = new
00164  *     return true
00165  * }
00166  *
00167  * @note: In the failure case (where the destination isn't set), the value
00168  * pointed to by expectedCurrentValue is instead updated with the current value.
00169  * This property helps writing concise code for the following incr:
00170  *
00171  * function incr(p : pointer to int, a : int) returns int {
00172  *     done = false
00173  *     value = *p // This fetch operation need not be atomic.
00174  *     while not done {
00175  *         done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
00176  *     }
00177  *     return value + a
00178  * }
00179  *
00180  * @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
00181  * always succeeds if the current value is expected, as per the pseudocode
00182  * above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
00183  */
00184 bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue);
00185 
00186 /**
00187  * Atomic compare and set. It compares the contents of a memory location to a
00188  * given value and, only if they are the same, modifies the contents of that
00189  * memory location to a given new value. This is done as a single atomic
00190  * operation. The atomicity guarantees that the new value is calculated based on
00191  * up-to-date information; if the value had been updated by another thread in
00192  * the meantime, the write would fail due to a mismatched expectedCurrentValue.
00193  *
00194  * Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
00195  * you to the article on compare-and swap].
00196  *
00197  * @param  ptr                  The target memory location.
00198  * @param[in,out] expectedCurrentValue A pointer to some location holding the
00199  *                              expected current value of the data being set atomically.
00200  *                              The computed 'desiredValue' should be a function of this current value.
00201  *                              @note: This is an in-out parameter. In the
00202  *                              failure case of atomic_cas (where the
00203  *                              destination isn't set), the pointee of expectedCurrentValue is
00204  *                              updated with the current value.
00205  * @param[in] desiredValue      The new value computed based on '*expectedCurrentValue'.
00206  *
00207  * @return                      true if the memory location was atomically
00208  *                              updated with the desired value (after verifying
00209  *                              that it contained the expectedCurrentValue),
00210  *                              false otherwise. In the failure case,
00211  *                              exepctedCurrentValue is updated with the new
00212  *                              value of the target memory location.
00213  *
00214  * pseudocode:
00215  * function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
00216  *     if *p != *old {
00217  *         *old = *p
00218  *         return false
00219  *     }
00220  *     *p = new
00221  *     return true
00222  * }
00223  *
00224  * @note: In the failure case (where the destination isn't set), the value
00225  * pointed to by expectedCurrentValue is instead updated with the current value.
00226  * This property helps writing concise code for the following incr:
00227  *
00228  * function incr(p : pointer to int, a : int) returns int {
00229  *     done = false
00230  *     value = *p // This fetch operation need not be atomic.
00231  *     while not done {
00232  *         done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
00233  *     }
00234  *     return value + a
00235  * }
00236  *
00237  * @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
00238  * always succeeds if the current value is expected, as per the pseudocode
00239  * above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
00240  */
00241 bool core_util_atomic_cas_u16(volatile uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue);
00242 
00243 /**
00244  * Atomic compare and set. It compares the contents of a memory location to a
00245  * given value and, only if they are the same, modifies the contents of that
00246  * memory location to a given new value. This is done as a single atomic
00247  * operation. The atomicity guarantees that the new value is calculated based on
00248  * up-to-date information; if the value had been updated by another thread in
00249  * the meantime, the write would fail due to a mismatched expectedCurrentValue.
00250  *
00251  * Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
00252  * you to the article on compare-and swap].
00253  *
00254  * @param  ptr                  The target memory location.
00255  * @param[in,out] expectedCurrentValue A pointer to some location holding the
00256  *                              expected current value of the data being set atomically.
00257  *                              The computed 'desiredValue' should be a function of this current value.
00258  *                              @note: This is an in-out parameter. In the
00259  *                              failure case of atomic_cas (where the
00260  *                              destination isn't set), the pointee of expectedCurrentValue is
00261  *                              updated with the current value.
00262  * @param[in] desiredValue      The new value computed based on '*expectedCurrentValue'.
00263  *
00264  * @return                      true if the memory location was atomically
00265  *                              updated with the desired value (after verifying
00266  *                              that it contained the expectedCurrentValue),
00267  *                              false otherwise. In the failure case,
00268  *                              exepctedCurrentValue is updated with the new
00269  *                              value of the target memory location.
00270  *
00271  * pseudocode:
00272  * function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
00273  *     if *p != *old {
00274  *         *old = *p
00275  *         return false
00276  *     }
00277  *     *p = new
00278  *     return true
00279  * }
00280  *
00281  * @note: In the failure case (where the destination isn't set), the value
00282  * pointed to by expectedCurrentValue is instead updated with the current value.
00283  * This property helps writing concise code for the following incr:
00284  *
00285  * function incr(p : pointer to int, a : int) returns int {
00286  *     done = false
00287  *     value = *p // This fetch operation need not be atomic.
00288  *     while not done {
00289  *         done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
00290  *     }
00291  *     return value + a
00292  *
00293  * @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
00294  * always succeeds if the current value is expected, as per the pseudocode
00295  * above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
00296  * }
00297  */
00298 bool core_util_atomic_cas_u32(volatile uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue);
00299 
00300 /**
00301  * Atomic compare and set. It compares the contents of a memory location to a
00302  * given value and, only if they are the same, modifies the contents of that
00303  * memory location to a given new value. This is done as a single atomic
00304  * operation. The atomicity guarantees that the new value is calculated based on
00305  * up-to-date information; if the value had been updated by another thread in
00306  * the meantime, the write would fail due to a mismatched expectedCurrentValue.
00307  *
00308  * Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
00309  * you to the article on compare-and swap].
00310  *
00311  * @param  ptr                  The target memory location.
00312  * @param[in,out] expectedCurrentValue A pointer to some location holding the
00313  *                              expected current value of the data being set atomically.
00314  *                              The computed 'desiredValue' should be a function of this current value.
00315  *                              @note: This is an in-out parameter. In the
00316  *                              failure case of atomic_cas (where the
00317  *                              destination isn't set), the pointee of expectedCurrentValue is
00318  *                              updated with the current value.
00319  * @param[in] desiredValue      The new value computed based on '*expectedCurrentValue'.
00320  *
00321  * @return                      true if the memory location was atomically
00322  *                              updated with the desired value (after verifying
00323  *                              that it contained the expectedCurrentValue),
00324  *                              false otherwise. In the failure case,
00325  *                              exepctedCurrentValue is updated with the new
00326  *                              value of the target memory location.
00327  *
00328  * pseudocode:
00329  * function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
00330  *     if *p != *old {
00331  *         *old = *p
00332  *         return false
00333  *     }
00334  *     *p = new
00335  *     return true
00336  * }
00337  *
00338  * @note: In the failure case (where the destination isn't set), the value
00339  * pointed to by expectedCurrentValue is instead updated with the current value.
00340  * This property helps writing concise code for the following incr:
00341  *
00342  * function incr(p : pointer to int, a : int) returns int {
00343  *     done = false
00344  *     value = *p // This fetch operation need not be atomic.
00345  *     while not done {
00346  *         done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
00347  *     }
00348  *     return value + a
00349  * }
00350  *
00351  * @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
00352  * always succeeds if the current value is expected, as per the pseudocode
00353  * above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
00354  */
00355 bool core_util_atomic_cas_ptr(void *volatile *ptr, void **expectedCurrentValue, void *desiredValue);
00356 
00357 /**
00358  * Atomic increment.
00359  * @param  valuePtr Target memory location being incremented.
00360  * @param  delta    The amount being incremented.
00361  * @return          The new incremented value.
00362  */
00363 uint8_t core_util_atomic_incr_u8(volatile uint8_t *valuePtr, uint8_t delta);
00364 
00365 /**
00366  * Atomic increment.
00367  * @param  valuePtr Target memory location being incremented.
00368  * @param  delta    The amount being incremented.
00369  * @return          The new incremented value.
00370  */
00371 uint16_t core_util_atomic_incr_u16(volatile uint16_t *valuePtr, uint16_t delta);
00372 
00373 /**
00374  * Atomic increment.
00375  * @param  valuePtr Target memory location being incremented.
00376  * @param  delta    The amount being incremented.
00377  * @return          The new incremented value.
00378  */
00379 uint32_t core_util_atomic_incr_u32(volatile uint32_t *valuePtr, uint32_t delta);
00380 
00381 /**
00382  * Atomic increment.
00383  * @param  valuePtr Target memory location being incremented.
00384  * @param  delta    The amount being incremented in bytes.
00385  * @return          The new incremented value.
00386  *
00387  * @note The type of the pointer argument is not taken into account
00388  *       and the pointer is incremented by bytes.
00389  */
00390 void *core_util_atomic_incr_ptr(void *volatile *valuePtr, ptrdiff_t delta);
00391 
00392 /**
00393  * Atomic decrement.
00394  * @param  valuePtr Target memory location being decremented.
00395  * @param  delta    The amount being decremented.
00396  * @return          The new decremented value.
00397  */
00398 uint8_t core_util_atomic_decr_u8(volatile uint8_t *valuePtr, uint8_t delta);
00399 
00400 /**
00401  * Atomic decrement.
00402  * @param  valuePtr Target memory location being decremented.
00403  * @param  delta    The amount being decremented.
00404  * @return          The new decremented value.
00405  */
00406 uint16_t core_util_atomic_decr_u16(volatile uint16_t *valuePtr, uint16_t delta);
00407 
00408 /**
00409  * Atomic decrement.
00410  * @param  valuePtr Target memory location being decremented.
00411  * @param  delta    The amount being decremented.
00412  * @return          The new decremented value.
00413  */
00414 uint32_t core_util_atomic_decr_u32(volatile uint32_t *valuePtr, uint32_t delta);
00415 
00416 /**
00417  * Atomic decrement.
00418  * @param  valuePtr Target memory location being decremented.
00419  * @param  delta    The amount being decremented in bytes.
00420  * @return          The new decremented value.
00421  *
00422  * @note The type of the pointer argument is not taken into account
00423  *       and the pointer is decremented by bytes
00424  */
00425 void *core_util_atomic_decr_ptr(void *volatile *valuePtr, ptrdiff_t delta);
00426 
00427 #ifdef __cplusplus
00428 } // extern "C"
00429 #endif
00430 /**@}*/
00431 
00432 /**@}*/
00433 
00434 #endif // __MBED_UTIL_CRITICAL_H__
00435 
00436 
00437