build-macos: fix C++20 compatibility for Clang13.1
Fixes compilation on Clang13.1 by backporting some C++20 features that aren't available in Clang and fixing the CMake config. Note that this doesn't yet properly package the app nor does anything work at this point. jthread, stop_token, and condition_variable_any impls taken from josuttis/jthread and appleCompat.h taken from Citra and modified by me.
This commit is contained in:
@@ -43,3 +43,6 @@
|
|||||||
[submodule "externals/ffmpeg/ffmpeg"]
|
[submodule "externals/ffmpeg/ffmpeg"]
|
||||||
path = externals/ffmpeg/ffmpeg
|
path = externals/ffmpeg/ffmpeg
|
||||||
url = https://git.ffmpeg.org/ffmpeg.git
|
url = https://git.ffmpeg.org/ffmpeg.git
|
||||||
|
[submodule "externals/range-v3"]
|
||||||
|
path = externals/range-v3
|
||||||
|
url = https://github.com/ericniebler/range-v3.git
|
||||||
|
|||||||
+9
-2
@@ -6,7 +6,14 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/find-module
|
|||||||
include(DownloadExternals)
|
include(DownloadExternals)
|
||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
|
|
||||||
project(yuzu)
|
if (APPLE)
|
||||||
|
# Hack for M1. Currently fails when compiling for arm64
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "")
|
||||||
|
set(CMAKE_CROSSCOMPILING TRUE)
|
||||||
|
project(yuzu)
|
||||||
|
else()
|
||||||
|
project(yuzu)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl2/qt as dependent options.
|
||||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||||
@@ -492,7 +499,7 @@ if (TARGET Boost::Boost)
|
|||||||
add_library(boost ALIAS Boost::Boost)
|
add_library(boost ALIAS Boost::Boost)
|
||||||
elseif (TARGET Boost::boost)
|
elseif (TARGET Boost::boost)
|
||||||
set_target_properties(Boost::boost PROPERTIES IMPORTED_GLOBAL TRUE)
|
set_target_properties(Boost::boost PROPERTIES IMPORTED_GLOBAL TRUE)
|
||||||
add_library(boost ALIAS Boost::boost src/common/apple_compat/appleCompat.h)
|
add_library(boost ALIAS Boost::boost)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Ensure libusb is properly configured (based on dolphin libusb include)
|
# Ensure libusb is properly configured (based on dolphin libusb include)
|
||||||
|
|||||||
Vendored
+5
@@ -127,3 +127,8 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
|||||||
set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
|
set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
|
||||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
add_library(range_v3 INTERFACE)
|
||||||
|
set_target_properties(range_v3 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/externals/range-v3/include)
|
||||||
|
endif()
|
||||||
|
|||||||
Vendored
+1
@@ -137,6 +137,7 @@ if (NOT WIN32)
|
|||||||
--disable-network
|
--disable-network
|
||||||
--disable-postproc
|
--disable-postproc
|
||||||
--disable-swresample
|
--disable-swresample
|
||||||
|
--disable-iconv
|
||||||
--enable-decoder=h264
|
--enable-decoder=h264
|
||||||
--enable-decoder=vp8
|
--enable-decoder=vp8
|
||||||
--enable-decoder=vp9
|
--enable-decoder=vp9
|
||||||
|
|||||||
+1
Submodule externals/range-v3 added at d800a03213
@@ -186,3 +186,7 @@ if (MSVC)
|
|||||||
else()
|
else()
|
||||||
target_link_libraries(common PRIVATE zstd)
|
target_link_libraries(common PRIVATE zstd)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(common PUBLIC range_v3)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Very hacky :)
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <concepts>
|
||||||
|
|
||||||
|
#include "common/apple_compat/condition_variable_any2.hpp"
|
||||||
|
#include "common/apple_compat/jthread.hpp"
|
||||||
|
|
||||||
|
#include <range/v3/all.hpp>
|
||||||
|
|
||||||
|
// use an external library range-v3 as std's one
|
||||||
|
namespace std::ranges {
|
||||||
|
using namespace ::ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
// adaptation of new features in c++20
|
||||||
|
namespace std {
|
||||||
|
constexpr unsigned long long min(const unsigned long long a, const unsigned long long b) {
|
||||||
|
return (b < a) ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::unsigned_integral T>
|
||||||
|
/* requires !std::custom_same_as<T, bool> && !std::custom_same_as<T, char> &&
|
||||||
|
!std::custom_same_as<T, char8_t> && !std::custom_same_as<T, char16_t> &&
|
||||||
|
!std::custom_same_as<T, char32_t> && !std::custom_same_as<T, wchar_t>*/
|
||||||
|
constexpr bool has_single_bit(T x) noexcept {
|
||||||
|
return x != 0 && (x & (x - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
using condition_variable_any_apple = std::condition_variable_any2;
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
// fix sorting with constexpr funcs
|
||||||
|
// thanks to https://tristanbrindle.com/posts/a-more-useful-compile-time-quicksort
|
||||||
|
namespace constexprSort {
|
||||||
|
namespace cstd {
|
||||||
|
template <typename RAIt>
|
||||||
|
constexpr RAIt next(RAIt it, typename std::iterator_traits<RAIt>::difference_type n = 1) {
|
||||||
|
return it + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename RAIt>
|
||||||
|
constexpr auto distance(RAIt first, RAIt last) {
|
||||||
|
return last - first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ForwardIt1, class ForwardIt2>
|
||||||
|
constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b) {
|
||||||
|
auto temp = std::move(*a);
|
||||||
|
*a = std::move(*b);
|
||||||
|
*b = std::move(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIt, class UnaryPredicate>
|
||||||
|
constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q) {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (!q(*first)) {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ForwardIt, class UnaryPredicate>
|
||||||
|
constexpr ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPredicate p) {
|
||||||
|
first = cstd::find_if_not(first, last, p);
|
||||||
|
if (first == last)
|
||||||
|
return first;
|
||||||
|
|
||||||
|
for (ForwardIt i = cstd::next(first); i != last; ++i) {
|
||||||
|
if (p(*i)) {
|
||||||
|
cstd::iter_swap(i, first);
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cstd
|
||||||
|
|
||||||
|
template <class RAIt, class Compare = std::less<>>
|
||||||
|
constexpr void quick_sort(RAIt first, RAIt last, Compare cmp = Compare{}) {
|
||||||
|
auto const N = cstd::distance(first, last);
|
||||||
|
if (N <= 1)
|
||||||
|
return;
|
||||||
|
auto const pivot = *cstd::next(first, N / 2);
|
||||||
|
auto const middle1 =
|
||||||
|
cstd::partition(first, last, [=](auto const& elem) { return cmp(elem, pivot); });
|
||||||
|
auto const middle2 =
|
||||||
|
cstd::partition(middle1, last, [=](auto const& elem) { return !cmp(pivot, elem); });
|
||||||
|
quick_sort(first, middle1, cmp); // assert(std::is_sorted(first, middle1, cmp));
|
||||||
|
quick_sort(middle2, last, cmp); // assert(std::is_sorted(middle2, last, cmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
constexpr auto sort(Range&& range) {
|
||||||
|
quick_sort(std::begin(range), std::end(range));
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
} // namespace constexprSort
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
// extended standard condition_variable to deal with
|
||||||
|
// interrupt tokens and jthread
|
||||||
|
// -----------------------------------------------------
|
||||||
|
#ifndef CONDITION_VARIABLE2_HPP
|
||||||
|
#define CONDITION_VARIABLE2_HPP
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// forward declarations are in separate header due to cyclic type dependencies:
|
||||||
|
//*****************************************************************************
|
||||||
|
#include "common/apple_compat/stop_token.hpp"
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
//* class condition_variable_any2
|
||||||
|
//* - joining std::thread with interrupt support
|
||||||
|
//*****************************************
|
||||||
|
class condition_variable_any2
|
||||||
|
{
|
||||||
|
template<typename Lockable>
|
||||||
|
struct unlock_guard{
|
||||||
|
unlock_guard(Lockable& mtx_):
|
||||||
|
mtx(mtx_){
|
||||||
|
mtx.unlock();
|
||||||
|
}
|
||||||
|
~unlock_guard(){
|
||||||
|
mtx.lock();
|
||||||
|
}
|
||||||
|
unlock_guard(unlock_guard const&)=delete;
|
||||||
|
unlock_guard(unlock_guard&&)=delete;
|
||||||
|
unlock_guard& operator=(unlock_guard const&)=delete;
|
||||||
|
unlock_guard& operator=(unlock_guard&&)=delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Lockable& mtx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cv_internals{
|
||||||
|
std::mutex m = {};
|
||||||
|
std::condition_variable cv = {};
|
||||||
|
|
||||||
|
void notify_all(){
|
||||||
|
std::lock_guard<std::mutex> guard(m);
|
||||||
|
cv.notify_all();
|
||||||
|
}
|
||||||
|
void notify_one(){
|
||||||
|
std::lock_guard<std::mutex> guard(m);
|
||||||
|
cv.notify_one();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
//*****************************************
|
||||||
|
//* standardized API for condition_variable_any:
|
||||||
|
//*****************************************
|
||||||
|
|
||||||
|
condition_variable_any2()
|
||||||
|
: internals{std::make_shared<cv_internals>()} {
|
||||||
|
}
|
||||||
|
~condition_variable_any2() {
|
||||||
|
}
|
||||||
|
condition_variable_any2(const condition_variable_any2&) = delete;
|
||||||
|
condition_variable_any2& operator=(const condition_variable_any2&) = delete;
|
||||||
|
|
||||||
|
void notify_one() noexcept {
|
||||||
|
internals->notify_one();
|
||||||
|
}
|
||||||
|
void notify_all() noexcept {
|
||||||
|
internals->notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait()
|
||||||
|
|
||||||
|
template<typename Lockable>
|
||||||
|
void wait(Lockable& lock) {
|
||||||
|
auto local_internals=internals;
|
||||||
|
std::unique_lock<std::mutex> first_internal_lock(local_internals->m);
|
||||||
|
unlock_guard<Lockable> unlocker(lock);
|
||||||
|
std::unique_lock<std::mutex> second_internal_lock(std::move(first_internal_lock));
|
||||||
|
local_internals->cv.wait(second_internal_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Lockable,class Predicate>
|
||||||
|
void wait(Lockable& lock, Predicate pred) {
|
||||||
|
// have to manually implement the loop so that the user-provided lock is reacquired before calling pred().
|
||||||
|
// (otherwise the test_cvrace_pred test case fails)
|
||||||
|
auto local_internals=internals;
|
||||||
|
while (!pred()) {
|
||||||
|
std::unique_lock<std::mutex> first_internal_lock(local_internals->m);
|
||||||
|
unlock_guard<Lockable> unlocker(lock);
|
||||||
|
std::unique_lock<std::mutex> second_internal_lock(std::move(first_internal_lock));
|
||||||
|
local_internals->cv.wait(second_internal_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait_until()
|
||||||
|
|
||||||
|
template<class Lockable, class Clock, class Duration>
|
||||||
|
cv_status wait_until(Lockable& lock,
|
||||||
|
const chrono::time_point<Clock, Duration>& abs_time) {
|
||||||
|
auto local_internals=internals;
|
||||||
|
std::unique_lock<std::mutex> first_internal_lock(local_internals->m);
|
||||||
|
unlock_guard<Lockable> unlocker(lock);
|
||||||
|
std::unique_lock<std::mutex> second_internal_lock(std::move(first_internal_lock));
|
||||||
|
return local_internals->cv.wait_until(second_internal_lock, abs_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Lockable,class Clock, class Duration, class Predicate>
|
||||||
|
bool wait_until(Lockable& lock,
|
||||||
|
const chrono::time_point<Clock, Duration>& abs_time,
|
||||||
|
Predicate pred) {
|
||||||
|
// have to manually implement the loop so that the user-provided lock is reacquired before calling pred().
|
||||||
|
// (otherwise the test_cvrace_pred test case fails)
|
||||||
|
auto local_internals=internals;
|
||||||
|
while (!pred()) {
|
||||||
|
bool shouldStop;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> first_internal_lock(local_internals->m);
|
||||||
|
unlock_guard<Lockable> unlocker(lock);
|
||||||
|
std::unique_lock<std::mutex> second_internal_lock(std::move(first_internal_lock));
|
||||||
|
shouldStop = (local_internals->cv.wait_until(second_internal_lock, abs_time) == std::cv_status::timeout);
|
||||||
|
}
|
||||||
|
if (shouldStop) {
|
||||||
|
return pred();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait_for()
|
||||||
|
|
||||||
|
template<class Lockable,class Rep, class Period>
|
||||||
|
cv_status wait_for(Lockable& lock,
|
||||||
|
const chrono::duration<Rep, Period>& rel_time) {
|
||||||
|
return wait_until(lock, std::chrono::steady_clock::now() + rel_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Lockable,class Rep, class Period, class Predicate>
|
||||||
|
bool wait_for(Lockable& lock,
|
||||||
|
const chrono::duration<Rep, Period>& rel_time,
|
||||||
|
Predicate pred) {
|
||||||
|
return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
//* supplementary API:
|
||||||
|
//*****************************************
|
||||||
|
|
||||||
|
// x.6.2.1 dealing with interrupts:
|
||||||
|
|
||||||
|
// return:
|
||||||
|
// - true if pred() yields true
|
||||||
|
// - false otherwise (i.e. on interrupt)
|
||||||
|
template <class Lockable,class Predicate>
|
||||||
|
bool wait(Lockable& lock,
|
||||||
|
stop_token stoken,
|
||||||
|
Predicate pred);
|
||||||
|
|
||||||
|
// return:
|
||||||
|
// - true if pred() yields true
|
||||||
|
// - false otherwise (i.e. on timeout or interrupt)
|
||||||
|
template <class Lockable, class Clock, class Duration, class Predicate>
|
||||||
|
bool wait_until(Lockable& lock,
|
||||||
|
stop_token stoken,
|
||||||
|
const chrono::time_point<Clock, Duration>& abs_time,
|
||||||
|
Predicate pred);
|
||||||
|
// return:
|
||||||
|
// - true if pred() yields true
|
||||||
|
// - false otherwise (i.e. on timeout or interrupt)
|
||||||
|
template <class Lockable, class Rep, class Period, class Predicate>
|
||||||
|
bool wait_for(Lockable& lock,
|
||||||
|
stop_token stoken,
|
||||||
|
const chrono::duration<Rep, Period>& rel_time,
|
||||||
|
Predicate pred);
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
//* implementation:
|
||||||
|
//*****************************************
|
||||||
|
|
||||||
|
private:
|
||||||
|
//*** API for the starting thread:
|
||||||
|
std::shared_ptr<cv_internals> internals;
|
||||||
|
// NOTE (as Howard Hinnant pointed out):
|
||||||
|
// std::~condition_variable_any() says:
|
||||||
|
// Requires: There shall be no thread blocked on *this. [Note: That is, all threads shall have been notified;
|
||||||
|
// they may subsequently block on the lock specified in the wait.
|
||||||
|
// This relaxes the usual rules, which would have required all wait calls to happen before destruction.
|
||||||
|
// Only the notification to unblock the wait needs to happen before destruction.
|
||||||
|
// The user should take care to ensure that no threads wait on *this once the destructor has been started,
|
||||||
|
// especially when the waiting threads are calling the wait functions in a loop or using the overloads of
|
||||||
|
// wait, wait_for, or wait_until that take a predicate. ]
|
||||||
|
// That big long note means ~condition_variable_any() can execute before a signaled thread returns from a wait.
|
||||||
|
// If this happens with condition_variable_any2, that waiting thread will attempt to lock the destructed mutex mut.
|
||||||
|
// To fix this, there must be shared ownership of the data member mut between the condition_variable_any object
|
||||||
|
// and the member functions wait (wait_for, etc.).
|
||||||
|
// (libc++'s implementation gets this right: https://github.com/llvm-mirror/libcxx/blob/master/include/condition_variable
|
||||||
|
// It holds the data member mutex with a shared_ptr<mutex> instead of mutex directly, and the wait functions create
|
||||||
|
// a local shared_ptr<mutex> copy on entry so that if *this destructs out from under the thread executing the wait function,
|
||||||
|
// the mutex stays alive until the wait function returns.)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
//* implementation of class condition_variable_any2
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
// wait_until(): wait with interrupt handling
|
||||||
|
// - returns on interrupt
|
||||||
|
// return value:
|
||||||
|
// - true if pred() yields true
|
||||||
|
// - false otherwise (i.e. on interrupt)
|
||||||
|
template <class Lockable, class Predicate>
|
||||||
|
inline bool condition_variable_any2::wait(Lockable& lock,
|
||||||
|
stop_token stoken,
|
||||||
|
Predicate pred)
|
||||||
|
{
|
||||||
|
if (stoken.stop_requested()) {
|
||||||
|
return pred();
|
||||||
|
}
|
||||||
|
auto local_internals=internals;
|
||||||
|
stop_callback cb(stoken, [&local_internals] { local_internals->notify_all(); });
|
||||||
|
while (!pred()) {
|
||||||
|
std::unique_lock<std::mutex> first_internal_lock(local_internals->m);
|
||||||
|
if (stoken.stop_requested()) {
|
||||||
|
// pred() has already evaluated to 'false' since we last a acquired 'lock'
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unlock_guard<Lockable> unlocker(lock);
|
||||||
|
std::unique_lock<std::mutex> second_internal_lock(std::move(first_internal_lock));
|
||||||
|
local_internals->cv.wait(second_internal_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait_until(): timed wait with interrupt handling
|
||||||
|
// - returns on interrupt
|
||||||
|
// return:
|
||||||
|
// - true if pred() yields true
|
||||||
|
// - false otherwise (i.e. on timeout or interrupt)
|
||||||
|
template <class Lockable, class Clock, class Duration, class Predicate>
|
||||||
|
inline bool condition_variable_any2::wait_until(Lockable& lock,
|
||||||
|
stop_token stoken,
|
||||||
|
const chrono::time_point<Clock, Duration>& abs_time,
|
||||||
|
Predicate pred)
|
||||||
|
{
|
||||||
|
if (stoken.stop_requested()) {
|
||||||
|
return pred();
|
||||||
|
}
|
||||||
|
// have to manually implement the loop so that the user-provided lock is reacquired before calling pred().
|
||||||
|
// (otherwise the test_cvrace_pred test case fails)
|
||||||
|
auto local_internals=internals;
|
||||||
|
stop_callback cb(stoken, [&local_internals] { local_internals->notify_all(); });
|
||||||
|
while (!pred()) {
|
||||||
|
bool shouldStop;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> first_internal_lock(local_internals->m);
|
||||||
|
if (stoken.stop_requested()) {
|
||||||
|
// pred() has already evaluated to 'false' since we last acquired 'lock'.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unlock_guard<Lockable> unlocker(lock);
|
||||||
|
std::unique_lock<std::mutex> second_internal_lock(std::move(first_internal_lock));
|
||||||
|
const auto status = local_internals->cv.wait_until(second_internal_lock, abs_time);
|
||||||
|
shouldStop = (status == std::cv_status::timeout) || stoken.stop_requested();
|
||||||
|
}
|
||||||
|
if (shouldStop) {
|
||||||
|
return pred();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait_for(): timed wait with interrupt handling
|
||||||
|
// - returns on interrupt
|
||||||
|
// return:
|
||||||
|
// - true if pred() yields true
|
||||||
|
// - false otherwise (i.e. on timeout or interrupt)
|
||||||
|
template <class Lockable,class Rep, class Period, class Predicate>
|
||||||
|
inline bool condition_variable_any2::wait_for(Lockable& lock,
|
||||||
|
stop_token stoken,
|
||||||
|
const chrono::duration<Rep, Period>& rel_time,
|
||||||
|
Predicate pred)
|
||||||
|
{
|
||||||
|
auto abs_time = std::chrono::steady_clock::now() + rel_time;
|
||||||
|
return wait_until(lock,
|
||||||
|
std::move(stoken),
|
||||||
|
abs_time,
|
||||||
|
std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // std
|
||||||
|
|
||||||
|
#endif // CONDITION_VARIABLE2_HPP
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
// -----------------------------------------------------
|
||||||
|
// cooperative interruptable and joining thread:
|
||||||
|
// -----------------------------------------------------
|
||||||
|
#ifndef JTHREAD_HPP
|
||||||
|
#define JTHREAD_HPP
|
||||||
|
|
||||||
|
#include "common/apple_compat/stop_token.hpp"
|
||||||
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional> // for invoke()
|
||||||
|
#include <iostream> // for debugging output
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
//* class jthread
|
||||||
|
//* - joining std::thread with signaling stop/end support
|
||||||
|
//*****************************************
|
||||||
|
class jthread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//*****************************************
|
||||||
|
//* standardized API:
|
||||||
|
//*****************************************
|
||||||
|
// - cover full API of std::thread
|
||||||
|
// to be able to switch from std::thread to std::jthread
|
||||||
|
|
||||||
|
// types are those from std::thread:
|
||||||
|
using id = ::std::thread::id;
|
||||||
|
using native_handle_type = ::std::thread::native_handle_type;
|
||||||
|
|
||||||
|
// construct/copy/destroy:
|
||||||
|
jthread() noexcept;
|
||||||
|
//template <typename F, typename... Args> explicit jthread(F&& f, Args&&... args);
|
||||||
|
// THE constructor that starts the thread:
|
||||||
|
// - NOTE: does SFINAE out copy constructor semantics
|
||||||
|
template <typename Callable, typename... Args,
|
||||||
|
typename = ::std::enable_if_t<!::std::is_same_v<::std::decay_t<Callable>, jthread>>>
|
||||||
|
explicit jthread(Callable&& cb, Args&&... args);
|
||||||
|
~jthread();
|
||||||
|
|
||||||
|
jthread(const jthread&) = delete;
|
||||||
|
jthread(jthread&&) noexcept = default;
|
||||||
|
jthread& operator=(const jthread&) = delete;
|
||||||
|
jthread& operator=(jthread&&) noexcept;
|
||||||
|
|
||||||
|
// members:
|
||||||
|
void swap(jthread&) noexcept;
|
||||||
|
bool joinable() const noexcept;
|
||||||
|
void join();
|
||||||
|
void detach();
|
||||||
|
|
||||||
|
id get_id() const noexcept;
|
||||||
|
native_handle_type native_handle();
|
||||||
|
|
||||||
|
// static members:
|
||||||
|
static unsigned hardware_concurrency() noexcept {
|
||||||
|
return ::std::thread::hardware_concurrency();
|
||||||
|
};
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
// - supplementary API:
|
||||||
|
// - for the calling thread:
|
||||||
|
[[nodiscard]] stop_source get_stop_source() noexcept;
|
||||||
|
[[nodiscard]] stop_token get_stop_token() const noexcept;
|
||||||
|
bool request_stop() noexcept {
|
||||||
|
return get_stop_source().request_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
//* implementation:
|
||||||
|
//*****************************************
|
||||||
|
|
||||||
|
private:
|
||||||
|
//*** API for the starting thread:
|
||||||
|
stop_source _stopSource; // stop_source for started thread
|
||||||
|
::std::thread _thread{}; // started thread (if any)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//**********************************************************************
|
||||||
|
|
||||||
|
//*****************************************
|
||||||
|
//* implementation of class jthread
|
||||||
|
//*****************************************
|
||||||
|
|
||||||
|
// default constructor:
|
||||||
|
inline jthread::jthread() noexcept
|
||||||
|
: _stopSource{nostopstate} {
|
||||||
|
}
|
||||||
|
|
||||||
|
// THE constructor that starts the thread:
|
||||||
|
// - NOTE: declaration does SFINAE out copy constructor semantics
|
||||||
|
template <typename Callable, typename... Args,
|
||||||
|
typename >
|
||||||
|
inline jthread::jthread(Callable&& cb, Args&&... args)
|
||||||
|
: _stopSource{}, // initialize stop_source
|
||||||
|
_thread{[] (stop_token st, auto&& cb, auto&&... args) { // called lambda in the thread
|
||||||
|
// perform tasks of the thread:
|
||||||
|
if constexpr(std::is_invocable_v<Callable, stop_token, Args...>) {
|
||||||
|
// pass the stop_token as first argument to the started thread:
|
||||||
|
::std::invoke(::std::forward<decltype(cb)>(cb),
|
||||||
|
std::move(st),
|
||||||
|
::std::forward<decltype(args)>(args)...);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// started thread does not expect a stop token:
|
||||||
|
::std::invoke(::std::forward<decltype(cb)>(cb),
|
||||||
|
::std::forward<decltype(args)>(args)...);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_stopSource.get_token(), // not captured due to possible races if immediately set
|
||||||
|
::std::forward<Callable>(cb), // pass callable
|
||||||
|
::std::forward<Args>(args)... // pass arguments for callable
|
||||||
|
}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// move assignment operator:
|
||||||
|
inline jthread& jthread::operator=(jthread&& t) noexcept {
|
||||||
|
if (joinable()) { // if not joined/detached, signal stop and wait for end:
|
||||||
|
request_stop();
|
||||||
|
join();
|
||||||
|
}
|
||||||
|
|
||||||
|
_thread = std::move(t._thread);
|
||||||
|
_stopSource = std::move(t._stopSource);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor:
|
||||||
|
inline jthread::~jthread() {
|
||||||
|
if (joinable()) { // if not joined/detached, signal stop and wait for end:
|
||||||
|
request_stop();
|
||||||
|
join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// others:
|
||||||
|
inline bool jthread::joinable() const noexcept {
|
||||||
|
return _thread.joinable();
|
||||||
|
}
|
||||||
|
inline void jthread::join() {
|
||||||
|
_thread.join();
|
||||||
|
}
|
||||||
|
inline void jthread::detach() {
|
||||||
|
_thread.detach();
|
||||||
|
}
|
||||||
|
inline typename jthread::id jthread::get_id() const noexcept {
|
||||||
|
return _thread.get_id();
|
||||||
|
}
|
||||||
|
inline typename jthread::native_handle_type jthread::native_handle() {
|
||||||
|
return _thread.native_handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline stop_source jthread::get_stop_source() noexcept {
|
||||||
|
return _stopSource;
|
||||||
|
}
|
||||||
|
inline stop_token jthread::get_stop_token() const noexcept {
|
||||||
|
return _stopSource.get_token();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void jthread::swap(jthread& t) noexcept {
|
||||||
|
std::swap(_stopSource, t._stopSource);
|
||||||
|
std::swap(_thread, t._thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // std
|
||||||
|
|
||||||
|
#endif // JTHREAD_HPP
|
||||||
@@ -0,0 +1,566 @@
|
|||||||
|
#pragma once
|
||||||
|
// <stop_token> header
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#ifdef SAFE
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
|
#include <immintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
inline void __spin_yield() noexcept {
|
||||||
|
// TODO: Platform-specific code here
|
||||||
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
|
_mm_pause();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// internal types for shared stop state
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
struct __stop_callback_base {
|
||||||
|
void(*__callback_)(__stop_callback_base*) = nullptr;
|
||||||
|
|
||||||
|
__stop_callback_base* __next_ = nullptr;
|
||||||
|
__stop_callback_base** __prev_ = nullptr;
|
||||||
|
bool* __isRemoved_ = nullptr;
|
||||||
|
std::atomic<bool> __callbackFinishedExecuting_{false};
|
||||||
|
|
||||||
|
void __execute() noexcept {
|
||||||
|
__callback_(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// it shall only by us who deletes this
|
||||||
|
// (workaround for virtual __execute() and destructor)
|
||||||
|
~__stop_callback_base() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __stop_state {
|
||||||
|
public:
|
||||||
|
void __add_token_reference() noexcept {
|
||||||
|
__state_.fetch_add(__token_ref_increment, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __remove_token_reference() noexcept {
|
||||||
|
auto __oldState =
|
||||||
|
__state_.fetch_sub(__token_ref_increment, std::memory_order_acq_rel);
|
||||||
|
if (__oldState < (__token_ref_increment + __source_ref_increment)) {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __add_source_reference() noexcept {
|
||||||
|
__state_.fetch_add(__source_ref_increment, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __remove_source_reference() noexcept {
|
||||||
|
auto __oldState =
|
||||||
|
__state_.fetch_sub(__source_ref_increment, std::memory_order_acq_rel);
|
||||||
|
if (__oldState < (__token_ref_increment + __source_ref_increment)) {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __request_stop() noexcept {
|
||||||
|
|
||||||
|
if (!__try_lock_and_signal_until_signalled()) {
|
||||||
|
// Stop has already been requested.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the 'stop_requested' signal and acquired the lock.
|
||||||
|
|
||||||
|
__signallingThread_ = std::this_thread::get_id();
|
||||||
|
|
||||||
|
while (__head_ != nullptr) {
|
||||||
|
// Dequeue the head of the queue
|
||||||
|
auto* __cb = __head_;
|
||||||
|
__head_ = __cb->__next_;
|
||||||
|
const bool anyMore = __head_ != nullptr;
|
||||||
|
if (anyMore) {
|
||||||
|
__head_->__prev_ = &__head_;
|
||||||
|
}
|
||||||
|
// Mark this item as removed from the list.
|
||||||
|
__cb->__prev_ = nullptr;
|
||||||
|
|
||||||
|
// Don't hold lock while executing callback
|
||||||
|
// so we don't block other threads from deregistering callbacks.
|
||||||
|
__unlock();
|
||||||
|
|
||||||
|
// TRICKY: Need to store a flag on the stack here that the callback
|
||||||
|
// can use to signal that the destructor was executed inline
|
||||||
|
// during the call. If the destructor was executed inline then
|
||||||
|
// it's not safe to dereference __cb after __execute() returns.
|
||||||
|
// If the destructor runs on some other thread then the other
|
||||||
|
// thread will block waiting for this thread to signal that the
|
||||||
|
// callback has finished executing.
|
||||||
|
bool __isRemoved = false;
|
||||||
|
__cb->__isRemoved_ = &__isRemoved;
|
||||||
|
|
||||||
|
__cb->__execute();
|
||||||
|
|
||||||
|
if (!__isRemoved) {
|
||||||
|
__cb->__isRemoved_ = nullptr;
|
||||||
|
__cb->__callbackFinishedExecuting_.store(
|
||||||
|
true, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyMore) {
|
||||||
|
// This was the last item in the queue when we dequeued it.
|
||||||
|
// No more items should be added to the queue after we have
|
||||||
|
// marked the state as interrupted, only removed from the queue.
|
||||||
|
// Avoid acquring/releasing the lock in this case.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
__unlock();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __is_stop_requested() noexcept {
|
||||||
|
return __is_stop_requested(__state_.load(std::memory_order_acquire));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __is_stop_requestable() noexcept {
|
||||||
|
return __is_stop_requestable(__state_.load(std::memory_order_acquire));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __try_add_callback(
|
||||||
|
__stop_callback_base* __cb,
|
||||||
|
bool __incrementRefCountIfSuccessful) noexcept {
|
||||||
|
std::uint64_t __oldState;
|
||||||
|
goto __load_state;
|
||||||
|
do {
|
||||||
|
goto __check_state;
|
||||||
|
do {
|
||||||
|
__spin_yield();
|
||||||
|
__load_state:
|
||||||
|
__oldState = __state_.load(std::memory_order_acquire);
|
||||||
|
__check_state:
|
||||||
|
if (__is_stop_requested(__oldState)) {
|
||||||
|
__cb->__execute();
|
||||||
|
return false;
|
||||||
|
} else if (!__is_stop_requestable(__oldState)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (__is_locked(__oldState));
|
||||||
|
} while (!__state_.compare_exchange_weak(
|
||||||
|
__oldState, __oldState | __locked_flag, std::memory_order_acquire));
|
||||||
|
|
||||||
|
// Push callback onto callback list.
|
||||||
|
__cb->__next_ = __head_;
|
||||||
|
if (__cb->__next_ != nullptr) {
|
||||||
|
__cb->__next_->__prev_ = &__cb->__next_;
|
||||||
|
}
|
||||||
|
__cb->__prev_ = &__head_;
|
||||||
|
__head_ = __cb;
|
||||||
|
|
||||||
|
if (__incrementRefCountIfSuccessful) {
|
||||||
|
__unlock_and_increment_token_ref_count();
|
||||||
|
} else {
|
||||||
|
__unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully added the callback.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __remove_callback(__stop_callback_base* __cb) noexcept {
|
||||||
|
__lock();
|
||||||
|
|
||||||
|
if (__cb->__prev_ != nullptr) {
|
||||||
|
// Still registered, not yet executed
|
||||||
|
// Just remove from the list.
|
||||||
|
*__cb->__prev_ = __cb->__next_;
|
||||||
|
if (__cb->__next_ != nullptr) {
|
||||||
|
__cb->__next_->__prev_ = __cb->__prev_;
|
||||||
|
}
|
||||||
|
|
||||||
|
__unlock_and_decrement_token_ref_count();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__unlock();
|
||||||
|
|
||||||
|
// Callback has either already executed or is executing
|
||||||
|
// concurrently on another thread.
|
||||||
|
|
||||||
|
if (__signallingThread_ == std::this_thread::get_id()) {
|
||||||
|
// Callback executed on this thread or is still currently executing
|
||||||
|
// and is deregistering itself from within the callback.
|
||||||
|
if (__cb->__isRemoved_ != nullptr) {
|
||||||
|
// Currently inside the callback, let the __request_stop() method
|
||||||
|
// know the object is about to be destructed and that it should
|
||||||
|
// not try to access the object when the callback returns.
|
||||||
|
*__cb->__isRemoved_ = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Callback is currently executing on another thread,
|
||||||
|
// block until it finishes executing.
|
||||||
|
while (
|
||||||
|
!__cb->__callbackFinishedExecuting_.load(std::memory_order_acquire)) {
|
||||||
|
__spin_yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__remove_token_reference();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool __is_locked(std::uint64_t __state) noexcept {
|
||||||
|
return (__state & __locked_flag) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __is_stop_requested(std::uint64_t __state) noexcept {
|
||||||
|
return (__state & __stop_requested_flag) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __is_stop_requestable(std::uint64_t __state) noexcept {
|
||||||
|
// Interruptible if it has already been interrupted or if there are
|
||||||
|
// still interrupt_source instances in existence.
|
||||||
|
return __is_stop_requested(__state) || (__state >= __source_ref_increment);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __try_lock_and_signal_until_signalled() noexcept {
|
||||||
|
std::uint64_t __oldState = __state_.load(std::memory_order_acquire);
|
||||||
|
do {
|
||||||
|
if (__is_stop_requested(__oldState))
|
||||||
|
return false;
|
||||||
|
while (__is_locked(__oldState)) {
|
||||||
|
__spin_yield();
|
||||||
|
__oldState = __state_.load(std::memory_order_acquire);
|
||||||
|
if (__is_stop_requested(__oldState))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (!__state_.compare_exchange_weak(
|
||||||
|
__oldState,
|
||||||
|
__oldState | __stop_requested_flag | __locked_flag,
|
||||||
|
std::memory_order_acq_rel,
|
||||||
|
std::memory_order_acquire));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __lock() noexcept {
|
||||||
|
auto __oldState = __state_.load(std::memory_order_relaxed);
|
||||||
|
do {
|
||||||
|
while (__is_locked(__oldState)) {
|
||||||
|
__spin_yield();
|
||||||
|
__oldState = __state_.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
} while (!__state_.compare_exchange_weak(
|
||||||
|
__oldState,
|
||||||
|
__oldState | __locked_flag,
|
||||||
|
std::memory_order_acquire,
|
||||||
|
std::memory_order_relaxed));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __unlock() noexcept {
|
||||||
|
__state_.fetch_sub(__locked_flag, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __unlock_and_increment_token_ref_count() noexcept {
|
||||||
|
__state_.fetch_sub(
|
||||||
|
__locked_flag - __token_ref_increment, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __unlock_and_decrement_token_ref_count() noexcept {
|
||||||
|
auto __oldState = __state_.fetch_sub(
|
||||||
|
__locked_flag + __token_ref_increment, std::memory_order_acq_rel);
|
||||||
|
// Check if new state is less than __token_ref_increment which would
|
||||||
|
// indicate that this was the last reference.
|
||||||
|
if (__oldState <
|
||||||
|
(__locked_flag + __token_ref_increment + __token_ref_increment)) {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::uint64_t __stop_requested_flag = 1u;
|
||||||
|
static constexpr std::uint64_t __locked_flag = 2u;
|
||||||
|
static constexpr std::uint64_t __token_ref_increment = 4u;
|
||||||
|
static constexpr std::uint64_t __source_ref_increment =
|
||||||
|
static_cast<std::uint64_t>(1u) << 33u;
|
||||||
|
|
||||||
|
// bit 0 - stop-requested
|
||||||
|
// bit 1 - locked
|
||||||
|
// bits 2-32 - token ref count (31 bits)
|
||||||
|
// bits 33-63 - source ref count (31 bits)
|
||||||
|
std::atomic<std::uint64_t> __state_{__source_ref_increment};
|
||||||
|
__stop_callback_base* __head_ = nullptr;
|
||||||
|
std::thread::id __signallingThread_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// forward declarations
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
class stop_source;
|
||||||
|
template <typename _Callback>
|
||||||
|
class stop_callback;
|
||||||
|
|
||||||
|
// std::nostopstate
|
||||||
|
// - to initialize a stop_source without shared stop state
|
||||||
|
struct nostopstate_t { explicit nostopstate_t() = default; };
|
||||||
|
inline constexpr nostopstate_t nostopstate{};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// stop_token
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
class stop_token {
|
||||||
|
public:
|
||||||
|
// construct:
|
||||||
|
// - TODO: explicit?
|
||||||
|
stop_token() noexcept
|
||||||
|
: __state_(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy/move/assign/destroy:
|
||||||
|
stop_token(const stop_token& __it) noexcept
|
||||||
|
: __state_(__it.__state_) {
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
__state_->__add_token_reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_token(stop_token&& __it) noexcept
|
||||||
|
: __state_(std::exchange(__it.__state_, nullptr)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~stop_token() {
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
__state_->__remove_token_reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_token& operator=(const stop_token& __it) noexcept {
|
||||||
|
if (__state_ != __it.__state_) {
|
||||||
|
stop_token __tmp{__it};
|
||||||
|
swap(__tmp);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_token& operator=(stop_token&& __it) noexcept {
|
||||||
|
stop_token __tmp{std::move(__it)};
|
||||||
|
swap(__tmp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(stop_token& __it) noexcept {
|
||||||
|
std::swap(__state_, __it.__state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop handling:
|
||||||
|
[[nodiscard]] bool stop_requested() const noexcept {
|
||||||
|
return __state_ != nullptr && __state_->__is_stop_requested();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool stop_possible() const noexcept {
|
||||||
|
return __state_ != nullptr && __state_->__is_stop_requestable();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] friend bool operator==(
|
||||||
|
const stop_token& __a,
|
||||||
|
const stop_token& __b) noexcept {
|
||||||
|
return __a.__state_ == __b.__state_;
|
||||||
|
}
|
||||||
|
[[nodiscard]] friend bool operator!=(
|
||||||
|
const stop_token& __a,
|
||||||
|
const stop_token& __b) noexcept {
|
||||||
|
return __a.__state_ != __b.__state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class stop_source;
|
||||||
|
template <typename _Callback>
|
||||||
|
friend class stop_callback;
|
||||||
|
|
||||||
|
explicit stop_token(__stop_state* __state) noexcept : __state_(__state) {
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
__state_->__add_token_reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__stop_state* __state_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// stop_source
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
class stop_source {
|
||||||
|
public:
|
||||||
|
stop_source() : __state_(new __stop_state()) {}
|
||||||
|
|
||||||
|
explicit stop_source(nostopstate_t) noexcept : __state_(nullptr) {}
|
||||||
|
|
||||||
|
~stop_source() {
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
__state_->__remove_source_reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_source(const stop_source& __other) noexcept
|
||||||
|
: __state_(__other.__state_) {
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
__state_->__add_source_reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_source(stop_source&& __other) noexcept
|
||||||
|
: __state_(std::exchange(__other.__state_, nullptr)) {}
|
||||||
|
|
||||||
|
stop_source& operator=(stop_source&& __other) noexcept {
|
||||||
|
stop_source __tmp{std::move(__other)};
|
||||||
|
swap(__tmp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_source& operator=(const stop_source& __other) noexcept {
|
||||||
|
if (__state_ != __other.__state_) {
|
||||||
|
stop_source __tmp{__other};
|
||||||
|
swap(__tmp);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool stop_requested() const noexcept {
|
||||||
|
return __state_ != nullptr && __state_->__is_stop_requested();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool stop_possible() const noexcept {
|
||||||
|
return __state_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool request_stop() noexcept {
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
return __state_->__request_stop();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] stop_token get_token() const noexcept {
|
||||||
|
return stop_token{__state_};
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(stop_source& __other) noexcept {
|
||||||
|
std::swap(__state_, __other.__state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] friend bool operator==(
|
||||||
|
const stop_source& __a,
|
||||||
|
const stop_source& __b) noexcept {
|
||||||
|
return __a.__state_ == __b.__state_;
|
||||||
|
}
|
||||||
|
[[nodiscard]] friend bool operator!=(
|
||||||
|
const stop_source& __a,
|
||||||
|
const stop_source& __b) noexcept {
|
||||||
|
return __a.__state_ != __b.__state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
__stop_state* __state_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// stop_callback
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
template <typename _Callback>
|
||||||
|
// requires Destructible<_Callback> && Invocable<_Callback>
|
||||||
|
class [[nodiscard]] stop_callback : private __stop_callback_base {
|
||||||
|
public:
|
||||||
|
using callback_type = _Callback;
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename _CB,
|
||||||
|
std::enable_if_t<std::is_constructible_v<_Callback, _CB>, int> = 0>
|
||||||
|
// requires Constructible<Callback, C>
|
||||||
|
explicit stop_callback(const stop_token& __token, _CB&& __cb) noexcept(
|
||||||
|
std::is_nothrow_constructible_v<_Callback, _CB>)
|
||||||
|
: __stop_callback_base{[](__stop_callback_base *__that) noexcept {
|
||||||
|
static_cast<stop_callback*>(__that)->__execute();
|
||||||
|
}},
|
||||||
|
__state_(nullptr),
|
||||||
|
__cb_(static_cast<_CB&&>(__cb)) {
|
||||||
|
if (__token.__state_ != nullptr &&
|
||||||
|
__token.__state_->__try_add_callback(this, true)) {
|
||||||
|
__state_ = __token.__state_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename _CB,
|
||||||
|
std::enable_if_t<std::is_constructible_v<_Callback, _CB>, int> = 0>
|
||||||
|
// requires Constructible<Callback, C>
|
||||||
|
explicit stop_callback(stop_token&& __token, _CB&& __cb) noexcept(
|
||||||
|
std::is_nothrow_constructible_v<_Callback, _CB>)
|
||||||
|
: __stop_callback_base{[](__stop_callback_base *__that) noexcept {
|
||||||
|
static_cast<stop_callback*>(__that)->__execute();
|
||||||
|
}},
|
||||||
|
__state_(nullptr),
|
||||||
|
__cb_(static_cast<_CB&&>(__cb)) {
|
||||||
|
if (__token.__state_ != nullptr &&
|
||||||
|
__token.__state_->__try_add_callback(this, false)) {
|
||||||
|
__state_ = std::exchange(__token.__state_, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~stop_callback() {
|
||||||
|
#ifdef SAFE
|
||||||
|
if (__inExecute_.load()) {
|
||||||
|
std::cerr << "*** OOPS: ~stop_callback() while callback executed\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (__state_ != nullptr) {
|
||||||
|
__state_->__remove_callback(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_callback& operator=(const stop_callback&) = delete;
|
||||||
|
stop_callback& operator=(stop_callback&&) = delete;
|
||||||
|
stop_callback(const stop_callback&) = delete;
|
||||||
|
stop_callback(stop_callback&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void __execute() noexcept {
|
||||||
|
// Executed in a noexcept context
|
||||||
|
// If it throws then we call std::terminate().
|
||||||
|
#ifdef SAFE
|
||||||
|
__inExecute_.store(true);
|
||||||
|
__cb_();
|
||||||
|
__inExecute_.store(false);
|
||||||
|
#else
|
||||||
|
__cb_();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__stop_state* __state_;
|
||||||
|
_Callback __cb_;
|
||||||
|
#ifdef SAFE
|
||||||
|
std::atomic<bool> __inExecute_{false};
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _Callback>
|
||||||
|
stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/fs/file.h"
|
#include "common/fs/file.h"
|
||||||
#include "common/fs/fs.h"
|
#include "common/fs/fs.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/fs/fs_util.h"
|
#include "common/fs/fs_util.h"
|
||||||
|
|
||||||
namespace Common::FS {
|
namespace Common::FS {
|
||||||
@@ -13,7 +16,11 @@ std::u8string ToU8String(std::string_view utf8_string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::u8string BufferToU8String(std::span<const u8> buffer) {
|
std::u8string BufferToU8String(std::span<const u8> buffer) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
return std::u8string{buffer.begin(), ranges::find(buffer, u8{0})};
|
||||||
|
#else
|
||||||
return std::u8string{buffer.begin(), std::ranges::find(buffer, u8{0})};
|
return std::u8string{buffer.begin(), std::ranges::find(buffer, u8{0})};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u8string_view BufferToU8StringView(std::span<const u8> buffer) {
|
std::u8string_view BufferToU8StringView(std::span<const u8> buffer) {
|
||||||
@@ -25,7 +32,11 @@ std::string ToUTF8String(std::u8string_view u8_string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string BufferToUTF8String(std::span<const u8> buffer) {
|
std::string BufferToUTF8String(std::span<const u8> buffer) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
return std::string{buffer.begin(), ranges::find(buffer, u8{0})};
|
||||||
|
#else
|
||||||
return std::string{buffer.begin(), std::ranges::find(buffer, u8{0})};
|
return std::string{buffer.begin(), std::ranges::find(buffer, u8{0})};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view BufferToUTF8StringView(std::span<const u8> buffer) {
|
std::string_view BufferToUTF8StringView(std::span<const u8> buffer) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/fs/fs.h"
|
#include "common/fs/fs.h"
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|||||||
@@ -8,7 +8,11 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -102,7 +106,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::queue<Task> requests;
|
std::queue<Task> requests;
|
||||||
std::mutex queue_mutex;
|
std::mutex queue_mutex;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::condition_variable_any_apple condition;
|
||||||
|
#else
|
||||||
std::condition_variable_any condition;
|
std::condition_variable_any condition;
|
||||||
|
#endif
|
||||||
std::condition_variable wait_condition;
|
std::condition_variable wait_condition;
|
||||||
std::atomic<size_t> work_scheduled{};
|
std::atomic<size_t> work_scheduled{};
|
||||||
std::atomic<size_t> work_done{};
|
std::atomic<size_t> work_done{};
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
// single reader, single writer queue
|
// single reader, single writer queue
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -136,7 +139,12 @@ private:
|
|||||||
ElementPtr* read_ptr;
|
ElementPtr* read_ptr;
|
||||||
std::atomic_size_t size{0};
|
std::atomic_size_t size{0};
|
||||||
std::mutex cv_mutex;
|
std::mutex cv_mutex;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::conditional_t<with_stop_token, std::condition_variable_any_apple, std::condition_variable>
|
||||||
|
cv;
|
||||||
|
#else
|
||||||
std::conditional_t<with_stop_token, std::condition_variable_any, std::condition_variable> cv;
|
std::conditional_t<with_stop_token, std::condition_variable_any, std::condition_variable> cv;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// a simple thread-safe,
|
// a simple thread-safe,
|
||||||
|
|||||||
@@ -762,3 +762,7 @@ if (ARCHITECTURE_x86_64)
|
|||||||
)
|
)
|
||||||
target_link_libraries(core PRIVATE dynarmic)
|
target_link_libraries(core PRIVATE dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(core PUBLIC range_v3)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/fiber.h"
|
#include "common/fiber.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/hardware_properties.h"
|
#include "core/hardware_properties.h"
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/crypto/aes_util.h"
|
#include "core/crypto/aes_util.h"
|
||||||
#include "core/crypto/ctr_encryption_layer.h"
|
#include "core/crypto/ctr_encryption_layer.h"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||||
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <boost/atomic/atomic_ref.hpp>
|
||||||
|
#include <boost/atomic/capabilities.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
@@ -208,8 +212,13 @@ void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) {
|
|||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; ++i) {
|
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; ++i) {
|
||||||
// Get an atomic reference to the core scheduler's previous thread.
|
// Get an atomic reference to the core scheduler's previous thread.
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static_assert(BOOST_ATOMIC_ADDRESS_LOCK_FREE);
|
||||||
|
boost::atomic_ref<KThread*> prev_thread(kernel.Scheduler(static_cast<s32>(i)).prev_thread);
|
||||||
|
#else
|
||||||
std::atomic_ref<KThread*> prev_thread(kernel.Scheduler(static_cast<s32>(i)).prev_thread);
|
std::atomic_ref<KThread*> prev_thread(kernel.Scheduler(static_cast<s32>(i)).prev_thread);
|
||||||
static_assert(std::atomic_ref<KThread*>::is_always_lock_free);
|
static_assert(std::atomic_ref<KThread*>::is_always_lock_free);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Atomically clear the previous thread if it's our target.
|
// Atomically clear the previous thread if it's our target.
|
||||||
KThread* compare = thread;
|
KThread* compare = thread;
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <boost/atomic/atomic_ref.hpp>
|
||||||
|
#include <boost/atomic/capabilities.hpp>
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
@@ -70,14 +75,24 @@ class KSlabHeapBase : protected impl::KSlabHeapImpl {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_obj_size{};
|
size_t m_obj_size{};
|
||||||
uintptr_t m_peak{};
|
uintptr_t m_peak {}
|
||||||
|
#ifdef __APPLE
|
||||||
|
alignas(boost::atomic_ref<uintptr_t>::required_alignment);
|
||||||
|
#else
|
||||||
|
;
|
||||||
|
#endif
|
||||||
uintptr_t m_start{};
|
uintptr_t m_start{};
|
||||||
uintptr_t m_end{};
|
uintptr_t m_end{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdatePeakImpl(uintptr_t obj) {
|
void UpdatePeakImpl(uintptr_t obj) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static_assert(BOOST_ATOMIC_ADDRESS_LOCK_FREE);
|
||||||
|
boost::atomic_ref<uintptr_t> peak_ref(m_peak);
|
||||||
|
#else
|
||||||
static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free);
|
static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free);
|
||||||
std::atomic_ref<uintptr_t> peak_ref(m_peak);
|
std::atomic_ref<uintptr_t> peak_ref(m_peak);
|
||||||
|
#endif
|
||||||
|
|
||||||
const uintptr_t alloc_peak = obj + this->GetObjectSize();
|
const uintptr_t alloc_peak = obj + this->GetObjectSize();
|
||||||
uintptr_t cur_peak = m_peak;
|
uintptr_t cur_peak = m_peak;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/hle/kernel/k_session.h"
|
#include "core/hle/kernel/k_session.h"
|
||||||
@@ -29,7 +32,11 @@ private:
|
|||||||
std::vector<std::jthread> threads;
|
std::vector<std::jthread> threads;
|
||||||
std::queue<std::function<void()>> requests;
|
std::queue<std::function<void()>> requests;
|
||||||
std::mutex queue_mutex;
|
std::mutex queue_mutex;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::condition_variable_any_apple condition;
|
||||||
|
#else
|
||||||
std::condition_variable_any condition;
|
std::condition_variable_any condition;
|
||||||
|
#endif
|
||||||
const std::string service_name;
|
const std::string service_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ void SvcWrap64(Core::System& system) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used by ControlCodeMemory
|
// Used by ControlCodeMemory
|
||||||
template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
|
template <ResultCode func(Core::System&, Handle, u32, u64, size_t, Svc::MemoryPermission)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
|
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
|
||||||
static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
|
static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
|
||||||
@@ -327,7 +327,7 @@ void SvcWrap64(Core::System& system) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used by CreateCodeMemory
|
// Used by CreateCodeMemory
|
||||||
template <ResultCode func(Core::System&, Handle*, u64, u64)>
|
template <ResultCode func(Core::System&, Handle*, u64, size_t)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
u32 param_1 = 0;
|
u32 param_1 = 0;
|
||||||
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw;
|
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/fs/file.h"
|
#include "common/fs/file.h"
|
||||||
#include "common/fs/fs.h"
|
#include "common/fs/fs.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
#error "Unimplemented platform"
|
#error "Unimplemented platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -64,3 +64,7 @@ target_link_libraries(input_common PRIVATE usb)
|
|||||||
|
|
||||||
create_target_directory_groups(input_common)
|
create_target_directory_groups(input_common)
|
||||||
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
|
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(input_common PUBLIC range_v3)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included
|
// Refer to the license.txt file included
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "common/fs/file.h"
|
#include "common/fs/file.h"
|
||||||
|
|||||||
@@ -267,3 +267,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(shader_recompiler)
|
create_target_directory_groups(shader_recompiler)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(shader_recompiler PUBLIC range_v3)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "shader_recompiler/frontend/ir/type.h"
|
#include "shader_recompiler/frontend/ir/type.h"
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <bit>
|
#include <bit>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "shader_recompiler/exception.h"
|
#include "shader_recompiler/exception.h"
|
||||||
#include "shader_recompiler/frontend/maxwell/decode.h"
|
#include "shader_recompiler/frontend/maxwell/decode.h"
|
||||||
@@ -63,9 +66,16 @@ constexpr std::array UNORDERED_ENCODINGS{
|
|||||||
|
|
||||||
constexpr auto SortedEncodings() {
|
constexpr auto SortedEncodings() {
|
||||||
std::array encodings{UNORDERED_ENCODINGS};
|
std::array encodings{UNORDERED_ENCODINGS};
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::sort(encodings.begin(), encodings.end(),
|
||||||
|
[](const InstEncoding& lhs, const InstEncoding& rhs) {
|
||||||
|
return std::popcount(lhs.mask_value.mask) > std::popcount(rhs.mask_value.mask);
|
||||||
|
});
|
||||||
|
#else
|
||||||
std::ranges::sort(encodings, [](const InstEncoding& lhs, const InstEncoding& rhs) {
|
std::ranges::sort(encodings, [](const InstEncoding& lhs, const InstEncoding& rhs) {
|
||||||
return std::popcount(lhs.mask_value.mask) > std::popcount(rhs.mask_value.mask);
|
return std::popcount(lhs.mask_value.mask) > std::popcount(rhs.mask_value.mask);
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
return encodings;
|
return encodings;
|
||||||
}
|
}
|
||||||
constexpr auto ENCODINGS{SortedEncodings()};
|
constexpr auto ENCODINGS{SortedEncodings()};
|
||||||
|
|||||||
+3
-2
@@ -181,8 +181,9 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
|
|||||||
result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)};
|
result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)};
|
||||||
} else if (f2i.dest_format == DestFormat::I64) {
|
} else if (f2i.dest_format == DestFormat::I64) {
|
||||||
handled_special_case = true;
|
handled_special_case = true;
|
||||||
result = IR::U64{
|
// fix clang overload resolution on macOS by explicitly defining this
|
||||||
v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(0x8000'0000'0000'0000UL), result)};
|
u64 immediate = 0x8000'0000'0000'0000UL;
|
||||||
|
result = IR::U64{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(immediate), result)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!handled_special_case && is_signed) {
|
if (!handled_special_case && is_signed) {
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Shader {
|
namespace Shader {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@@ -277,3 +277,7 @@ else()
|
|||||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
|
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(video_core PUBLIC range_v3)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ private:
|
|||||||
const u64* const state_words = Array<type>();
|
const u64* const state_words = Array<type>();
|
||||||
const u64 num_query_words = size / BYTES_PER_WORD + 1;
|
const u64 num_query_words = size / BYTES_PER_WORD + 1;
|
||||||
const u64 word_begin = offset / BYTES_PER_WORD;
|
const u64 word_begin = offset / BYTES_PER_WORD;
|
||||||
const u64 word_end = std::min(word_begin + num_query_words, NumWords());
|
const u64 word_end = std::min(word_begin + num_query_words, static_cast<u64>(NumWords()));
|
||||||
const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
|
const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
|
||||||
u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD;
|
u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD;
|
||||||
for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) {
|
for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) {
|
||||||
@@ -566,7 +566,7 @@ private:
|
|||||||
const u64* const state_words = Array<type>();
|
const u64* const state_words = Array<type>();
|
||||||
const u64 num_query_words = size / BYTES_PER_WORD + 1;
|
const u64 num_query_words = size / BYTES_PER_WORD + 1;
|
||||||
const u64 word_begin = offset / BYTES_PER_WORD;
|
const u64 word_begin = offset / BYTES_PER_WORD;
|
||||||
const u64 word_end = std::min(word_begin + num_query_words, NumWords());
|
const u64 word_end = std::min(word_begin + num_query_words, static_cast<u64>(NumWords()));
|
||||||
const u64 page_base = offset / BYTES_PER_PAGE;
|
const u64 page_base = offset / BYTES_PER_PAGE;
|
||||||
const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
|
const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
|
||||||
u64 begin = std::numeric_limits<u64>::max();
|
u64 begin = std::numeric_limits<u64>::max();
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/threadsafe_queue.h"
|
#include "common/threadsafe_queue.h"
|
||||||
#include "video_core/framebuffer_config.h"
|
#include "video_core/framebuffer_config.h"
|
||||||
|
|
||||||
@@ -102,7 +105,11 @@ struct SynchState final {
|
|||||||
CommandQueue queue;
|
CommandQueue queue;
|
||||||
u64 last_fence{};
|
u64 last_fence{};
|
||||||
std::atomic<u64> signaled_fence{};
|
std::atomic<u64> signaled_fence{};
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::condition_variable_any_apple cv;
|
||||||
|
#else
|
||||||
std::condition_variable_any cv;
|
std::condition_variable_any cv;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Class used to manage the GPU thread
|
/// Class used to manage the GPU thread
|
||||||
|
|||||||
@@ -7,7 +7,11 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/engines/fermi_2d.h"
|
#include "video_core/engines/fermi_2d.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/bit_cast.h"
|
#include "common/bit_cast.h"
|
||||||
#include "common/cityhash.h"
|
#include "common/cityhash.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||||
@@ -229,7 +232,11 @@ private:
|
|||||||
std::vector<std::unique_ptr<CommandChunk>> chunk_reserve;
|
std::vector<std::unique_ptr<CommandChunk>> chunk_reserve;
|
||||||
std::mutex reserve_mutex;
|
std::mutex reserve_mutex;
|
||||||
std::mutex work_mutex;
|
std::mutex work_mutex;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::condition_variable_any_apple work_cv;
|
||||||
|
#else
|
||||||
std::condition_variable_any work_cv;
|
std::condition_variable_any work_cv;
|
||||||
|
#endif
|
||||||
std::condition_variable wait_cv;
|
std::condition_variable wait_cv;
|
||||||
std::jthread worker_thread;
|
std::jthread worker_thread;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#else
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
|
#endif
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
#include <boost/container/static_vector.hpp>
|
#include <boost/container/static_vector.hpp>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/textures/astc.h"
|
#include "video_core/textures/astc.h"
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "shader_recompiler/shader_info.h"
|
#include "shader_recompiler/shader_info.h"
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/dynamic_library.h"
|
#include "common/dynamic_library.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ if (APPLE)
|
|||||||
target_sources(yuzu PRIVATE ${MACOSX_ICON})
|
target_sources(yuzu PRIVATE ${MACOSX_ICON})
|
||||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
||||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
||||||
|
target_link_libraries(yuzu PUBLIC range_v3)
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
# compile as a win32 gui application instead of a console application
|
# compile as a win32 gui application instead of a console application
|
||||||
target_link_libraries(yuzu PRIVATE Qt5::WinMain)
|
target_link_libraries(yuzu PRIVATE Qt5::WinMain)
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#include <QTouchEvent>
|
#include <QTouchEvent>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/apple_compat/appleCompat.h"
|
||||||
|
#endif
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
|
||||||
@@ -103,7 +106,11 @@ private:
|
|||||||
bool running = false;
|
bool running = false;
|
||||||
std::stop_source stop_source;
|
std::stop_source stop_source;
|
||||||
std::mutex running_mutex;
|
std::mutex running_mutex;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::condition_variable_any_apple running_cv;
|
||||||
|
#else
|
||||||
std::condition_variable_any running_cv;
|
std::condition_variable_any running_cv;
|
||||||
|
#endif
|
||||||
Common::Event running_wait{};
|
Common::Event running_wait{};
|
||||||
std::atomic_bool running_guard{false};
|
std::atomic_bool running_guard{false};
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|||||||
@@ -52,3 +52,7 @@ if (MSVC)
|
|||||||
include(CopyYuzuSDLDeps)
|
include(CopyYuzuSDLDeps)
|
||||||
copy_yuzu_SDL_deps(yuzu-cmd)
|
copy_yuzu_SDL_deps(yuzu-cmd)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(yuzu-cmd PUBLIC range_v3)
|
||||||
|
endif()
|
||||||
|
|||||||
Reference in New Issue
Block a user