/* * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _PLATFORM_MUTEX_H #define _PLATFORM_MUTEX_H #include "pico/lock_core.h" #ifdef __cplusplus extern "C" { #endif /** \file mutex.h * \defgroup mutex mutex * \ingroup pico_sync * \brief Mutex API for non IRQ mutual exclusion between cores * * Mutexes are application level locks usually used protecting data structures that might be used by * multiple cores. Unlike critical sections, the mutex protected code is not necessarily * required/expected to complete quickly, as no other sytemwide locks are held on account of a locked mutex. * * Because they are not re-entrant on the same core, blocking on a mutex should never be done in an IRQ * handler. It is valid to call \ref mutex_try_enter from within an IRQ handler, if the operation * that would be conducted under lock can be skipped if the mutex is locked (at least by the same core). * * See \ref critical_section.h for protecting access between multiple cores AND IRQ handlers */ typedef struct __packed_aligned mutex { lock_core_t core; int8_t owner; //! core number or -1 for unowned } mutex_t; /*! \brief Initialise a mutex structure * \ingroup mutex * * \param mtx Pointer to mutex structure */ void mutex_init(mutex_t *mtx); /*! \brief Take ownership of a mutex * \ingroup mutex * * This function will block until the calling core can claim ownership of the mutex. * On return the caller core owns the mutex * * \param mtx Pointer to mutex structure */ void mutex_enter_blocking(mutex_t *mtx); /*! \brief Check to see if a mutex is available * \ingroup mutex * * Will return true if the mutex is unowned, false otherwise * * \param mtx Pointer to mutex structure * \param owner_out If mutex is owned, and this pointer is non-zero, it will be filled in with the core number of the current owner of the mutex */ bool mutex_try_enter(mutex_t *mtx, uint32_t *owner_out); /*! \brief Wait for mutex with timeout * \ingroup mutex * * Wait for up to the specific time to take ownership of the mutex. If the calling * core can take ownership of the mutex before the timeout expires, then true will be returned * and the calling core will own the mutex, otherwise false will be returned and the calling * core will *NOT* own the mutex. * * \param mtx Pointer to mutex structure * \param timeout_ms The timeout in milliseconds. * \return true if mutex now owned, false if timeout occurred before mutex became available */ bool mutex_enter_timeout_ms(mutex_t *mtx, uint32_t timeout_ms); /*! \brief Wait for mutex until a specific time * \ingroup mutex * * Wait until the specific time to take ownership of the mutex. If the calling * core can take ownership of the mutex before the timeout expires, then true will be returned * and the calling core will own the mutex, otherwise false will be returned and the calling * core will *NOT* own the mutex. * * \param mtx Pointer to mutex structure * \param until The time after which to return if the core cannot take owner ship of the mutex * \return true if mutex now owned, false if timeout occurred before mutex became available */ bool mutex_enter_block_until(mutex_t *mtx, absolute_time_t until); /*! \brief Release ownership of a mutex * \ingroup mutex * * \param mtx Pointer to mutex structure */ void mutex_exit(mutex_t *mtx); /*! \brief Test for mutex initialised state * \ingroup mutex * * \param mtx Pointer to mutex structure * \return true if the mutex is initialised, false otherwise */ static inline bool mutex_is_initialzed(mutex_t *mtx) { return mtx->core.spin_lock != 0; } /*! \brief Helper macro for static definition of mutexes * \ingroup mutex * * A mutex defined as follows: * * ```c * auto_init_mutex(my_mutex); * ``` * * Is equivalent to doing * * ```c * static mutex_t my_mutex; * * void my_init_function() { * mutex_init(&my_mutex); * } * ``` * * But the initialization of the mutex is performed automatically during runtime initialization */ #define auto_init_mutex(name) static __attribute__((section(".mutex_array"))) mutex_t name #ifdef __cplusplus } #endif #endif