/* * * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2016-2017 Nest Labs, Inc. * * 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. */ /** * @file * This file declares the abstraction of mutual exclusion locks * offered by the target platform. */ #pragma once // Include configuration headers #include // Include dependent headers #include #include #include #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING #include #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING #if CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #if defined(ESP_PLATFORM) #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/task.h" #else #include #include #include #endif #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #if CHIP_SYSTEM_CONFIG_MBED_LOCKING #include #endif // CHIP_SYSTEM_CONFIG_MBED_LOCKING #if CHIP_SYSTEM_CONFIG_CMSIS_RTOS_LOCKING #include #endif // CHIP_SYSTEM_CONFIG_CMSIS_RTOS_LOCKING #if CHIP_SYSTEM_CONFIG_ZEPHYR_LOCKING #include #endif namespace chip { namespace System { // Enable thread safety attributes only with clang. #if defined(SYSTEM_ENABLE_CLANG_THREAD_SAFETY_ANALYSIS) && (!defined(SWIG)) #define CHIP_TSA_ATTRIBUTE__(x) __attribute__((x)) #else #define CHIP_TSA_ATTRIBUTE__(x) #endif #define CHIP_CAPABILITY(x) CHIP_TSA_ATTRIBUTE__(capability(x)) #define CHIP_SCOPED_CAPABILITY CHIP_TSA_ATTRIBUTE__(scoped_lockable) #define CHIP_GUARDED_BY(x) CHIP_TSA_ATTRIBUTE__(guarded_by(x)) #define CHIP_PT_GUARDED_BY(x) CHIP_TSA_ATTRIBUTE__(pt_guarded_by(x)) #define CHIP_ACQUIRED_BEFORE(...) CHIP_TSA_ATTRIBUTE__(acquired_before(__VA_ARGS__)) #define CHIP_ACQUIRED_AFTER(...) CHIP_TSA_ATTRIBUTE__(acquired_after(__VA_ARGS__)) #define CHIP_REQUIRES(...) CHIP_TSA_ATTRIBUTE__(requires_capability(__VA_ARGS__)) #define CHIP_REQUIRES_SHARED(...) CHIP_TSA_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) #define CHIP_ACQUIRE(...) CHIP_TSA_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) #define CHIP_ACQUIRE_SHARED(...) CHIP_TSA_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) #define CHIP_RELEASE(...) CHIP_TSA_ATTRIBUTE__(release_capability(__VA_ARGS__)) #define CHIP_RELEASE_SHARED(...) CHIP_TSA_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) #define CHIP_RELEASE_GENERIC(...) CHIP_TSA_ATTRIBUTE__(release_generic_capability(__VA_ARGS__)) #define CHIP_TRY_ACQUIRE(...) CHIP_TSA_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) #define CHIP_TRY_ACQUIRE_SHARED(...) CHIP_TSA_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) #define CHIP_EXCLUDES(...) CHIP_TSA_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) #define CHIP_ASSERT_CAPABILITY(x) CHIP_TSA_ATTRIBUTE__(assert_capability(x)) #define CHIP_ASSERT_SHARED_CAPABILITY(x) CHIP_TSA_ATTRIBUTE__(assert_shared_capability(x)) #define CHIP_RETURN_CAPABILITY(x) CHIP_TSA_ATTRIBUTE__(lock_returned(x)) #define CHIP_NO_THREAD_SAFETY_ANALYSIS CHIP_TSA_ATTRIBUTE__(no_thread_safety_analysis) /** * @class Mutex * * @brief * This class represents a simple mutual exclusion lock used on platforms with preemptively scheduled multi-threaded * programming environments, for example, POSIX threads and FreeRTOS. The lock is non-recursive, and may not be used * in a hardware interrupt context. The constructor and destructor are defined as null functions to facilitate using * objects with \c static storage duration and uninitialized memory. Use \c Init method to initialize. The copy/move * operators are not provided. * * @note * This class is compatible with \c std::lock_guard and provides * annotations for thread safety analysis. * */ class DLL_EXPORT CHIP_CAPABILITY("mutex") Mutex { public: Mutex() = default; static CHIP_ERROR Init(Mutex & aMutex); #if CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING inline bool isInitialized() { return mInitialized; } #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING void Lock() CHIP_ACQUIRE(); /**< Acquire the mutual exclusion lock, blocking the current thread indefinitely if necessary. */ void Unlock() CHIP_RELEASE(); /**< Release the mutual exclusion lock (can block on some systems until scheduler completes). */ // Synonyms for compatibility with std::lock_guard. void lock() CHIP_ACQUIRE() { Lock(); } void unlock() CHIP_RELEASE() { Unlock(); } private: #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING pthread_mutex_t mPOSIXMutex; #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING #if CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #if (configSUPPORT_STATIC_ALLOCATION == 1) StaticSemaphore_t mFreeRTOSSemaphoreObj; #endif // (configSUPPORT_STATIC_ALLOCATION == 1) volatile SemaphoreHandle_t mFreeRTOSSemaphore = nullptr; volatile bool mInitialized = 0; #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #if CHIP_SYSTEM_CONFIG_MBED_LOCKING rtos::Mutex mMbedMutex; #endif // CHIP_SYSTEM_CONFIG_MBED_LOCKING #if CHIP_SYSTEM_CONFIG_CMSIS_RTOS_LOCKING osMutexId_t mCmsisRTOSMutex; #endif // CHIP_SYSTEM_CONFIG_CMSIS_RTOS_LOCKING #if CHIP_SYSTEM_CONFIG_ZEPHYR_LOCKING k_mutex mZephyrMutex; #endif // CHIP_SYSTEM_CONFIG_ZEPHYR_LOCKING Mutex(const Mutex &) = delete; Mutex & operator=(const Mutex &) = delete; }; #if CHIP_SYSTEM_CONFIG_NO_LOCKING inline CHIP_ERROR Init(Mutex & aMutex) { return CHIP_NO_ERROR; } inline void Mutex::Lock() {} inline void Mutex::Unlock() {} #endif // CHIP_SYSTEM_CONFIG_NO_LOCKING #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING inline void Mutex::Lock() { pthread_mutex_lock(&this->mPOSIXMutex); } inline void Mutex::Unlock() { pthread_mutex_unlock(&this->mPOSIXMutex); } #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING #if CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING inline void Mutex::Unlock(void) { xSemaphoreGive(this->mFreeRTOSSemaphore); } #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #if CHIP_SYSTEM_CONFIG_MBED_LOCKING inline CHIP_ERROR Mutex::Init(Mutex & aMutex) { // The mutex is initialized when constructed and generates // a runtime error in case of failure. return CHIP_NO_ERROR; } inline void Mutex::Lock() { return mMbedMutex.lock(); } inline void Mutex::Unlock(void) { return mMbedMutex.unlock(); } #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #if CHIP_SYSTEM_CONFIG_ZEPHYR_LOCKING inline CHIP_ERROR Mutex::Init(Mutex & aMutex) { return System::MapErrorZephyr(k_mutex_init(&aMutex.mZephyrMutex)); } inline void Mutex::Lock() { VerifyOrDie(0 == k_mutex_lock(&mZephyrMutex, K_FOREVER)); } inline void Mutex::Unlock(void) { VerifyOrDie(0 == k_mutex_unlock(&mZephyrMutex)); } #endif // CHIP_SYSTEM_CONFIG_ZEPHYR_LOCKING } // namespace System } // namespace chip