/* * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 FFRT_API_CPP_FAST_MUTEX_HPP #define FFRT_API_CPP_FAST_MUTEX_HPP // Provide synchronization primitives #include #include #include #include #include #include #include namespace ffrt { namespace sync_detail { const int UNLOCK = 0; const int LOCK = 1; const int WAIT = 2; } // namespace sync_detail static void spin() { #if defined(__x86_64__) asm volatile("pause"); #elif defined(__aarch64__) asm volatile("isb sy"); #elif defined(__arm__) asm volatile("yield"); #endif } class fast_mutex { int l; __attribute__((noinline)) void lock_contended() { int v = 0; // lightly contended for (uint32_t n = static_cast(1 + rand() % 4); n <= 64; n <<= 1) { for (uint32_t i = 0; i < n; ++i) { spin(); } v = __atomic_load_n(&l, __ATOMIC_RELAXED); if (v == sync_detail::WAIT) { break; } if (v == sync_detail::UNLOCK) { if (__atomic_compare_exchange_n(&l, &v, sync_detail::LOCK, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { return; } break; } } // heavily contended if (v == sync_detail::WAIT) { syscall(SYS_futex, &l, FUTEX_WAIT_PRIVATE, sync_detail::WAIT, nullptr, nullptr, 0); } while (__atomic_exchange_n(&l, sync_detail::WAIT, __ATOMIC_ACQUIRE) != sync_detail::UNLOCK) { syscall(SYS_futex, &l, FUTEX_WAIT_PRIVATE, sync_detail::WAIT, nullptr, nullptr, 0); } } public: fast_mutex() : l(sync_detail::UNLOCK) { } fast_mutex(fast_mutex const&) = delete; void operator=(fast_mutex const&) = delete; void lock() { int v = sync_detail::UNLOCK; if (__atomic_compare_exchange_n(&l, &v, sync_detail::LOCK, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { return; } lock_contended(); } bool try_lock() { int v = sync_detail::UNLOCK; return __atomic_compare_exchange_n(&l, &v, sync_detail::LOCK, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); } void unlock() { if (__atomic_exchange_n(&l, sync_detail::UNLOCK, __ATOMIC_RELEASE) == sync_detail::WAIT) { syscall(SYS_futex, &l, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); } } }; } // namespace ffrt #endif