/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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. */ #pragma once #include <atomic> #include <condition_variable> #include <mutex> #include <folly/Hash.h> #include <folly/Indestructible.h> #include <folly/Portability.h> #include <folly/Unit.h> #include <folly/lang/SafeAssert.h> namespace folly { namespace parking_lot_detail { struct WaitNodeBase { … }; extern std::atomic<uint64_t> idallocator; // Our emulated futex uses 4096 lists of wait nodes. There are two levels // of locking: a per-list mutex that controls access to the list and a // per-node mutex, condvar, and bool that are used for the actual wakeups. // The per-node mutex allows us to do precise wakeups without thundering // herds. struct Bucket { … }; } // namespace parking_lot_detail enum class UnparkControl { … }; enum class ParkResult { … }; /* * ParkingLot provides an interface that is similar to Linux's futex * system call, but with additional functionality. It is implemented * in a portable way on top of std::mutex and std::condition_variable. * * Additional reading: * https://webkit.org/blog/6161/locking-in-webkit/ * https://github.com/WebKit/webkit/blob/master/Source/WTF/wtf/ParkingLot.h * https://locklessinc.com/articles/futex_cheat_sheet/ * * The main difference from futex is that park/unpark take lambdas, * such that nearly anything can be done while holding the bucket * lock. Unpark() lambda can also be used to wake up any number of * waiters. * * ParkingLot is templated on the data type, however, all ParkingLot * implementations are backed by a single static array of buckets to * avoid large memory overhead. Lambdas will only ever be called on * the specific ParkingLot's nodes. */ template <typename Data = Unit> class ParkingLot { … }; template <typename Data> template < typename Key, typename D, typename ToPark, typename PreWait, typename Clock, typename Duration> ParkResult ParkingLot<Data>::park_until( const Key bits, D&& data, ToPark&& toPark, PreWait&& preWait, std::chrono::time_point<Clock, Duration> deadline) { … } template <typename Data> template <typename Key, typename Func> void ParkingLot<Data>::unpark(const Key bits, Func&& func) { … } } // namespace folly