| /* |
| * Copyright (C) 2021 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include <atomic> |
| #include <cstdint> |
| #include <utility> |
| #include <wtf/Assertions.h> |
| #include <wtf/ExportMacros.h> |
| #include <wtf/StdLibExtras.h> |
| #include <wtf/ThreadSafetyAnalysis.h> |
| |
| namespace WTF { |
| |
| class ThreadLikeAssertion; |
| WTF_EXPORT_PRIVATE bool NODELETE isMainThread(); |
| |
| struct MainThreadLike { |
| constexpr operator uint32_t() const { return -3; } |
| }; |
| inline constexpr MainThreadLike mainThreadLike; |
| |
| struct CurrentThreadLike { |
| constexpr operator uint32_t() const { return static_cast<uint32_t>(-2); } |
| }; |
| inline constexpr CurrentThreadLike currentThreadLike; |
| |
| struct AnyThreadLike { |
| constexpr operator uint32_t() const { return static_cast<uint32_t>(-1); } |
| }; |
| inline constexpr AnyThreadLike anyThreadLike; |
| |
| struct NoneThreadLike { |
| constexpr operator uint32_t() const { return 0; } |
| }; |
| inline constexpr NoneThreadLike noneThreadLike; |
| |
| class ThreadLike { |
| public: |
| // Never returns 0. |
| WTF_EXPORT_PRIVATE static uint32_t currentSequence(); |
| |
| protected: |
| static constexpr uint32_t mainThreadID { 1 }; |
| WTF_EXPORT_PRIVATE static std::atomic<uint32_t> s_uid; |
| static ThreadLikeAssertion createThreadLikeAssertion(uint32_t); |
| }; |
| |
| // A type to use for asserting that private member functions or private member variables |
| // of a class are accessed from correct threads. |
| // Supports run-time checking with assertion enabled builds. |
| // Supports compile-time declaration and checking. |
| // Example: |
| // struct MyClass { |
| // void doTask() { assertIsCurrent(m_ownerThread); doTaskImpl(); } |
| // template<typename> void doTaskCompileFailure() { doTaskImpl(); } |
| // private: |
| // void doTaskImpl() WTF_REQUIRES_CAPABILITY(m_ownerThread); |
| // int m_value WTF_GUARDED_BY_CAPABILITY(m_ownerThread) { 0 }; |
| // NO_UNIQUE_ADDRESS ThreadLikeAssertion m_ownerThread; |
| // }; |
| class WTF_CAPABILITY("is current") ThreadLikeAssertion { |
| public: |
| constexpr ThreadLikeAssertion(NoneThreadLike a) |
| : ThreadLikeAssertion(static_cast<uint32_t>(a)) |
| { |
| } |
| constexpr ThreadLikeAssertion(AnyThreadLike a) |
| : ThreadLikeAssertion(static_cast<uint32_t>(a)) |
| { |
| } |
| constexpr ThreadLikeAssertion(MainThreadLike a) |
| : ThreadLikeAssertion(static_cast<uint32_t>(a)) |
| { |
| } |
| ThreadLikeAssertion(CurrentThreadLike = currentThreadLike); |
| ThreadLikeAssertion(ThreadLikeAssertion&&); |
| ~ThreadLikeAssertion() { assertIsCurrent(*this); } |
| ThreadLikeAssertion(const ThreadLikeAssertion&) = default; |
| ThreadLikeAssertion& operator=(const ThreadLikeAssertion&) = default; |
| ThreadLikeAssertion& operator=(ThreadLikeAssertion&&); |
| |
| void reset() { *this = currentThreadLike; } |
| bool isCurrent() const; // Public as used in API tests. |
| private: |
| constexpr ThreadLikeAssertion(uint32_t uid); |
| #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
| uint32_t m_uid; |
| #endif |
| friend void assertIsCurrent(const ThreadLikeAssertion&); |
| friend class ThreadLike; |
| }; |
| |
| inline ThreadLikeAssertion::ThreadLikeAssertion(CurrentThreadLike) |
| { |
| #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
| m_uid = isMainThread() ? mainThreadLike : ThreadLike::currentSequence(); |
| #endif |
| } |
| |
| inline ThreadLikeAssertion::ThreadLikeAssertion(ThreadLikeAssertion&& other) |
| { |
| *this = WTF::move(other); |
| } |
| |
| inline ThreadLikeAssertion& ThreadLikeAssertion::operator=(ThreadLikeAssertion&& other) |
| { |
| #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
| m_uid = std::exchange(other.m_uid, anyThreadLike); |
| #else |
| UNUSED_PARAM(other); |
| #endif |
| return *this; |
| } |
| |
| inline constexpr ThreadLikeAssertion::ThreadLikeAssertion(uint32_t uid) |
| #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
| : m_uid(uid) |
| #endif |
| { |
| UNUSED_PARAM(uid); |
| } |
| |
| inline bool ThreadLikeAssertion::isCurrent() const |
| { |
| #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED |
| if (m_uid == anyThreadLike) |
| return true; |
| if (m_uid == mainThreadLike) |
| return isMainThread(); |
| return ThreadLike::currentSequence() == m_uid; |
| #else |
| return true; |
| #endif |
| } |
| |
| inline void assertIsCurrent(const ThreadLikeAssertion& threadLikeAssertion) WTF_ASSERTS_ACQUIRED_CAPABILITY(threadLikeAssertion) |
| { |
| UNUSED_PARAM(threadLikeAssertion); |
| ASSERT_WITH_SECURITY_IMPLICATION(threadLikeAssertion.isCurrent()); |
| } |
| |
| inline ThreadLikeAssertion ThreadLike::createThreadLikeAssertion(uint32_t uid) |
| { |
| return ThreadLikeAssertion { uid }; |
| } |
| |
| // Type for globally named assertions for describing access requirements. |
| // Can be used, for example, to require that a variable is accessed only in |
| // a known named thread. |
| // Example: |
| // extern NamedAssertion& mainThread; |
| // inline void assertIsMainThread() WTF_ASSERTS_ACQUIRED_CAPABILITY(mainThread); |
| // void myTask() WTF_REQUIRES_CAPABILITY(mainThread) { printf("my task is running"); } |
| // void runner() { |
| // assertIsMainThread(); |
| // myTask(); |
| // } |
| // template<typename> runnerCompileFailure() { |
| // myTask(); |
| // } |
| class WTF_CAPABILITY("is current") NamedAssertion { }; |
| |
| } |
| |
| using WTF::anyThreadLike; |
| using WTF::AnyThreadLike; |
| using WTF::assertIsCurrent; |
| using WTF::currentThreadLike; |
| using WTF::CurrentThreadLike; |
| using WTF::mainThreadLike; |
| using WTF::MainThreadLike; |
| using WTF::NamedAssertion; |
| using WTF::noneThreadLike; |
| using WTF::NoneThreadLike; |
| using WTF::ThreadLike; |
| using WTF::ThreadLikeAssertion; |