blob: 8abf04eaf0ba5ff956f1e4708ee77b96967a7992 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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 <pthread.h>
#include <android-base/threads.h>
#include <functional>
#include <memory>
#include <thread>
namespace android {
#ifdef BINDER_RPC_SINGLE_THREADED
class RpcMutex {
public:
void lock() {}
void unlock() {}
};
class RpcMutexUniqueLock {
public:
RpcMutexUniqueLock(RpcMutex&) {}
void unlock() {}
};
class RpcMutexLockGuard {
public:
RpcMutexLockGuard(RpcMutex&) {}
};
class RpcConditionVariable {
public:
void notify_one() {}
void notify_all() {}
void wait(RpcMutexUniqueLock&) {}
template <typename Predicate>
void wait(RpcMutexUniqueLock&, Predicate stop_waiting) {
LOG_ALWAYS_FATAL_IF(!stop_waiting(), "RpcConditionVariable::wait condition not met");
}
template <typename Duration>
std::cv_status wait_for(RpcMutexUniqueLock&, const Duration&) {
return std::cv_status::no_timeout;
}
template <typename Duration, typename Predicate>
bool wait_for(RpcMutexUniqueLock&, const Duration&, Predicate stop_waiting) {
return stop_waiting();
}
};
class RpcMaybeThread {
public:
RpcMaybeThread() = default;
template <typename Function, typename... Args>
RpcMaybeThread(Function&& f, Args&&... args) {
// std::function requires a copy-constructible closure,
// so we need to wrap both the function and its arguments
// in a shared pointer that std::function can copy internally
struct Vars {
std::decay_t<Function> f;
std::tuple<std::decay_t<Args>...> args;
explicit Vars(Function&& f, Args&&... args)
: f(std::move(f)), args(std::move(args)...) {}
};
auto vars = std::make_shared<Vars>(std::forward<Function>(f), std::forward<Args>(args)...);
mFunc = [vars]() { std::apply(std::move(vars->f), std::move(vars->args)); };
}
void join() {
if (mFunc) {
// Move mFunc into a temporary so we can clear mFunc before
// executing the callback. This avoids infinite recursion if
// the callee then calls join() again directly or indirectly.
decltype(mFunc) func = nullptr;
mFunc.swap(func);
func();
}
}
void detach() { join(); }
class id {
public:
bool operator==(const id&) const { return true; }
bool operator!=(const id&) const { return false; }
bool operator<(const id&) const { return false; }
bool operator<=(const id&) const { return true; }
bool operator>(const id&) const { return false; }
bool operator>=(const id&) const { return true; }
};
id get_id() const { return id(); }
private:
std::function<void(void)> mFunc;
};
namespace rpc_this_thread {
static inline RpcMaybeThread::id get_id() {
return RpcMaybeThread::id();
}
} // namespace rpc_this_thread
static inline uint64_t rpcGetThreadId() {
return 0;
}
static inline void rpcJoinIfSingleThreaded(RpcMaybeThread& t) {
t.join();
}
#else // BINDER_RPC_SINGLE_THREADED
using RpcMutex = std::mutex;
using RpcMutexUniqueLock = std::unique_lock<std::mutex>;
using RpcMutexLockGuard = std::lock_guard<std::mutex>;
using RpcConditionVariable = std::condition_variable;
using RpcMaybeThread = std::thread;
namespace rpc_this_thread = std::this_thread;
static inline uint64_t rpcGetThreadId() {
return base::GetThreadId();
}
static inline void rpcJoinIfSingleThreaded(RpcMaybeThread&) {}
#endif // BINDER_RPC_SINGLE_THREADED
} // namespace android