summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt17
-rw-r--r--externals/cmake-modules/FindSDL2.cmake239
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp3
-rw-r--r--src/core/core_timing.cpp3
-rw-r--r--src/core/core_timing_util.cpp18
-rw-r--r--src/core/core_timing_util.h12
-rw-r--r--src/core/cpu_manager.h5
-rw-r--r--src/core/hardware_properties.h45
-rw-r--r--src/core/hle/kernel/client_session.cpp7
-rw-r--r--src/core/hle/kernel/client_session.h6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp20
-rw-r--r--src/core/hle/kernel/kernel.cpp17
-rw-r--r--src/core/hle/kernel/kernel.h7
-rw-r--r--src/core/hle/kernel/process.cpp4
-rw-r--r--src/core/hle/kernel/process.h8
-rw-r--r--src/core/hle/kernel/readable_event.cpp16
-rw-r--r--src/core/hle/kernel/readable_event.h10
-rw-r--r--src/core/hle/kernel/scheduler.cpp12
-rw-r--r--src/core/hle/kernel/scheduler.h13
-rw-r--r--src/core/hle/kernel/server_port.cpp6
-rw-r--r--src/core/hle/kernel/server_port.h6
-rw-r--r--src/core/hle/kernel/server_session.cpp12
-rw-r--r--src/core/hle/kernel/server_session.h6
-rw-r--r--src/core/hle/kernel/session.cpp7
-rw-r--r--src/core/hle/kernel/session.h6
-rw-r--r--src/core/hle/kernel/svc.cpp72
-rw-r--r--src/core/hle/kernel/synchronization.cpp87
-rw-r--r--src/core/hle/kernel/synchronization.h44
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp (renamed from src/core/hle/kernel/wait_object.cpp)28
-rw-r--r--src/core/hle/kernel/synchronization_object.h (renamed from src/core/hle/kernel/wait_object.h)23
-rw-r--r--src/core/hle/kernel/thread.cpp37
-rw-r--r--src/core/hle/kernel/thread.h23
-rw-r--r--src/core/hle/kernel/writable_event.cpp3
-rw-r--r--src/core/hle/service/audio/hwopus.cpp6
-rw-r--r--src/core/hle/service/hid/hid.cpp7
-rw-r--r--src/core/hle/service/ldn/ldn.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h8
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp7
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.cpp3
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.cpp3
-rw-r--r--src/core/hle/service/time/time.cpp3
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp3
-rw-r--r--src/core/memory/cheat_engine.cpp3
-rw-r--r--src/core/tools/freezer.cpp3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp91
-rw-r--r--src/video_core/engines/maxwell_3d.h16
-rw-r--r--src/video_core/engines/shader_bytecode.h4
-rw-r--r--src/video_core/gpu.cpp18
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/memory_manager.cpp14
-rw-r--r--src/video_core/memory_manager.h7
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp4
-rw-r--r--src/video_core/shader/decode/bfi.cpp2
-rw-r--r--src/yuzu/debugger/wait_tree.cpp35
-rw-r--r--src/yuzu/debugger/wait_tree.h22
57 files changed, 571 insertions, 540 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc782e252..467d769a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -151,15 +151,22 @@ if (ENABLE_SDL2)
151 set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers") 151 set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
152 set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library") 152 set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
153 set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll") 153 set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
154 else()
155 find_package(SDL2 REQUIRED)
156 endif()
157 154
158 if (SDL2_FOUND)
159 # TODO(yuriks): Make FindSDL2.cmake export an IMPORTED library instead
160 add_library(SDL2 INTERFACE) 155 add_library(SDL2 INTERFACE)
161 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}") 156 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
162 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") 157 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
158 else()
159 find_package(SDL2 REQUIRED)
160
161 # Some installations don't set SDL2_LIBRARIES
162 if("${SDL2_LIBRARIES}" STREQUAL "")
163 message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
164 set(SDL2_LIBRARIES "SDL2::SDL2")
165 endif()
166
167 include_directories(${SDL2_INCLUDE_DIRS})
168 add_library(SDL2 INTERFACE)
169 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
163 endif() 170 endif()
164else() 171else()
165 set(SDL2_FOUND NO) 172 set(SDL2_FOUND NO)
diff --git a/externals/cmake-modules/FindSDL2.cmake b/externals/cmake-modules/FindSDL2.cmake
deleted file mode 100644
index 22ce752c5..000000000
--- a/externals/cmake-modules/FindSDL2.cmake
+++ /dev/null
@@ -1,239 +0,0 @@
1
2# This module defines
3# SDL2_LIBRARY, the name of the library to link against
4# SDL2_FOUND, if false, do not try to link to SDL2
5# SDL2_INCLUDE_DIR, where to find SDL.h
6# SDL2_DLL_DIR, where to find SDL2.dll if it exists
7#
8# This module responds to the the flag:
9# SDL2_BUILDING_LIBRARY
10# If this is defined, then no SDL2main will be linked in because
11# only applications need main().
12# Otherwise, it is assumed you are building an application and this
13# module will attempt to locate and set the the proper link flags
14# as part of the returned SDL2_LIBRARY variable.
15#
16# Don't forget to include SDLmain.h and SDLmain.m your project for the
17# OS X framework based version. (Other versions link to -lSDL2main which
18# this module will try to find on your behalf.) Also for OS X, this
19# module will automatically add the -framework Cocoa on your behalf.
20#
21#
22# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
23# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
24# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
25# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
26# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
27# as appropriate. These values are used to generate the final SDL2_LIBRARY
28# variable, but when these values are unset, SDL2_LIBRARY does not get created.
29#
30#
31# $SDL2DIR is an environment variable that would
32# correspond to the ./configure --prefix=$SDL2DIR
33# used in building SDL2.
34# l.e.galup 9-20-02
35#
36# Modified by Eric Wing.
37# Added code to assist with automated building by using environmental variables
38# and providing a more controlled/consistent search behavior.
39# Added new modifications to recognize OS X frameworks and
40# additional Unix paths (FreeBSD, etc).
41# Also corrected the header search path to follow "proper" SDL guidelines.
42# Added a search for SDL2main which is needed by some platforms.
43# Added a search for threads which is needed by some platforms.
44# Added needed compile switches for MinGW.
45#
46# On OSX, this will prefer the Framework version (if found) over others.
47# People will have to manually change the cache values of
48# SDL2_LIBRARY to override this selection or set the CMake environment
49# CMAKE_INCLUDE_PATH to modify the search paths.
50#
51# Note that the header path has changed from SDL2/SDL.h to just SDL.h
52# This needed to change because "proper" SDL convention
53# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
54# reasons because not all systems place things in SDL2/ (see FreeBSD).
55
56#=============================================================================
57# Copyright 2003-2009 Kitware, Inc.
58#
59# Distributed under the OSI-approved BSD License (the "License").
60#
61# This software is distributed WITHOUT ANY WARRANTY; without even the
62# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
63# See the License for more information.
64#=============================================================================
65# CMake - Cross Platform Makefile Generator
66# Copyright 2000-2016 Kitware, Inc.
67# Copyright 2000-2011 Insight Software Consortium
68# All rights reserved.
69#
70# Redistribution and use in source and binary forms, with or without
71# modification, are permitted provided that the following conditions
72# are met:
73#
74# * Redistributions of source code must retain the above copyright
75# notice, this list of conditions and the following disclaimer.
76#
77# * Redistributions in binary form must reproduce the above copyright
78# notice, this list of conditions and the following disclaimer in the
79# documentation and/or other materials provided with the distribution.
80#
81# * Neither the names of Kitware, Inc., the Insight Software Consortium,
82# nor the names of their contributors may be used to endorse or promote
83# products derived from this software without specific prior written
84# permission.
85#
86# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
87# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
88# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
89# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
90# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
91# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
92# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
93# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
94# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
95# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
96# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
97#
98# ------------------------------------------------------------------------------
99#
100# The above copyright and license notice applies to distributions of
101# CMake in source and binary form. Some source files contain additional
102# notices of original copyright by their contributors; see each source
103# for details. Third-party software packages supplied with CMake under
104# compatible licenses provide their own copyright notices documented in
105# corresponding subdirectories.
106#
107# ------------------------------------------------------------------------------
108#
109# CMake was initially developed by Kitware with the following sponsorship:
110#
111# * National Library of Medicine at the National Institutes of Health
112# as part of the Insight Segmentation and Registration Toolkit (ITK).
113#
114# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
115# Visualization Initiative.
116#
117# * National Alliance for Medical Image Computing (NAMIC) is funded by the
118# National Institutes of Health through the NIH Roadmap for Medical Research,
119# Grant U54 EB005149.
120#
121# * Kitware, Inc.
122#
123
124message("<FindSDL2.cmake>")
125
126SET(SDL2_SEARCH_PATHS
127 ~/Library/Frameworks
128 /Library/Frameworks
129 /usr/local
130 /usr
131 /sw # Fink
132 /opt/local # DarwinPorts
133 /opt/csw # Blastwave
134 /opt
135 ${SDL2_PATH}
136)
137
138if(CMAKE_SIZEOF_VOID_P EQUAL 8)
139 set(VC_LIB_PATH_SUFFIX lib/x64)
140else()
141 set(VC_LIB_PATH_SUFFIX lib/x86)
142endif()
143
144FIND_LIBRARY(SDL2_LIBRARY_TEMP
145 NAMES SDL2
146 HINTS
147 $ENV{SDL2DIR}
148 PATH_SUFFIXES lib64 lib ${VC_LIB_PATH_SUFFIX}
149 PATHS ${SDL2_SEARCH_PATHS}
150)
151
152IF(SDL2_LIBRARY_TEMP)
153 if(MSVC)
154 get_filename_component(SDL2_DLL_DIR_TEMP ${SDL2_LIBRARY_TEMP} DIRECTORY)
155 if(EXISTS ${SDL2_DLL_DIR_TEMP}/SDL2.dll)
156 set(SDL2_DLL_DIR ${SDL2_DLL_DIR_TEMP})
157 unset(SDL2_DLL_DIR_TEMP)
158 endif()
159 endif()
160
161 FIND_PATH(SDL2_INCLUDE_DIR SDL.h
162 HINTS
163 $ENV{SDL2DIR}
164 PATH_SUFFIXES include/SDL2 include
165 PATHS ${SDL2_SEARCH_PATHS}
166 )
167
168 IF(NOT SDL2_BUILDING_LIBRARY)
169 IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
170 # Non-OS X framework versions expect you to also dynamically link to
171 # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
172 # seem to provide SDL2main for compatibility even though they don't
173 # necessarily need it.
174 FIND_LIBRARY(SDL2MAIN_LIBRARY
175 NAMES SDL2main
176 HINTS
177 $ENV{SDL2DIR}
178 PATH_SUFFIXES lib64 lib
179 PATHS ${SDL2_SEARCH_PATHS}
180 )
181 ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
182 ENDIF(NOT SDL2_BUILDING_LIBRARY)
183
184 # SDL2 may require threads on your system.
185 # The Apple build may not need an explicit flag because one of the
186 # frameworks may already provide it.
187 # But for non-OSX systems, I will use the CMake Threads package.
188 IF(NOT APPLE)
189 FIND_PACKAGE(Threads)
190 ENDIF(NOT APPLE)
191
192 # MinGW needs an additional library, mwindows
193 # It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
194 # (Actually on second look, I think it only needs one of the m* libraries.)
195 IF(MINGW)
196 SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
197 ENDIF(MINGW)
198
199 # For SDL2main
200 IF(NOT SDL2_BUILDING_LIBRARY)
201 IF(SDL2MAIN_LIBRARY)
202 SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
203 ENDIF(SDL2MAIN_LIBRARY)
204 ENDIF(NOT SDL2_BUILDING_LIBRARY)
205
206 # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
207 # CMake doesn't display the -framework Cocoa string in the UI even
208 # though it actually is there if I modify a pre-used variable.
209 # I think it has something to do with the CACHE STRING.
210 # So I use a temporary variable until the end so I can set the
211 # "real" variable in one-shot.
212 IF(APPLE)
213 SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
214 ENDIF(APPLE)
215
216 # For threads, as mentioned Apple doesn't need this.
217 # In fact, there seems to be a problem if I used the Threads package
218 # and try using this line, so I'm just skipping it entirely for OS X.
219 IF(NOT APPLE)
220 SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
221 ENDIF(NOT APPLE)
222
223 # For MinGW library
224 IF(MINGW)
225 SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
226 ENDIF(MINGW)
227
228 # Set the final string here so the GUI reflects the final state.
229 SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
230
231 # Unset the temp variable to INTERNAL so it is not seen in the CMake GUI
232 UNSET(SDL2_LIBRARY_TEMP)
233ENDIF(SDL2_LIBRARY_TEMP)
234
235message("</FindSDL2.cmake>")
236
237INCLUDE(FindPackageHandleStandardArgs)
238
239FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d342cafe0..26612e692 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -181,14 +181,16 @@ add_library(core STATIC
181 hle/kernel/svc.cpp 181 hle/kernel/svc.cpp
182 hle/kernel/svc.h 182 hle/kernel/svc.h
183 hle/kernel/svc_wrap.h 183 hle/kernel/svc_wrap.h
184 hle/kernel/synchronization_object.cpp
185 hle/kernel/synchronization_object.h
186 hle/kernel/synchronization.cpp
187 hle/kernel/synchronization.h
184 hle/kernel/thread.cpp 188 hle/kernel/thread.cpp
185 hle/kernel/thread.h 189 hle/kernel/thread.h
186 hle/kernel/transfer_memory.cpp 190 hle/kernel/transfer_memory.cpp
187 hle/kernel/transfer_memory.h 191 hle/kernel/transfer_memory.h
188 hle/kernel/vm_manager.cpp 192 hle/kernel/vm_manager.cpp
189 hle/kernel/vm_manager.h 193 hle/kernel/vm_manager.h
190 hle/kernel/wait_object.cpp
191 hle/kernel/wait_object.h
192 hle/kernel/writable_event.cpp 194 hle/kernel/writable_event.cpp
193 hle/kernel/writable_event.h 195 hle/kernel/writable_event.h
194 hle/lock.cpp 196 hle/lock.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 791640a3a..29eaf74e5 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -14,6 +14,7 @@
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
16#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
17#include "core/hardware_properties.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/scheduler.h" 19#include "core/hle/kernel/scheduler.h"
19#include "core/hle/kernel/svc.h" 20#include "core/hle/kernel/svc.h"
@@ -153,7 +154,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& pag
153 config.tpidr_el0 = &cb->tpidr_el0; 154 config.tpidr_el0 = &cb->tpidr_el0;
154 config.dczid_el0 = 4; 155 config.dczid_el0 = 4;
155 config.ctr_el0 = 0x8444c004; 156 config.ctr_el0 = 0x8444c004;
156 config.cntfrq_el0 = Timing::CNTFREQ; 157 config.cntfrq_el0 = Hardware::CNTFREQ;
157 158
158 // Unpredictable instructions 159 // Unpredictable instructions
159 config.define_unpredictable_behaviour = true; 160 config.define_unpredictable_behaviour = true;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index aa09fa453..46d4178c4 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -12,6 +12,7 @@
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/thread.h" 13#include "common/thread.h"
14#include "core/core_timing_util.h" 14#include "core/core_timing_util.h"
15#include "core/hardware_properties.h"
15 16
16namespace Core::Timing { 17namespace Core::Timing {
17 18
@@ -215,7 +216,7 @@ void CoreTiming::Idle() {
215} 216}
216 217
217std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { 218std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
218 return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE}; 219 return std::chrono::microseconds{GetTicks() * 1000000 / Hardware::BASE_CLOCK_RATE};
219} 220}
220 221
221s64 CoreTiming::GetDowncount() const { 222s64 CoreTiming::GetDowncount() const {
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index a10472a95..de50d3b14 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -11,7 +11,7 @@
11 11
12namespace Core::Timing { 12namespace Core::Timing {
13 13
14constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE; 14constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / Hardware::BASE_CLOCK_RATE;
15 15
16s64 msToCycles(std::chrono::milliseconds ms) { 16s64 msToCycles(std::chrono::milliseconds ms) {
17 if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) { 17 if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) {
@@ -20,9 +20,9 @@ s64 msToCycles(std::chrono::milliseconds ms) {
20 } 20 }
21 if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) { 21 if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) {
22 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 22 LOG_DEBUG(Core_Timing, "Time very big, do rounding");
23 return BASE_CLOCK_RATE * (ms.count() / 1000); 23 return Hardware::BASE_CLOCK_RATE * (ms.count() / 1000);
24 } 24 }
25 return (BASE_CLOCK_RATE * ms.count()) / 1000; 25 return (Hardware::BASE_CLOCK_RATE * ms.count()) / 1000;
26} 26}
27 27
28s64 usToCycles(std::chrono::microseconds us) { 28s64 usToCycles(std::chrono::microseconds us) {
@@ -32,9 +32,9 @@ s64 usToCycles(std::chrono::microseconds us) {
32 } 32 }
33 if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) { 33 if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) {
34 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 34 LOG_DEBUG(Core_Timing, "Time very big, do rounding");
35 return BASE_CLOCK_RATE * (us.count() / 1000000); 35 return Hardware::BASE_CLOCK_RATE * (us.count() / 1000000);
36 } 36 }
37 return (BASE_CLOCK_RATE * us.count()) / 1000000; 37 return (Hardware::BASE_CLOCK_RATE * us.count()) / 1000000;
38} 38}
39 39
40s64 nsToCycles(std::chrono::nanoseconds ns) { 40s64 nsToCycles(std::chrono::nanoseconds ns) {
@@ -44,14 +44,14 @@ s64 nsToCycles(std::chrono::nanoseconds ns) {
44 } 44 }
45 if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) { 45 if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) {
46 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 46 LOG_DEBUG(Core_Timing, "Time very big, do rounding");
47 return BASE_CLOCK_RATE * (ns.count() / 1000000000); 47 return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000);
48 } 48 }
49 return (BASE_CLOCK_RATE * ns.count()) / 1000000000; 49 return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000;
50} 50}
51 51
52u64 CpuCyclesToClockCycles(u64 ticks) { 52u64 CpuCyclesToClockCycles(u64 ticks) {
53 const u128 temporal = Common::Multiply64Into128(ticks, CNTFREQ); 53 const u128 temporal = Common::Multiply64Into128(ticks, Hardware::CNTFREQ);
54 return Common::Divide128On32(temporal, static_cast<u32>(BASE_CLOCK_RATE)).first; 54 return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
55} 55}
56 56
57} // namespace Core::Timing 57} // namespace Core::Timing
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index cdd84d70f..addc72b19 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -6,28 +6,24 @@
6 6
7#include <chrono> 7#include <chrono>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hardware_properties.h"
9 10
10namespace Core::Timing { 11namespace Core::Timing {
11 12
12// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
13// The exact value used is of course unverified.
14constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked
15constexpr u64 CNTFREQ = 19200000; // Value from fusee.
16
17s64 msToCycles(std::chrono::milliseconds ms); 13s64 msToCycles(std::chrono::milliseconds ms);
18s64 usToCycles(std::chrono::microseconds us); 14s64 usToCycles(std::chrono::microseconds us);
19s64 nsToCycles(std::chrono::nanoseconds ns); 15s64 nsToCycles(std::chrono::nanoseconds ns);
20 16
21inline std::chrono::milliseconds CyclesToMs(s64 cycles) { 17inline std::chrono::milliseconds CyclesToMs(s64 cycles) {
22 return std::chrono::milliseconds(cycles * 1000 / BASE_CLOCK_RATE); 18 return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE);
23} 19}
24 20
25inline std::chrono::nanoseconds CyclesToNs(s64 cycles) { 21inline std::chrono::nanoseconds CyclesToNs(s64 cycles) {
26 return std::chrono::nanoseconds(cycles * 1000000000 / BASE_CLOCK_RATE); 22 return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE);
27} 23}
28 24
29inline std::chrono::microseconds CyclesToUs(s64 cycles) { 25inline std::chrono::microseconds CyclesToUs(s64 cycles) {
30 return std::chrono::microseconds(cycles * 1000000 / BASE_CLOCK_RATE); 26 return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE);
31} 27}
32 28
33u64 CpuCyclesToClockCycles(u64 ticks); 29u64 CpuCyclesToClockCycles(u64 ticks);
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index feb619e1b..97554d1bb 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include "core/hardware_properties.h"
9 10
10namespace Core { 11namespace Core {
11 12
@@ -39,9 +40,7 @@ public:
39 void RunLoop(bool tight_loop); 40 void RunLoop(bool tight_loop);
40 41
41private: 42private:
42 static constexpr std::size_t NUM_CPU_CORES = 4; 43 std::array<std::unique_ptr<CoreManager>, Hardware::NUM_CPU_CORES> core_managers;
43
44 std::array<std::unique_ptr<CoreManager>, NUM_CPU_CORES> core_managers;
45 std::size_t active_core{}; ///< Active core, only used in single thread mode 44 std::size_t active_core{}; ///< Active core, only used in single thread mode
46 45
47 System& system; 46 System& system;
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
new file mode 100644
index 000000000..213461b6a
--- /dev/null
+++ b/src/core/hardware_properties.h
@@ -0,0 +1,45 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <tuple>
8
9#include "common/common_types.h"
10
11namespace Core {
12
13namespace Hardware {
14
15// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
16// The exact value used is of course unverified.
17constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked
18constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
19constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
20
21} // namespace Hardware
22
23struct EmuThreadHandle {
24 u32 host_handle;
25 u32 guest_handle;
26
27 u64 GetRaw() const {
28 return (static_cast<u64>(host_handle) << 32) | guest_handle;
29 }
30
31 bool operator==(const EmuThreadHandle& rhs) const {
32 return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle);
33 }
34
35 bool operator!=(const EmuThreadHandle& rhs) const {
36 return !operator==(rhs);
37 }
38
39 static constexpr EmuThreadHandle InvalidHandle() {
40 constexpr u32 invalid_handle = 0xFFFFFFFF;
41 return {invalid_handle, invalid_handle};
42 }
43};
44
45} // namespace Core
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 4669a14ad..6d66276bc 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Kernel { 13namespace Kernel {
14 14
15ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} 15ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
16 16
17ClientSession::~ClientSession() { 17ClientSession::~ClientSession() {
18 // This destructor will be called automatically when the last ClientSession handle is closed by 18 // This destructor will be called automatically when the last ClientSession handle is closed by
@@ -31,6 +31,11 @@ void ClientSession::Acquire(Thread* thread) {
31 UNIMPLEMENTED(); 31 UNIMPLEMENTED();
32} 32}
33 33
34bool ClientSession::IsSignaled() const {
35 UNIMPLEMENTED();
36 return true;
37}
38
34ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, 39ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
35 std::shared_ptr<Session> parent, 40 std::shared_ptr<Session> parent,
36 std::string name) { 41 std::string name) {
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index b4289a9a8..d15b09554 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -7,7 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9 9
10#include "core/hle/kernel/wait_object.h" 10#include "core/hle/kernel/synchronization_object.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12 12
13union ResultCode; 13union ResultCode;
@@ -22,7 +22,7 @@ class KernelCore;
22class Session; 22class Session;
23class Thread; 23class Thread;
24 24
25class ClientSession final : public WaitObject { 25class ClientSession final : public SynchronizationObject {
26public: 26public:
27 explicit ClientSession(KernelCore& kernel); 27 explicit ClientSession(KernelCore& kernel);
28 ~ClientSession() override; 28 ~ClientSession() override;
@@ -48,6 +48,8 @@ public:
48 48
49 void Acquire(Thread* thread) override; 49 void Acquire(Thread* thread) override;
50 50
51 bool IsSignaled() const override;
52
51private: 53private:
52 static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, 54 static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
53 std::shared_ptr<Session> parent, 55 std::shared_ptr<Session> parent,
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index ab05788d7..c558a2f33 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -47,15 +47,15 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
47 const std::string& reason, u64 timeout, WakeupCallback&& callback, 47 const std::string& reason, u64 timeout, WakeupCallback&& callback,
48 std::shared_ptr<WritableEvent> writable_event) { 48 std::shared_ptr<WritableEvent> writable_event) {
49 // Put the client thread to sleep until the wait event is signaled or the timeout expires. 49 // Put the client thread to sleep until the wait event is signaled or the timeout expires.
50 thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason, 50 thread->SetWakeupCallback(
51 std::shared_ptr<Thread> thread, 51 [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
52 std::shared_ptr<WaitObject> object, 52 std::shared_ptr<SynchronizationObject> object,
53 std::size_t index) mutable -> bool { 53 std::size_t index) mutable -> bool {
54 ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); 54 ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
55 callback(thread, context, reason); 55 callback(thread, context, reason);
56 context.WriteToOutgoingCommandBuffer(*thread); 56 context.WriteToOutgoingCommandBuffer(*thread);
57 return true; 57 return true;
58 }); 58 });
59 59
60 auto& kernel = Core::System::GetInstance().Kernel(); 60 auto& kernel = Core::System::GetInstance().Kernel();
61 if (!writable_event) { 61 if (!writable_event) {
@@ -67,7 +67,7 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
67 const auto readable_event{writable_event->GetReadableEvent()}; 67 const auto readable_event{writable_event->GetReadableEvent()};
68 writable_event->Clear(); 68 writable_event->Clear();
69 thread->SetStatus(ThreadStatus::WaitHLEEvent); 69 thread->SetStatus(ThreadStatus::WaitHLEEvent);
70 thread->SetWaitObjects({readable_event}); 70 thread->SetSynchronizationObjects({readable_event});
71 readable_event->AddWaitingThread(thread); 71 readable_event->AddWaitingThread(thread);
72 72
73 if (timeout > 0) { 73 if (timeout > 0) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index edd4c4259..4eb1d8703 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -23,6 +23,7 @@
23#include "core/hle/kernel/process.h" 23#include "core/hle/kernel/process.h"
24#include "core/hle/kernel/resource_limit.h" 24#include "core/hle/kernel/resource_limit.h"
25#include "core/hle/kernel/scheduler.h" 25#include "core/hle/kernel/scheduler.h"
26#include "core/hle/kernel/synchronization.h"
26#include "core/hle/kernel/thread.h" 27#include "core/hle/kernel/thread.h"
27#include "core/hle/lock.h" 28#include "core/hle/lock.h"
28#include "core/hle/result.h" 29#include "core/hle/result.h"
@@ -54,10 +55,10 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
54 if (thread->GetStatus() == ThreadStatus::WaitSynch || 55 if (thread->GetStatus() == ThreadStatus::WaitSynch ||
55 thread->GetStatus() == ThreadStatus::WaitHLEEvent) { 56 thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
56 // Remove the thread from each of its waiting objects' waitlists 57 // Remove the thread from each of its waiting objects' waitlists
57 for (const auto& object : thread->GetWaitObjects()) { 58 for (const auto& object : thread->GetSynchronizationObjects()) {
58 object->RemoveWaitingThread(thread); 59 object->RemoveWaitingThread(thread);
59 } 60 }
60 thread->ClearWaitObjects(); 61 thread->ClearSynchronizationObjects();
61 62
62 // Invoke the wakeup callback before clearing the wait objects 63 // Invoke the wakeup callback before clearing the wait objects
63 if (thread->HasWakeupCallback()) { 64 if (thread->HasWakeupCallback()) {
@@ -96,7 +97,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
96} 97}
97 98
98struct KernelCore::Impl { 99struct KernelCore::Impl {
99 explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {} 100 explicit Impl(Core::System& system)
101 : system{system}, global_scheduler{system}, synchronization{system} {}
100 102
101 void Initialize(KernelCore& kernel) { 103 void Initialize(KernelCore& kernel) {
102 Shutdown(); 104 Shutdown();
@@ -191,6 +193,7 @@ struct KernelCore::Impl {
191 std::vector<std::shared_ptr<Process>> process_list; 193 std::vector<std::shared_ptr<Process>> process_list;
192 Process* current_process = nullptr; 194 Process* current_process = nullptr;
193 Kernel::GlobalScheduler global_scheduler; 195 Kernel::GlobalScheduler global_scheduler;
196 Kernel::Synchronization synchronization;
194 197
195 std::shared_ptr<ResourceLimit> system_resource_limit; 198 std::shared_ptr<ResourceLimit> system_resource_limit;
196 199
@@ -270,6 +273,14 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
270 return impl->cores[id]; 273 return impl->cores[id];
271} 274}
272 275
276Kernel::Synchronization& KernelCore::Synchronization() {
277 return impl->synchronization;
278}
279
280const Kernel::Synchronization& KernelCore::Synchronization() const {
281 return impl->synchronization;
282}
283
273Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { 284Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
274 return *impl->exclusive_monitor; 285 return *impl->exclusive_monitor;
275} 286}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index fccffaf3a..1eede3063 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -29,6 +29,7 @@ class HandleTable;
29class PhysicalCore; 29class PhysicalCore;
30class Process; 30class Process;
31class ResourceLimit; 31class ResourceLimit;
32class Synchronization;
32class Thread; 33class Thread;
33 34
34/// Represents a single instance of the kernel. 35/// Represents a single instance of the kernel.
@@ -92,6 +93,12 @@ public:
92 /// Gets the an instance of the respective physical CPU core. 93 /// Gets the an instance of the respective physical CPU core.
93 const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; 94 const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
94 95
96 /// Gets the an instance of the Synchronization Interface.
97 Kernel::Synchronization& Synchronization();
98
99 /// Gets the an instance of the Synchronization Interface.
100 const Kernel::Synchronization& Synchronization() const;
101
95 /// Stops execution of 'id' core, in order to reschedule a new thread. 102 /// Stops execution of 'id' core, in order to reschedule a new thread.
96 void PrepareReschedule(std::size_t id); 103 void PrepareReschedule(std::size_t id);
97 104
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b9035a0be..2fcb7326c 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -337,7 +337,7 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
337} 337}
338 338
339Process::Process(Core::System& system) 339Process::Process(Core::System& system)
340 : WaitObject{system.Kernel()}, vm_manager{system}, 340 : SynchronizationObject{system.Kernel()}, vm_manager{system},
341 address_arbiter{system}, mutex{system}, system{system} {} 341 address_arbiter{system}, mutex{system}, system{system} {}
342 342
343Process::~Process() = default; 343Process::~Process() = default;
@@ -357,7 +357,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
357 357
358 status = new_status; 358 status = new_status;
359 is_signaled = true; 359 is_signaled = true;
360 WakeupAllWaitingThreads(); 360 Signal();
361} 361}
362 362
363void Process::AllocateMainThreadStack(u64 stack_size) { 363void Process::AllocateMainThreadStack(u64 stack_size) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 3483fa19d..4887132a7 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -15,8 +15,8 @@
15#include "core/hle/kernel/handle_table.h" 15#include "core/hle/kernel/handle_table.h"
16#include "core/hle/kernel/mutex.h" 16#include "core/hle/kernel/mutex.h"
17#include "core/hle/kernel/process_capability.h" 17#include "core/hle/kernel/process_capability.h"
18#include "core/hle/kernel/synchronization_object.h"
18#include "core/hle/kernel/vm_manager.h" 19#include "core/hle/kernel/vm_manager.h"
19#include "core/hle/kernel/wait_object.h"
20#include "core/hle/result.h" 20#include "core/hle/result.h"
21 21
22namespace Core { 22namespace Core {
@@ -60,7 +60,7 @@ enum class ProcessStatus {
60 DebugBreak, 60 DebugBreak,
61}; 61};
62 62
63class Process final : public WaitObject { 63class Process final : public SynchronizationObject {
64public: 64public:
65 explicit Process(Core::System& system); 65 explicit Process(Core::System& system);
66 ~Process() override; 66 ~Process() override;
@@ -359,10 +359,6 @@ private:
359 /// specified by metadata provided to the process during loading. 359 /// specified by metadata provided to the process during loading.
360 bool is_64bit_process = true; 360 bool is_64bit_process = true;
361 361
362 /// Whether or not this process is signaled. This occurs
363 /// upon the process changing to a different state.
364 bool is_signaled = false;
365
366 /// Total running time for the process in ticks. 362 /// Total running time for the process in ticks.
367 u64 total_process_running_time_ticks = 0; 363 u64 total_process_running_time_ticks = 0;
368 364
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index d8ac97aa1..9d3d3a81b 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -11,30 +11,30 @@
11 11
12namespace Kernel { 12namespace Kernel {
13 13
14ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {} 14ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {}
15ReadableEvent::~ReadableEvent() = default; 15ReadableEvent::~ReadableEvent() = default;
16 16
17bool ReadableEvent::ShouldWait(const Thread* thread) const { 17bool ReadableEvent::ShouldWait(const Thread* thread) const {
18 return !signaled; 18 return !is_signaled;
19} 19}
20 20
21void ReadableEvent::Acquire(Thread* thread) { 21void ReadableEvent::Acquire(Thread* thread) {
22 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 22 ASSERT_MSG(IsSignaled(), "object unavailable!");
23} 23}
24 24
25void ReadableEvent::Signal() { 25void ReadableEvent::Signal() {
26 if (!signaled) { 26 if (!is_signaled) {
27 signaled = true; 27 is_signaled = true;
28 WakeupAllWaitingThreads(); 28 SynchronizationObject::Signal();
29 }; 29 };
30} 30}
31 31
32void ReadableEvent::Clear() { 32void ReadableEvent::Clear() {
33 signaled = false; 33 is_signaled = false;
34} 34}
35 35
36ResultCode ReadableEvent::Reset() { 36ResultCode ReadableEvent::Reset() {
37 if (!signaled) { 37 if (!is_signaled) {
38 return ERR_INVALID_STATE; 38 return ERR_INVALID_STATE;
39 } 39 }
40 40
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
index 11ff71c3a..3264dd066 100644
--- a/src/core/hle/kernel/readable_event.h
+++ b/src/core/hle/kernel/readable_event.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/wait_object.h" 8#include "core/hle/kernel/synchronization_object.h"
9 9
10union ResultCode; 10union ResultCode;
11 11
@@ -14,7 +14,7 @@ namespace Kernel {
14class KernelCore; 14class KernelCore;
15class WritableEvent; 15class WritableEvent;
16 16
17class ReadableEvent final : public WaitObject { 17class ReadableEvent final : public SynchronizationObject {
18 friend class WritableEvent; 18 friend class WritableEvent;
19 19
20public: 20public:
@@ -46,13 +46,11 @@ public:
46 /// then ERR_INVALID_STATE will be returned. 46 /// then ERR_INVALID_STATE will be returned.
47 ResultCode Reset(); 47 ResultCode Reset();
48 48
49 void Signal() override;
50
49private: 51private:
50 explicit ReadableEvent(KernelCore& kernel); 52 explicit ReadableEvent(KernelCore& kernel);
51 53
52 void Signal();
53
54 bool signaled{};
55
56 std::string name; ///< Name of event (optional) 54 std::string name; ///< Name of event (optional)
57}; 55};
58 56
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index eb196a690..86f1421bf 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -124,8 +124,8 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) {
124 "Thread yielding without being in front"); 124 "Thread yielding without being in front");
125 scheduled_queue[core_id].yield(priority); 125 scheduled_queue[core_id].yield(priority);
126 126
127 std::array<Thread*, NUM_CPU_CORES> current_threads; 127 std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
128 for (u32 i = 0; i < NUM_CPU_CORES; i++) { 128 for (std::size_t i = 0; i < current_threads.size(); i++) {
129 current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); 129 current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
130 } 130 }
131 131
@@ -177,8 +177,8 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
177 // function... 177 // function...
178 if (scheduled_queue[core_id].empty()) { 178 if (scheduled_queue[core_id].empty()) {
179 // Here, "current_threads" is calculated after the ""yield"", unlike yield -1 179 // Here, "current_threads" is calculated after the ""yield"", unlike yield -1
180 std::array<Thread*, NUM_CPU_CORES> current_threads; 180 std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
181 for (u32 i = 0; i < NUM_CPU_CORES; i++) { 181 for (std::size_t i = 0; i < current_threads.size(); i++) {
182 current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); 182 current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
183 } 183 }
184 for (auto& thread : suggested_queue[core_id]) { 184 for (auto& thread : suggested_queue[core_id]) {
@@ -208,7 +208,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
208} 208}
209 209
210void GlobalScheduler::PreemptThreads() { 210void GlobalScheduler::PreemptThreads() {
211 for (std::size_t core_id = 0; core_id < NUM_CPU_CORES; core_id++) { 211 for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
212 const u32 priority = preemption_priorities[core_id]; 212 const u32 priority = preemption_priorities[core_id];
213 213
214 if (scheduled_queue[core_id].size(priority) > 0) { 214 if (scheduled_queue[core_id].size(priority) > 0) {
@@ -349,7 +349,7 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread,
349} 349}
350 350
351void GlobalScheduler::Shutdown() { 351void GlobalScheduler::Shutdown() {
352 for (std::size_t core = 0; core < NUM_CPU_CORES; core++) { 352 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
353 scheduled_queue[core].clear(); 353 scheduled_queue[core].clear();
354 suggested_queue[core].clear(); 354 suggested_queue[core].clear();
355 } 355 }
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 14b77960a..96db049cb 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -10,6 +10,7 @@
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/multi_level_queue.h" 12#include "common/multi_level_queue.h"
13#include "core/hardware_properties.h"
13#include "core/hle/kernel/thread.h" 14#include "core/hle/kernel/thread.h"
14 15
15namespace Core { 16namespace Core {
@@ -23,8 +24,6 @@ class Process;
23 24
24class GlobalScheduler final { 25class GlobalScheduler final {
25public: 26public:
26 static constexpr u32 NUM_CPU_CORES = 4;
27
28 explicit GlobalScheduler(Core::System& system); 27 explicit GlobalScheduler(Core::System& system);
29 ~GlobalScheduler(); 28 ~GlobalScheduler();
30 29
@@ -125,7 +124,7 @@ public:
125 void PreemptThreads(); 124 void PreemptThreads();
126 125
127 u32 CpuCoresCount() const { 126 u32 CpuCoresCount() const {
128 return NUM_CPU_CORES; 127 return Core::Hardware::NUM_CPU_CORES;
129 } 128 }
130 129
131 void SetReselectionPending() { 130 void SetReselectionPending() {
@@ -149,13 +148,15 @@ private:
149 bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner); 148 bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner);
150 149
151 static constexpr u32 min_regular_priority = 2; 150 static constexpr u32 min_regular_priority = 2;
152 std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue; 151 std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
153 std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue; 152 scheduled_queue;
153 std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
154 suggested_queue;
154 std::atomic<bool> is_reselection_pending{false}; 155 std::atomic<bool> is_reselection_pending{false};
155 156
156 // The priority levels at which the global scheduler preempts threads every 10 ms. They are 157 // The priority levels at which the global scheduler preempts threads every 10 ms. They are
157 // ordered from Core 0 to Core 3. 158 // ordered from Core 0 to Core 3.
158 std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; 159 std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
159 160
160 /// Lists all thread ids that aren't deleted/etc. 161 /// Lists all thread ids that aren't deleted/etc.
161 std::vector<std::shared_ptr<Thread>> thread_list; 162 std::vector<std::shared_ptr<Thread>> thread_list;
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index a4ccfa35e..a549ae9d7 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -13,7 +13,7 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {} 16ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {}
17ServerPort::~ServerPort() = default; 17ServerPort::~ServerPort() = default;
18 18
19ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { 19ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
@@ -39,6 +39,10 @@ void ServerPort::Acquire(Thread* thread) {
39 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 39 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
40} 40}
41 41
42bool ServerPort::IsSignaled() const {
43 return !pending_sessions.empty();
44}
45
42ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, 46ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
43 std::string name) { 47 std::string name) {
44 std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel); 48 std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 8be8a75ea..41b191b86 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -10,7 +10,7 @@
10#include <vector> 10#include <vector>
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/kernel/object.h" 12#include "core/hle/kernel/object.h"
13#include "core/hle/kernel/wait_object.h" 13#include "core/hle/kernel/synchronization_object.h"
14#include "core/hle/result.h" 14#include "core/hle/result.h"
15 15
16namespace Kernel { 16namespace Kernel {
@@ -20,7 +20,7 @@ class KernelCore;
20class ServerSession; 20class ServerSession;
21class SessionRequestHandler; 21class SessionRequestHandler;
22 22
23class ServerPort final : public WaitObject { 23class ServerPort final : public SynchronizationObject {
24public: 24public:
25 explicit ServerPort(KernelCore& kernel); 25 explicit ServerPort(KernelCore& kernel);
26 ~ServerPort() override; 26 ~ServerPort() override;
@@ -82,6 +82,8 @@ public:
82 bool ShouldWait(const Thread* thread) const override; 82 bool ShouldWait(const Thread* thread) const override;
83 void Acquire(Thread* thread) override; 83 void Acquire(Thread* thread) override;
84 84
85 bool IsSignaled() const override;
86
85private: 87private:
86 /// ServerSessions waiting to be accepted by the port 88 /// ServerSessions waiting to be accepted by the port
87 std::vector<std::shared_ptr<ServerSession>> pending_sessions; 89 std::vector<std::shared_ptr<ServerSession>> pending_sessions;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 7825e1ec4..4604e35c5 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -24,7 +24,7 @@
24 24
25namespace Kernel { 25namespace Kernel {
26 26
27ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} 27ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
28ServerSession::~ServerSession() = default; 28ServerSession::~ServerSession() = default;
29 29
30ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, 30ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
@@ -50,6 +50,16 @@ bool ServerSession::ShouldWait(const Thread* thread) const {
50 return pending_requesting_threads.empty() || currently_handling != nullptr; 50 return pending_requesting_threads.empty() || currently_handling != nullptr;
51} 51}
52 52
53bool ServerSession::IsSignaled() const {
54 // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
55 if (!parent->Client()) {
56 return true;
57 }
58
59 // Wait if we have no pending requests, or if we're currently handling a request.
60 return !pending_requesting_threads.empty() && currently_handling == nullptr;
61}
62
53void ServerSession::Acquire(Thread* thread) { 63void ServerSession::Acquire(Thread* thread) {
54 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 64 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
55 // We are now handling a request, pop it from the stack. 65 // We are now handling a request, pop it from the stack.
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index d6e48109e..77e4f6721 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -10,7 +10,7 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/threadsafe_queue.h" 12#include "common/threadsafe_queue.h"
13#include "core/hle/kernel/wait_object.h" 13#include "core/hle/kernel/synchronization_object.h"
14#include "core/hle/result.h" 14#include "core/hle/result.h"
15 15
16namespace Memory { 16namespace Memory {
@@ -41,7 +41,7 @@ class Thread;
41 * After the server replies to the request, the response is marshalled back to the caller's 41 * After the server replies to the request, the response is marshalled back to the caller's
42 * TLS buffer and control is transferred back to it. 42 * TLS buffer and control is transferred back to it.
43 */ 43 */
44class ServerSession final : public WaitObject { 44class ServerSession final : public SynchronizationObject {
45public: 45public:
46 explicit ServerSession(KernelCore& kernel); 46 explicit ServerSession(KernelCore& kernel);
47 ~ServerSession() override; 47 ~ServerSession() override;
@@ -73,6 +73,8 @@ public:
73 return parent.get(); 73 return parent.get();
74 } 74 }
75 75
76 bool IsSignaled() const override;
77
76 /** 78 /**
77 * Sets the HLE handler for the session. This handler will be called to service IPC requests 79 * Sets the HLE handler for the session. This handler will be called to service IPC requests
78 * instead of the regular IPC machinery. (The regular IPC machinery is currently not 80 * instead of the regular IPC machinery. (The regular IPC machinery is currently not
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index dee6e2b72..e4dd53e24 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -9,7 +9,7 @@
9 9
10namespace Kernel { 10namespace Kernel {
11 11
12Session::Session(KernelCore& kernel) : WaitObject{kernel} {} 12Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {}
13Session::~Session() = default; 13Session::~Session() = default;
14 14
15Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { 15Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
@@ -29,6 +29,11 @@ bool Session::ShouldWait(const Thread* thread) const {
29 return {}; 29 return {};
30} 30}
31 31
32bool Session::IsSignaled() const {
33 UNIMPLEMENTED();
34 return true;
35}
36
32void Session::Acquire(Thread* thread) { 37void Session::Acquire(Thread* thread) {
33 UNIMPLEMENTED(); 38 UNIMPLEMENTED();
34} 39}
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 15a5ac15f..7cd9c0d77 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -8,7 +8,7 @@
8#include <string> 8#include <string>
9#include <utility> 9#include <utility>
10 10
11#include "core/hle/kernel/wait_object.h" 11#include "core/hle/kernel/synchronization_object.h"
12 12
13namespace Kernel { 13namespace Kernel {
14 14
@@ -19,7 +19,7 @@ class ServerSession;
19 * Parent structure to link the client and server endpoints of a session with their associated 19 * Parent structure to link the client and server endpoints of a session with their associated
20 * client port. 20 * client port.
21 */ 21 */
22class Session final : public WaitObject { 22class Session final : public SynchronizationObject {
23public: 23public:
24 explicit Session(KernelCore& kernel); 24 explicit Session(KernelCore& kernel);
25 ~Session() override; 25 ~Session() override;
@@ -39,6 +39,8 @@ public:
39 39
40 bool ShouldWait(const Thread* thread) const override; 40 bool ShouldWait(const Thread* thread) const override;
41 41
42 bool IsSignaled() const override;
43
42 void Acquire(Thread* thread) override; 44 void Acquire(Thread* thread) override;
43 45
44 std::shared_ptr<ClientSession> Client() { 46 std::shared_ptr<ClientSession> Client() {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 9cae5c73d..fd91779a3 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -32,6 +32,7 @@
32#include "core/hle/kernel/shared_memory.h" 32#include "core/hle/kernel/shared_memory.h"
33#include "core/hle/kernel/svc.h" 33#include "core/hle/kernel/svc.h"
34#include "core/hle/kernel/svc_wrap.h" 34#include "core/hle/kernel/svc_wrap.h"
35#include "core/hle/kernel/synchronization.h"
35#include "core/hle/kernel/thread.h" 36#include "core/hle/kernel/thread.h"
36#include "core/hle/kernel/transfer_memory.h" 37#include "core/hle/kernel/transfer_memory.h"
37#include "core/hle/kernel/writable_event.h" 38#include "core/hle/kernel/writable_event.h"
@@ -433,22 +434,6 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
433 return ERR_INVALID_HANDLE; 434 return ERR_INVALID_HANDLE;
434} 435}
435 436
436/// Default thread wakeup callback for WaitSynchronization
437static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
438 std::shared_ptr<WaitObject> object, std::size_t index) {
439 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
440
441 if (reason == ThreadWakeupReason::Timeout) {
442 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
443 return true;
444 }
445
446 ASSERT(reason == ThreadWakeupReason::Signal);
447 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
448 thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
449 return true;
450};
451
452/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 437/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
453static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, 438static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address,
454 u64 handle_count, s64 nano_seconds) { 439 u64 handle_count, s64 nano_seconds) {
@@ -472,14 +457,14 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
472 } 457 }
473 458
474 auto* const thread = system.CurrentScheduler().GetCurrentThread(); 459 auto* const thread = system.CurrentScheduler().GetCurrentThread();
475 460 auto& kernel = system.Kernel();
476 using ObjectPtr = Thread::ThreadWaitObjects::value_type; 461 using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type;
477 Thread::ThreadWaitObjects objects(handle_count); 462 Thread::ThreadSynchronizationObjects objects(handle_count);
478 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 463 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
479 464
480 for (u64 i = 0; i < handle_count; ++i) { 465 for (u64 i = 0; i < handle_count; ++i) {
481 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); 466 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
482 const auto object = handle_table.Get<WaitObject>(handle); 467 const auto object = handle_table.Get<SynchronizationObject>(handle);
483 468
484 if (object == nullptr) { 469 if (object == nullptr) {
485 LOG_ERROR(Kernel_SVC, "Object is a nullptr"); 470 LOG_ERROR(Kernel_SVC, "Object is a nullptr");
@@ -488,47 +473,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
488 473
489 objects[i] = object; 474 objects[i] = object;
490 } 475 }
491 476 auto& synchronization = kernel.Synchronization();
492 // Find the first object that is acquirable in the provided list of objects 477 const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds);
493 auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { 478 *index = handle_result;
494 return !object->ShouldWait(thread); 479 return result;
495 });
496
497 if (itr != objects.end()) {
498 // We found a ready object, acquire it and set the result value
499 WaitObject* object = itr->get();
500 object->Acquire(thread);
501 *index = static_cast<s32>(std::distance(objects.begin(), itr));
502 return RESULT_SUCCESS;
503 }
504
505 // No objects were ready to be acquired, prepare to suspend the thread.
506
507 // If a timeout value of 0 was provided, just return the Timeout error code instead of
508 // suspending the thread.
509 if (nano_seconds == 0) {
510 return RESULT_TIMEOUT;
511 }
512
513 if (thread->IsSyncCancelled()) {
514 thread->SetSyncCancelled(false);
515 return ERR_SYNCHRONIZATION_CANCELED;
516 }
517
518 for (auto& object : objects) {
519 object->AddWaitingThread(SharedFrom(thread));
520 }
521
522 thread->SetWaitObjects(std::move(objects));
523 thread->SetStatus(ThreadStatus::WaitSynch);
524
525 // Create an event to wake the thread up after the specified nanosecond delay has passed
526 thread->WakeAfterDelay(nano_seconds);
527 thread->SetWakeupCallback(DefaultThreadWakeupCallback);
528
529 system.PrepareReschedule(thread->GetProcessorID());
530
531 return RESULT_TIMEOUT;
532} 480}
533 481
534/// Resumes a thread waiting on WaitSynchronization 482/// Resumes a thread waiting on WaitSynchronization
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
new file mode 100644
index 000000000..dc37fad1a
--- /dev/null
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -0,0 +1,87 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/hle/kernel/errors.h"
7#include "core/hle/kernel/handle_table.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/scheduler.h"
10#include "core/hle/kernel/synchronization.h"
11#include "core/hle/kernel/synchronization_object.h"
12#include "core/hle/kernel/thread.h"
13
14namespace Kernel {
15
16/// Default thread wakeup callback for WaitSynchronization
17static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
18 std::shared_ptr<SynchronizationObject> object,
19 std::size_t index) {
20 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
21
22 if (reason == ThreadWakeupReason::Timeout) {
23 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
24 return true;
25 }
26
27 ASSERT(reason == ThreadWakeupReason::Signal);
28 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
29 thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
30 return true;
31}
32
33Synchronization::Synchronization(Core::System& system) : system{system} {}
34
35void Synchronization::SignalObject(SynchronizationObject& obj) const {
36 if (obj.IsSignaled()) {
37 obj.WakeupAllWaitingThreads();
38 }
39}
40
41std::pair<ResultCode, Handle> Synchronization::WaitFor(
42 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
43 auto* const thread = system.CurrentScheduler().GetCurrentThread();
44 // Find the first object that is acquirable in the provided list of objects
45 const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(),
46 [thread](const std::shared_ptr<SynchronizationObject>& object) {
47 return object->IsSignaled();
48 });
49
50 if (itr != sync_objects.end()) {
51 // We found a ready object, acquire it and set the result value
52 SynchronizationObject* object = itr->get();
53 object->Acquire(thread);
54 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
55 return {RESULT_SUCCESS, index};
56 }
57
58 // No objects were ready to be acquired, prepare to suspend the thread.
59
60 // If a timeout value of 0 was provided, just return the Timeout error code instead of
61 // suspending the thread.
62 if (nano_seconds == 0) {
63 return {RESULT_TIMEOUT, InvalidHandle};
64 }
65
66 if (thread->IsSyncCancelled()) {
67 thread->SetSyncCancelled(false);
68 return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
69 }
70
71 for (auto& object : sync_objects) {
72 object->AddWaitingThread(SharedFrom(thread));
73 }
74
75 thread->SetSynchronizationObjects(std::move(sync_objects));
76 thread->SetStatus(ThreadStatus::WaitSynch);
77
78 // Create an event to wake the thread up after the specified nanosecond delay has passed
79 thread->WakeAfterDelay(nano_seconds);
80 thread->SetWakeupCallback(DefaultThreadWakeupCallback);
81
82 system.PrepareReschedule(thread->GetProcessorID());
83
84 return {RESULT_TIMEOUT, InvalidHandle};
85}
86
87} // namespace Kernel
diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h
new file mode 100644
index 000000000..379f4b1d3
--- /dev/null
+++ b/src/core/hle/kernel/synchronization.h
@@ -0,0 +1,44 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <utility>
9#include <vector>
10
11#include "core/hle/kernel/object.h"
12#include "core/hle/result.h"
13
14namespace Core {
15class System;
16} // namespace Core
17
18namespace Kernel {
19
20class SynchronizationObject;
21
22/**
23 * The 'Synchronization' class is an interface for handling synchronization methods
24 * used by Synchronization objects and synchronization SVCs. This centralizes processing of
25 * such
26 */
27class Synchronization {
28public:
29 explicit Synchronization(Core::System& system);
30
31 /// Signals a synchronization object, waking up all its waiting threads
32 void SignalObject(SynchronizationObject& obj) const;
33
34 /// Tries to see if waiting for any of the sync_objects is necessary, if not
35 /// it returns Success and the handle index of the signaled sync object. In
36 /// case not, the current thread will be locked and wait for nano_seconds or
37 /// for a synchronization object to signal.
38 std::pair<ResultCode, Handle> WaitFor(
39 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds);
40
41private:
42 Core::System& system;
43};
44} // namespace Kernel
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/synchronization_object.cpp
index 1838260fd..43f3eef18 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/synchronization_object.cpp
@@ -10,20 +10,26 @@
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/object.h" 11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/synchronization.h"
14#include "core/hle/kernel/synchronization_object.h"
13#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
14 16
15namespace Kernel { 17namespace Kernel {
16 18
17WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {} 19SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
18WaitObject::~WaitObject() = default; 20SynchronizationObject::~SynchronizationObject() = default;
19 21
20void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) { 22void SynchronizationObject::Signal() {
23 kernel.Synchronization().SignalObject(*this);
24}
25
26void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
21 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); 27 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
22 if (itr == waiting_threads.end()) 28 if (itr == waiting_threads.end())
23 waiting_threads.push_back(std::move(thread)); 29 waiting_threads.push_back(std::move(thread));
24} 30}
25 31
26void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { 32void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
27 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); 33 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
28 // If a thread passed multiple handles to the same object, 34 // If a thread passed multiple handles to the same object,
29 // the kernel might attempt to remove the thread from the object's 35 // the kernel might attempt to remove the thread from the object's
@@ -32,7 +38,7 @@ void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
32 waiting_threads.erase(itr); 38 waiting_threads.erase(itr);
33} 39}
34 40
35std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { 41std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
36 Thread* candidate = nullptr; 42 Thread* candidate = nullptr;
37 u32 candidate_priority = THREADPRIO_LOWEST + 1; 43 u32 candidate_priority = THREADPRIO_LOWEST + 1;
38 44
@@ -57,7 +63,7 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
57 return SharedFrom(candidate); 63 return SharedFrom(candidate);
58} 64}
59 65
60void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { 66void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
61 ASSERT(!ShouldWait(thread.get())); 67 ASSERT(!ShouldWait(thread.get()));
62 68
63 if (!thread) { 69 if (!thread) {
@@ -65,7 +71,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
65 } 71 }
66 72
67 if (thread->IsSleepingOnWait()) { 73 if (thread->IsSleepingOnWait()) {
68 for (const auto& object : thread->GetWaitObjects()) { 74 for (const auto& object : thread->GetSynchronizationObjects()) {
69 ASSERT(!object->ShouldWait(thread.get())); 75 ASSERT(!object->ShouldWait(thread.get()));
70 object->Acquire(thread.get()); 76 object->Acquire(thread.get());
71 } 77 }
@@ -73,9 +79,9 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
73 Acquire(thread.get()); 79 Acquire(thread.get());
74 } 80 }
75 81
76 const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this)); 82 const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
77 83
78 thread->ClearWaitObjects(); 84 thread->ClearSynchronizationObjects();
79 85
80 thread->CancelWakeupTimer(); 86 thread->CancelWakeupTimer();
81 87
@@ -90,13 +96,13 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
90 } 96 }
91} 97}
92 98
93void WaitObject::WakeupAllWaitingThreads() { 99void SynchronizationObject::WakeupAllWaitingThreads() {
94 while (auto thread = GetHighestPriorityReadyThread()) { 100 while (auto thread = GetHighestPriorityReadyThread()) {
95 WakeupWaitingThread(thread); 101 WakeupWaitingThread(thread);
96 } 102 }
97} 103}
98 104
99const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const { 105const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
100 return waiting_threads; 106 return waiting_threads;
101} 107}
102 108
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/synchronization_object.h
index 9a17958a4..741c31faf 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/synchronization_object.h
@@ -15,10 +15,10 @@ class KernelCore;
15class Thread; 15class Thread;
16 16
17/// Class that represents a Kernel object that a thread can be waiting on 17/// Class that represents a Kernel object that a thread can be waiting on
18class WaitObject : public Object { 18class SynchronizationObject : public Object {
19public: 19public:
20 explicit WaitObject(KernelCore& kernel); 20 explicit SynchronizationObject(KernelCore& kernel);
21 ~WaitObject() override; 21 ~SynchronizationObject() override;
22 22
23 /** 23 /**
24 * Check if the specified thread should wait until the object is available 24 * Check if the specified thread should wait until the object is available
@@ -30,6 +30,13 @@ public:
30 /// Acquire/lock the object for the specified thread if it is available 30 /// Acquire/lock the object for the specified thread if it is available
31 virtual void Acquire(Thread* thread) = 0; 31 virtual void Acquire(Thread* thread) = 0;
32 32
33 /// Signal this object
34 virtual void Signal();
35
36 virtual bool IsSignaled() const {
37 return is_signaled;
38 }
39
33 /** 40 /**
34 * Add a thread to wait on this object 41 * Add a thread to wait on this object
35 * @param thread Pointer to thread to add 42 * @param thread Pointer to thread to add
@@ -60,16 +67,20 @@ public:
60 /// Get a const reference to the waiting threads list for debug use 67 /// Get a const reference to the waiting threads list for debug use
61 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; 68 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
62 69
70protected:
71 bool is_signaled{}; // Tells if this sync object is signalled;
72
63private: 73private:
64 /// Threads waiting for this object to become available 74 /// Threads waiting for this object to become available
65 std::vector<std::shared_ptr<Thread>> waiting_threads; 75 std::vector<std::shared_ptr<Thread>> waiting_threads;
66}; 76};
67 77
68// Specialization of DynamicObjectCast for WaitObjects 78// Specialization of DynamicObjectCast for SynchronizationObjects
69template <> 79template <>
70inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) { 80inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>(
81 std::shared_ptr<Object> object) {
71 if (object != nullptr && object->IsWaitable()) { 82 if (object != nullptr && object->IsWaitable()) {
72 return std::static_pointer_cast<WaitObject>(object); 83 return std::static_pointer_cast<SynchronizationObject>(object);
73 } 84 }
74 return nullptr; 85 return nullptr;
75} 86}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ad464e03b..ae5f2c8bd 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -15,6 +15,7 @@
15#include "core/core.h" 15#include "core/core.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/core_timing_util.h" 17#include "core/core_timing_util.h"
18#include "core/hardware_properties.h"
18#include "core/hle/kernel/errors.h" 19#include "core/hle/kernel/errors.h"
19#include "core/hle/kernel/handle_table.h" 20#include "core/hle/kernel/handle_table.h"
20#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
@@ -31,11 +32,15 @@ bool Thread::ShouldWait(const Thread* thread) const {
31 return status != ThreadStatus::Dead; 32 return status != ThreadStatus::Dead;
32} 33}
33 34
35bool Thread::IsSignaled() const {
36 return status == ThreadStatus::Dead;
37}
38
34void Thread::Acquire(Thread* thread) { 39void Thread::Acquire(Thread* thread) {
35 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 40 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
36} 41}
37 42
38Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {} 43Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {}
39Thread::~Thread() = default; 44Thread::~Thread() = default;
40 45
41void Thread::Stop() { 46void Thread::Stop() {
@@ -45,7 +50,7 @@ void Thread::Stop() {
45 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); 50 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
46 callback_handle = 0; 51 callback_handle = 0;
47 SetStatus(ThreadStatus::Dead); 52 SetStatus(ThreadStatus::Dead);
48 WakeupAllWaitingThreads(); 53 Signal();
49 54
50 // Clean up any dangling references in objects that this thread was waiting for 55 // Clean up any dangling references in objects that this thread was waiting for
51 for (auto& wait_object : wait_objects) { 56 for (auto& wait_object : wait_objects) {
@@ -215,7 +220,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
215 context.cpu_registers[1] = output; 220 context.cpu_registers[1] = output;
216} 221}
217 222
218s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const { 223s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const {
219 ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); 224 ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
220 const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); 225 const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
221 return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1); 226 return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
@@ -336,14 +341,16 @@ void Thread::ChangeCore(u32 core, u64 mask) {
336 SetCoreAndAffinityMask(core, mask); 341 SetCoreAndAffinityMask(core, mask);
337} 342}
338 343
339bool Thread::AllWaitObjectsReady() const { 344bool Thread::AllSynchronizationObjectsReady() const {
340 return std::none_of( 345 return std::none_of(wait_objects.begin(), wait_objects.end(),
341 wait_objects.begin(), wait_objects.end(), 346 [this](const std::shared_ptr<SynchronizationObject>& object) {
342 [this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); }); 347 return object->ShouldWait(this);
348 });
343} 349}
344 350
345bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, 351bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
346 std::shared_ptr<WaitObject> object, std::size_t index) { 352 std::shared_ptr<SynchronizationObject> object,
353 std::size_t index) {
347 ASSERT(wakeup_callback); 354 ASSERT(wakeup_callback);
348 return wakeup_callback(reason, std::move(thread), std::move(object), index); 355 return wakeup_callback(reason, std::move(thread), std::move(object), index);
349} 356}
@@ -425,7 +432,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
425 const s32 old_core = processor_id; 432 const s32 old_core = processor_id;
426 if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { 433 if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) {
427 if (static_cast<s32>(ideal_core) < 0) { 434 if (static_cast<s32>(ideal_core) < 0) {
428 processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES); 435 processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES);
429 } else { 436 } else {
430 processor_id = ideal_core; 437 processor_id = ideal_core;
431 } 438 }
@@ -449,7 +456,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
449 scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this); 456 scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this);
450 } 457 }
451 458
452 for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { 459 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
453 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { 460 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
454 scheduler.Unsuggest(current_priority, core, this); 461 scheduler.Unsuggest(current_priority, core, this);
455 } 462 }
@@ -460,7 +467,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
460 scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this); 467 scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this);
461 } 468 }
462 469
463 for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { 470 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
464 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { 471 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
465 scheduler.Suggest(current_priority, core, this); 472 scheduler.Suggest(current_priority, core, this);
466 } 473 }
@@ -479,7 +486,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
479 scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this); 486 scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
480 } 487 }
481 488
482 for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { 489 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
483 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { 490 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
484 scheduler.Unsuggest(old_priority, core, this); 491 scheduler.Unsuggest(old_priority, core, this);
485 } 492 }
@@ -496,7 +503,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
496 } 503 }
497 } 504 }
498 505
499 for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { 506 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
500 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { 507 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
501 scheduler.Suggest(current_priority, core, this); 508 scheduler.Suggest(current_priority, core, this);
502 } 509 }
@@ -512,7 +519,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
512 return; 519 return;
513 } 520 }
514 521
515 for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { 522 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
516 if (((old_affinity_mask >> core) & 1) != 0) { 523 if (((old_affinity_mask >> core) & 1) != 0) {
517 if (core == static_cast<u32>(old_core)) { 524 if (core == static_cast<u32>(old_core)) {
518 scheduler.Unschedule(current_priority, core, this); 525 scheduler.Unschedule(current_priority, core, this);
@@ -522,7 +529,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
522 } 529 }
523 } 530 }
524 531
525 for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { 532 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
526 if (((affinity_mask >> core) & 1) != 0) { 533 if (((affinity_mask >> core) & 1) != 0) {
527 if (core == static_cast<u32>(processor_id)) { 534 if (core == static_cast<u32>(processor_id)) {
528 scheduler.Schedule(current_priority, core, this); 535 scheduler.Schedule(current_priority, core, this);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 3bcf9e137..7a4916318 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -11,7 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/arm/arm_interface.h" 12#include "core/arm/arm_interface.h"
13#include "core/hle/kernel/object.h" 13#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/wait_object.h" 14#include "core/hle/kernel/synchronization_object.h"
15#include "core/hle/result.h" 15#include "core/hle/result.h"
16 16
17namespace Kernel { 17namespace Kernel {
@@ -95,7 +95,7 @@ enum class ThreadSchedMasks : u32 {
95 ForcePauseMask = 0x0070, 95 ForcePauseMask = 0x0070,
96}; 96};
97 97
98class Thread final : public WaitObject { 98class Thread final : public SynchronizationObject {
99public: 99public:
100 explicit Thread(KernelCore& kernel); 100 explicit Thread(KernelCore& kernel);
101 ~Thread() override; 101 ~Thread() override;
@@ -104,11 +104,11 @@ public:
104 104
105 using ThreadContext = Core::ARM_Interface::ThreadContext; 105 using ThreadContext = Core::ARM_Interface::ThreadContext;
106 106
107 using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>; 107 using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>;
108 108
109 using WakeupCallback = 109 using WakeupCallback =
110 std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, 110 std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
111 std::shared_ptr<WaitObject> object, std::size_t index)>; 111 std::shared_ptr<SynchronizationObject> object, std::size_t index)>;
112 112
113 /** 113 /**
114 * Creates and returns a new thread. The new thread is immediately scheduled 114 * Creates and returns a new thread. The new thread is immediately scheduled
@@ -146,6 +146,7 @@ public:
146 146
147 bool ShouldWait(const Thread* thread) const override; 147 bool ShouldWait(const Thread* thread) const override;
148 void Acquire(Thread* thread) override; 148 void Acquire(Thread* thread) override;
149 bool IsSignaled() const override;
149 150
150 /** 151 /**
151 * Gets the thread's current priority 152 * Gets the thread's current priority
@@ -233,7 +234,7 @@ public:
233 * 234 *
234 * @param object Object to query the index of. 235 * @param object Object to query the index of.
235 */ 236 */
236 s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const; 237 s32 GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const;
237 238
238 /** 239 /**
239 * Stops a thread, invalidating it from further use 240 * Stops a thread, invalidating it from further use
@@ -314,15 +315,15 @@ public:
314 return owner_process; 315 return owner_process;
315 } 316 }
316 317
317 const ThreadWaitObjects& GetWaitObjects() const { 318 const ThreadSynchronizationObjects& GetSynchronizationObjects() const {
318 return wait_objects; 319 return wait_objects;
319 } 320 }
320 321
321 void SetWaitObjects(ThreadWaitObjects objects) { 322 void SetSynchronizationObjects(ThreadSynchronizationObjects objects) {
322 wait_objects = std::move(objects); 323 wait_objects = std::move(objects);
323 } 324 }
324 325
325 void ClearWaitObjects() { 326 void ClearSynchronizationObjects() {
326 for (const auto& waiting_object : wait_objects) { 327 for (const auto& waiting_object : wait_objects) {
327 waiting_object->RemoveWaitingThread(SharedFrom(this)); 328 waiting_object->RemoveWaitingThread(SharedFrom(this));
328 } 329 }
@@ -330,7 +331,7 @@ public:
330 } 331 }
331 332
332 /// Determines whether all the objects this thread is waiting on are ready. 333 /// Determines whether all the objects this thread is waiting on are ready.
333 bool AllWaitObjectsReady() const; 334 bool AllSynchronizationObjectsReady() const;
334 335
335 const MutexWaitingThreads& GetMutexWaitingThreads() const { 336 const MutexWaitingThreads& GetMutexWaitingThreads() const {
336 return wait_mutex_threads; 337 return wait_mutex_threads;
@@ -395,7 +396,7 @@ public:
395 * will cause an assertion to trigger. 396 * will cause an assertion to trigger.
396 */ 397 */
397 bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, 398 bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
398 std::shared_ptr<WaitObject> object, std::size_t index); 399 std::shared_ptr<SynchronizationObject> object, std::size_t index);
399 400
400 u32 GetIdealCore() const { 401 u32 GetIdealCore() const {
401 return ideal_core; 402 return ideal_core;
@@ -494,7 +495,7 @@ private:
494 495
495 /// Objects that the thread is waiting on, in the same order as they were 496 /// Objects that the thread is waiting on, in the same order as they were
496 /// passed to WaitSynchronization. 497 /// passed to WaitSynchronization.
497 ThreadWaitObjects wait_objects; 498 ThreadSynchronizationObjects wait_objects;
498 499
499 /// List of threads that are waiting for a mutex that is held by this thread. 500 /// List of threads that are waiting for a mutex that is held by this thread.
500 MutexWaitingThreads wait_mutex_threads; 501 MutexWaitingThreads wait_mutex_threads;
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
index c9332e3e1..fc2f7c424 100644
--- a/src/core/hle/kernel/writable_event.cpp
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -22,7 +22,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
22 writable_event->name = name + ":Writable"; 22 writable_event->name = name + ":Writable";
23 writable_event->readable = readable_event; 23 writable_event->readable = readable_event;
24 readable_event->name = name + ":Readable"; 24 readable_event->name = name + ":Readable";
25 readable_event->signaled = false;
26 25
27 return {std::move(readable_event), std::move(writable_event)}; 26 return {std::move(readable_event), std::move(writable_event)};
28} 27}
@@ -40,7 +39,7 @@ void WritableEvent::Clear() {
40} 39}
41 40
42bool WritableEvent::IsSignaled() const { 41bool WritableEvent::IsSignaled() const {
43 return readable->signaled; 42 return readable->IsSignaled();
44} 43}
45 44
46} // namespace Kernel 45} // namespace Kernel
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index cb839e4a2..d19513cbb 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -170,8 +170,10 @@ public:
170 {3, nullptr, "SetContextForMultiStream"}, 170 {3, nullptr, "SetContextForMultiStream"},
171 {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, 171 {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
172 {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"}, 172 {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
173 {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, 173 {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
174 {7, nullptr, "DecodeInterleavedForMultiStream"}, 174 {7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
175 {8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
176 {9, nullptr, "DecodeInterleavedForMultiStream"},
175 }; 177 };
176 // clang-format on 178 // clang-format on
177 179
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 89bf8b815..e6b56a9f9 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -10,6 +10,7 @@
10#include "core/core_timing_util.h" 10#include "core/core_timing_util.h"
11#include "core/frontend/emu_window.h" 11#include "core/frontend/emu_window.h"
12#include "core/frontend/input.h" 12#include "core/frontend/input.h"
13#include "core/hardware_properties.h"
13#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/client_port.h" 15#include "core/hle/kernel/client_port.h"
15#include "core/hle/kernel/client_session.h" 16#include "core/hle/kernel/client_session.h"
@@ -37,11 +38,11 @@ namespace Service::HID {
37 38
38// Updating period for each HID device. 39// Updating period for each HID device.
39// TODO(ogniK): Find actual polling rate of hid 40// TODO(ogniK): Find actual polling rate of hid
40constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66); 41constexpr s64 pad_update_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 66);
41[[maybe_unused]] constexpr s64 accelerometer_update_ticks = 42[[maybe_unused]] constexpr s64 accelerometer_update_ticks =
42 static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); 43 static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100);
43[[maybe_unused]] constexpr s64 gyroscope_update_ticks = 44[[maybe_unused]] constexpr s64 gyroscope_update_ticks =
44 static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); 45 static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100);
45constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 46constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
46 47
47IAppletResource::IAppletResource(Core::System& system) 48IAppletResource::IAppletResource(Core::System& system)
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index ed5059047..92adde6d4 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -129,12 +129,20 @@ public:
129 {304, nullptr, "Disconnect"}, 129 {304, nullptr, "Disconnect"},
130 {400, nullptr, "Initialize"}, 130 {400, nullptr, "Initialize"},
131 {401, nullptr, "Finalize"}, 131 {401, nullptr, "Finalize"},
132 {402, nullptr, "SetOperationMode"}, 132 {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+
133 }; 133 };
134 // clang-format on 134 // clang-format on
135 135
136 RegisterHandlers(functions); 136 RegisterHandlers(functions);
137 } 137 }
138
139 void Initialize2(Kernel::HLERequestContext& ctx) {
140 LOG_WARNING(Service_LDN, "(STUBBED) called");
141 // Result success seem make this services start network and continue.
142 // If we just pass result error then it will stop and maybe try again and again.
143 IPC::ResponseBuilder rb{ctx, 2};
144 rb.Push(RESULT_UNKNOWN);
145 }
138}; 146};
139 147
140class LDNS final : public ServiceFramework<LDNS> { 148class LDNS final : public ServiceFramework<LDNS> {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 6d8bca8bb..f1966ac0e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -44,6 +44,8 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
44 return GetWaitbase(input, output); 44 return GetWaitbase(input, output);
45 case IoctlCommand::IocChannelSetTimeoutCommand: 45 case IoctlCommand::IocChannelSetTimeoutCommand:
46 return ChannelSetTimeout(input, output); 46 return ChannelSetTimeout(input, output);
47 case IoctlCommand::IocChannelSetTimeslice:
48 return ChannelSetTimeslice(input, output);
47 default: 49 default:
48 break; 50 break;
49 } 51 }
@@ -228,4 +230,14 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>&
228 return 0; 230 return 0;
229} 231}
230 232
233u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
234 IoctlSetTimeslice params{};
235 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
236 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
237
238 channel_timeslice = params.timeslice;
239
240 return 0;
241}
242
231} // namespace Service::Nvidia::Devices 243} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index d056dd046..2ac74743f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -48,6 +48,7 @@ private:
48 IocAllocObjCtxCommand = 0xC0104809, 48 IocAllocObjCtxCommand = 0xC0104809,
49 IocChannelGetWaitbaseCommand = 0xC0080003, 49 IocChannelGetWaitbaseCommand = 0xC0080003,
50 IocChannelSetTimeoutCommand = 0x40044803, 50 IocChannelSetTimeoutCommand = 0x40044803,
51 IocChannelSetTimeslice = 0xC004481D,
51 }; 52 };
52 53
53 enum class CtxObjects : u32_le { 54 enum class CtxObjects : u32_le {
@@ -101,6 +102,11 @@ private:
101 static_assert(sizeof(IoctlChannelSetPriority) == 4, 102 static_assert(sizeof(IoctlChannelSetPriority) == 4,
102 "IoctlChannelSetPriority is incorrect size"); 103 "IoctlChannelSetPriority is incorrect size");
103 104
105 struct IoctlSetTimeslice {
106 u32_le timeslice;
107 };
108 static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
109
104 struct IoctlEventIdControl { 110 struct IoctlEventIdControl {
105 u32_le cmd; // 0=disable, 1=enable, 2=clear 111 u32_le cmd; // 0=disable, 1=enable, 2=clear
106 u32_le id; 112 u32_le id;
@@ -174,6 +180,7 @@ private:
174 u64_le user_data{}; 180 u64_le user_data{};
175 IoctlZCullBind zcull_params{}; 181 IoctlZCullBind zcull_params{};
176 u32_le channel_priority{}; 182 u32_le channel_priority{};
183 u32_le channel_timeslice{};
177 184
178 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 185 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
179 u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); 186 u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
@@ -188,6 +195,7 @@ private:
188 const std::vector<u8>& input2, IoctlVersion version); 195 const std::vector<u8>& input2, IoctlVersion version);
189 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 196 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
190 u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); 197 u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
198 u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
191 199
192 std::shared_ptr<nvmap> nvmap_dev; 200 std::shared_ptr<nvmap> nvmap_dev;
193 u32 assigned_syncpoints{}; 201 u32 assigned_syncpoints{};
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 62752e419..134152210 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -12,6 +12,7 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/core_timing_util.h" 14#include "core/core_timing_util.h"
15#include "core/hardware_properties.h"
15#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/readable_event.h" 17#include "core/hle/kernel/readable_event.h"
17#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 18#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
@@ -26,8 +27,8 @@
26 27
27namespace Service::NVFlinger { 28namespace Service::NVFlinger {
28 29
29constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); 30constexpr s64 frame_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60);
30constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); 31constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 30);
31 32
32NVFlinger::NVFlinger(Core::System& system) : system(system) { 33NVFlinger::NVFlinger(Core::System& system) : system(system) {
33 displays.emplace_back(0, "Default", system); 34 displays.emplace_back(0, "Default", system);
@@ -222,7 +223,7 @@ void NVFlinger::Compose() {
222 223
223s64 NVFlinger::GetNextTicks() const { 224s64 NVFlinger::GetNextTicks() const {
224 constexpr s64 max_hertz = 120LL; 225 constexpr s64 max_hertz = 120LL;
225 return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; 226 return (Core::Hardware::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz;
226} 227}
227 228
228} // namespace Service::NVFlinger 229} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp
index ca1a783fc..1575f0b49 100644
--- a/src/core/hle/service/time/standard_steady_clock_core.cpp
+++ b/src/core/hle/service/time/standard_steady_clock_core.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/core_timing.h" 6#include "core/core_timing.h"
7#include "core/core_timing_util.h" 7#include "core/core_timing_util.h"
8#include "core/hardware_properties.h"
8#include "core/hle/service/time/standard_steady_clock_core.h" 9#include "core/hle/service/time/standard_steady_clock_core.h"
9 10
10namespace Service::Time::Clock { 11namespace Service::Time::Clock {
@@ -12,7 +13,7 @@ namespace Service::Time::Clock {
12TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { 13TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
13 const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( 14 const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
14 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), 15 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
15 Core::Timing::CNTFREQ)}; 16 Core::Hardware::CNTFREQ)};
16 TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; 17 TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
17 18
18 if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { 19 if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
index c77b98189..44d5bc651 100644
--- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp
+++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/core_timing.h" 6#include "core/core_timing.h"
7#include "core/core_timing_util.h" 7#include "core/core_timing_util.h"
8#include "core/hardware_properties.h"
8#include "core/hle/service/time/tick_based_steady_clock_core.h" 9#include "core/hle/service/time/tick_based_steady_clock_core.h"
9 10
10namespace Service::Time::Clock { 11namespace Service::Time::Clock {
@@ -12,7 +13,7 @@ namespace Service::Time::Clock {
12SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { 13SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
13 const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( 14 const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
14 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), 15 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
15 Core::Timing::CNTFREQ)}; 16 Core::Hardware::CNTFREQ)};
16 17
17 return {ticks_time_span.ToSeconds(), GetClockSourceId()}; 18 return {ticks_time_span.ToSeconds(), GetClockSourceId()};
18} 19}
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 8ef4efcef..749b7be70 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -6,6 +6,7 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/core_timing_util.h" 8#include "core/core_timing_util.h"
9#include "core/hardware_properties.h"
9#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/client_port.h" 11#include "core/hle/kernel/client_port.h"
11#include "core/hle/kernel/client_session.h" 12#include "core/hle/kernel/client_session.h"
@@ -233,7 +234,7 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
233 if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { 234 if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
234 const auto ticks{Clock::TimeSpanType::FromTicks( 235 const auto ticks{Clock::TimeSpanType::FromTicks(
235 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), 236 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
236 Core::Timing::CNTFREQ)}; 237 Core::Hardware::CNTFREQ)};
237 const s64 base_time_point{context.offset + current_time_point.time_point - 238 const s64 base_time_point{context.offset + current_time_point.time_point -
238 ticks.ToSeconds()}; 239 ticks.ToSeconds()};
239 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; 240 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index 9b03191bf..fdaef233f 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/core_timing.h" 6#include "core/core_timing.h"
7#include "core/core_timing_util.h" 7#include "core/core_timing_util.h"
8#include "core/hardware_properties.h"
8#include "core/hle/service/time/clock_types.h" 9#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/steady_clock_core.h" 10#include "core/hle/service/time/steady_clock_core.h"
10#include "core/hle/service/time/time_sharedmemory.h" 11#include "core/hle/service/time/time_sharedmemory.h"
@@ -31,7 +32,7 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system,
31 Clock::TimeSpanType current_time_point) { 32 Clock::TimeSpanType current_time_point) {
32 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( 33 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
33 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), 34 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
34 Core::Timing::CNTFREQ)}; 35 Core::Hardware::CNTFREQ)};
35 const Clock::SteadyClockContext context{ 36 const Clock::SteadyClockContext context{
36 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), 37 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
37 clock_source_id}; 38 clock_source_id};
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index d1e6bed93..4472500d2 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -9,6 +9,7 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/core_timing.h" 10#include "core/core_timing.h"
11#include "core/core_timing_util.h" 11#include "core/core_timing_util.h"
12#include "core/hardware_properties.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
13#include "core/hle/service/hid/controllers/npad.h" 14#include "core/hle/service/hid/controllers/npad.h"
14#include "core/hle/service/hid/hid.h" 15#include "core/hle/service/hid/hid.h"
@@ -17,7 +18,7 @@
17 18
18namespace Memory { 19namespace Memory {
19 20
20constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12); 21constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 12);
21constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; 22constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
22 23
23StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) 24StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 55e0dbc49..1e060f009 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -7,13 +7,14 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/core_timing_util.h" 9#include "core/core_timing_util.h"
10#include "core/hardware_properties.h"
10#include "core/memory.h" 11#include "core/memory.h"
11#include "core/tools/freezer.h" 12#include "core/tools/freezer.h"
12 13
13namespace Tools { 14namespace Tools {
14namespace { 15namespace {
15 16
16constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); 17constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60);
17 18
18u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) { 19u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
19 switch (width) { 20 switch (width) {
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7cea146f0..0b3e8749b 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -9,6 +9,7 @@
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/engines/shader_type.h" 11#include "video_core/engines/shader_type.h"
12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
14#include "video_core/textures/texture.h" 15#include "video_core/textures/texture.h"
@@ -519,61 +520,63 @@ void Maxwell3D::ProcessFirmwareCall4() {
519 regs.reg_array[0xd00] = 1; 520 regs.reg_array[0xd00] = 1;
520} 521}
521 522
522void Maxwell3D::ProcessQueryGet() { 523void Maxwell3D::StampQueryResult(u64 payload, bool long_query) {
524 struct LongQueryResult {
525 u64_le value;
526 u64_le timestamp;
527 };
528 static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size");
523 const GPUVAddr sequence_address{regs.query.QueryAddress()}; 529 const GPUVAddr sequence_address{regs.query.QueryAddress()};
524 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application 530 if (long_query) {
525 // VAddr before writing. 531 // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast
532 // GPU, this command may actually take a while to complete in real hardware due to GPU
533 // wait queues.
534 LongQueryResult query_result{payload, system.GPU().GetTicks()};
535 memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result));
536 } else {
537 memory_manager.Write<u32>(sequence_address, static_cast<u32>(payload));
538 }
539}
526 540
541void Maxwell3D::ProcessQueryGet() {
527 // TODO(Subv): Support the other query units. 542 // TODO(Subv): Support the other query units.
528 ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, 543 ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop,
529 "Units other than CROP are unimplemented"); 544 "Units other than CROP are unimplemented");
530 545
531 u64 result = 0; 546 switch (regs.query.query_get.operation) {
532 547 case Regs::QueryOperation::Release: {
533 // TODO(Subv): Support the other query variables 548 const u64 result = regs.query.query_sequence;
534 switch (regs.query.query_get.select) { 549 StampQueryResult(result, regs.query.query_get.short_query == 0);
535 case Regs::QuerySelect::Zero:
536 // This seems to actually write the query sequence to the query address.
537 result = regs.query.query_sequence;
538 break; 550 break;
539 default:
540 result = 1;
541 UNIMPLEMENTED_MSG("Unimplemented query select type {}",
542 static_cast<u32>(regs.query.query_get.select.Value()));
543 } 551 }
544 552 case Regs::QueryOperation::Acquire: {
545 // TODO(Subv): Research and implement how query sync conditions work. 553 // Todo(Blinkhawk): Under this operation, the GPU waits for the CPU
546 554 // to write a value that matches the current payload.
547 struct LongQueryResult { 555 UNIMPLEMENTED_MSG("Unimplemented query operation ACQUIRE");
548 u64_le value; 556 break;
549 u64_le timestamp; 557 }
550 }; 558 case Regs::QueryOperation::Counter: {
551 static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size"); 559 u64 result{};
552 560 switch (regs.query.query_get.select) {
553 switch (regs.query.query_get.mode) { 561 case Regs::QuerySelect::Zero:
554 case Regs::QueryMode::Write: 562 result = 0;
555 case Regs::QueryMode::Write2: { 563 break;
556 u32 sequence = regs.query.query_sequence; 564 default:
557 if (regs.query.query_get.short_query) { 565 result = 1;
558 // Write the current query sequence to the sequence address. 566 UNIMPLEMENTED_MSG("Unimplemented query select type {}",
559 // TODO(Subv): Find out what happens if you use a long query type but mark it as a short 567 static_cast<u32>(regs.query.query_get.select.Value()));
560 // query.
561 memory_manager.Write<u32>(sequence_address, sequence);
562 } else {
563 // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast
564 // GPU, this command may actually take a while to complete in real hardware due to GPU
565 // wait queues.
566 LongQueryResult query_result{};
567 query_result.value = result;
568 // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming
569 query_result.timestamp = system.CoreTiming().GetTicks();
570 memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result));
571 } 568 }
569 StampQueryResult(result, regs.query.query_get.short_query == 0);
570 break;
571 }
572 case Regs::QueryOperation::Trap: {
573 UNIMPLEMENTED_MSG("Unimplemented query operation TRAP");
574 break;
575 }
576 default: {
577 UNIMPLEMENTED_MSG("Unknown query operation");
572 break; 578 break;
573 } 579 }
574 default:
575 UNIMPLEMENTED_MSG("Query mode {} not implemented",
576 static_cast<u32>(regs.query.query_get.mode.Value()));
577 } 580 }
578} 581}
579 582
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 7b1912a66..0a2af54e5 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -71,12 +71,11 @@ public:
71 static constexpr std::size_t MaxConstBuffers = 18; 71 static constexpr std::size_t MaxConstBuffers = 18;
72 static constexpr std::size_t MaxConstBufferSize = 0x10000; 72 static constexpr std::size_t MaxConstBufferSize = 0x10000;
73 73
74 enum class QueryMode : u32 { 74 enum class QueryOperation : u32 {
75 Write = 0, 75 Release = 0,
76 Sync = 1, 76 Acquire = 1,
77 // TODO(Subv): It is currently unknown what the difference between method 2 and method 0 77 Counter = 2,
78 // is. 78 Trap = 3,
79 Write2 = 2,
80 }; 79 };
81 80
82 enum class QueryUnit : u32 { 81 enum class QueryUnit : u32 {
@@ -1081,7 +1080,7 @@ public:
1081 u32 query_sequence; 1080 u32 query_sequence;
1082 union { 1081 union {
1083 u32 raw; 1082 u32 raw;
1084 BitField<0, 2, QueryMode> mode; 1083 BitField<0, 2, QueryOperation> operation;
1085 BitField<4, 1, u32> fence; 1084 BitField<4, 1, u32> fence;
1086 BitField<12, 4, QueryUnit> unit; 1085 BitField<12, 4, QueryUnit> unit;
1087 BitField<16, 1, QuerySyncCondition> sync_cond; 1086 BitField<16, 1, QuerySyncCondition> sync_cond;
@@ -1413,6 +1412,9 @@ private:
1413 /// Handles a write to the QUERY_GET register. 1412 /// Handles a write to the QUERY_GET register.
1414 void ProcessQueryGet(); 1413 void ProcessQueryGet();
1415 1414
1415 // Writes the query result accordingly
1416 void StampQueryResult(u64 payload, bool long_query);
1417
1416 // Handles Conditional Rendering 1418 // Handles Conditional Rendering
1417 void ProcessQueryCondition(); 1419 void ProcessQueryCondition();
1418 1420
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 402869fde..c9bc83cd7 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1677,11 +1677,11 @@ union Instruction {
1677 } xmad; 1677 } xmad;
1678 1678
1679 union { 1679 union {
1680 BitField<20, 14, u64> offset; 1680 BitField<20, 14, u64> shifted_offset;
1681 BitField<34, 5, u64> index; 1681 BitField<34, 5, u64> index;
1682 1682
1683 u64 GetOffset() const { 1683 u64 GetOffset() const {
1684 return offset * 4; 1684 return shifted_offset * 4;
1685 } 1685 }
1686 } cbuf34; 1686 } cbuf34;
1687 1687
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 062ca83b8..7d7137109 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -6,6 +6,7 @@
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/core_timing_util.h"
9#include "core/memory.h" 10#include "core/memory.h"
10#include "video_core/engines/fermi_2d.h" 11#include "video_core/engines/fermi_2d.h"
11#include "video_core/engines/kepler_compute.h" 12#include "video_core/engines/kepler_compute.h"
@@ -23,7 +24,7 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
23GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) 24GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async)
24 : system{system}, renderer{renderer}, is_async{is_async} { 25 : system{system}, renderer{renderer}, is_async{is_async} {
25 auto& rasterizer{renderer.Rasterizer()}; 26 auto& rasterizer{renderer.Rasterizer()};
26 memory_manager = std::make_unique<Tegra::MemoryManager>(system); 27 memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer);
27 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); 28 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
28 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); 29 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
29 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer); 30 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
@@ -122,6 +123,19 @@ bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
122 return true; 123 return true;
123} 124}
124 125
126u64 GPU::GetTicks() const {
127 // This values were reversed engineered by fincs from NVN
128 // The gpu clock is reported in units of 385/625 nanoseconds
129 constexpr u64 gpu_ticks_num = 384;
130 constexpr u64 gpu_ticks_den = 625;
131
132 const u64 cpu_ticks = system.CoreTiming().GetTicks();
133 const u64 nanoseconds = Core::Timing::CyclesToNs(cpu_ticks).count();
134 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
135 const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
136 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
137}
138
125void GPU::FlushCommands() { 139void GPU::FlushCommands() {
126 renderer.Rasterizer().FlushCommands(); 140 renderer.Rasterizer().FlushCommands();
127} 141}
@@ -340,7 +354,7 @@ void GPU::ProcessSemaphoreTriggerMethod() {
340 block.sequence = regs.semaphore_sequence; 354 block.sequence = regs.semaphore_sequence;
341 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of 355 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
342 // CoreTiming 356 // CoreTiming
343 block.timestamp = system.CoreTiming().GetTicks(); 357 block.timestamp = GetTicks();
344 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block, 358 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
345 sizeof(block)); 359 sizeof(block));
346 } else { 360 } else {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b648317bb..07727210c 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -192,6 +192,8 @@ public:
192 192
193 bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value); 193 bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
194 194
195 u64 GetTicks() const;
196
195 std::unique_lock<std::mutex> LockSync() { 197 std::unique_lock<std::mutex> LockSync() {
196 return std::unique_lock{sync_mutex}; 198 return std::unique_lock{sync_mutex};
197 } 199 }
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index f1d50be3e..11848fbce 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -9,12 +9,13 @@
9#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/vm_manager.h" 10#include "core/hle/kernel/vm_manager.h"
11#include "core/memory.h" 11#include "core/memory.h"
12#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
13#include "video_core/rasterizer_interface.h"
14 14
15namespace Tegra { 15namespace Tegra {
16 16
17MemoryManager::MemoryManager(Core::System& system) : system{system} { 17MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
18 : rasterizer{rasterizer}, system{system} {
18 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr); 19 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
19 std::fill(page_table.attributes.begin(), page_table.attributes.end(), 20 std::fill(page_table.attributes.begin(), page_table.attributes.end(),
20 Common::PageType::Unmapped); 21 Common::PageType::Unmapped);
@@ -83,8 +84,7 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
83 const auto cpu_addr = GpuToCpuAddress(gpu_addr); 84 const auto cpu_addr = GpuToCpuAddress(gpu_addr);
84 ASSERT(cpu_addr); 85 ASSERT(cpu_addr);
85 86
86 system.GPU().FlushAndInvalidateRegion(cache_addr, aligned_size); 87 rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size);
87
88 UnmapRange(gpu_addr, aligned_size); 88 UnmapRange(gpu_addr, aligned_size);
89 ASSERT(system.CurrentProcess() 89 ASSERT(system.CurrentProcess()
90 ->VMManager() 90 ->VMManager()
@@ -242,7 +242,7 @@ void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::s
242 switch (page_table.attributes[page_index]) { 242 switch (page_table.attributes[page_index]) {
243 case Common::PageType::Memory: { 243 case Common::PageType::Memory: {
244 const u8* src_ptr{page_table.pointers[page_index] + page_offset}; 244 const u8* src_ptr{page_table.pointers[page_index] + page_offset};
245 system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount); 245 rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
246 std::memcpy(dest_buffer, src_ptr, copy_amount); 246 std::memcpy(dest_buffer, src_ptr, copy_amount);
247 break; 247 break;
248 } 248 }
@@ -292,7 +292,7 @@ void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const
292 switch (page_table.attributes[page_index]) { 292 switch (page_table.attributes[page_index]) {
293 case Common::PageType::Memory: { 293 case Common::PageType::Memory: {
294 u8* dest_ptr{page_table.pointers[page_index] + page_offset}; 294 u8* dest_ptr{page_table.pointers[page_index] + page_offset};
295 system.GPU().InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount); 295 rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
296 std::memcpy(dest_ptr, src_buffer, copy_amount); 296 std::memcpy(dest_ptr, src_buffer, copy_amount);
297 break; 297 break;
298 } 298 }
@@ -340,7 +340,7 @@ void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::
340 switch (page_table.attributes[page_index]) { 340 switch (page_table.attributes[page_index]) {
341 case Common::PageType::Memory: { 341 case Common::PageType::Memory: {
342 const u8* src_ptr{page_table.pointers[page_index] + page_offset}; 342 const u8* src_ptr{page_table.pointers[page_index] + page_offset};
343 system.GPU().FlushRegion(ToCacheAddr(src_ptr), copy_amount); 343 rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
344 WriteBlock(dest_addr, src_ptr, copy_amount); 344 WriteBlock(dest_addr, src_ptr, copy_amount);
345 break; 345 break;
346 } 346 }
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 393447eb4..aea010087 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/page_table.h" 11#include "common/page_table.h"
12 12
13namespace VideoCore {
14class RasterizerInterface;
15}
16
13namespace Core { 17namespace Core {
14class System; 18class System;
15} 19}
@@ -47,7 +51,7 @@ struct VirtualMemoryArea {
47 51
48class MemoryManager final { 52class MemoryManager final {
49public: 53public:
50 explicit MemoryManager(Core::System& system); 54 explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
51 ~MemoryManager(); 55 ~MemoryManager();
52 56
53 GPUVAddr AllocateSpace(u64 size, u64 align); 57 GPUVAddr AllocateSpace(u64 size, u64 align);
@@ -172,6 +176,7 @@ private:
172 176
173 Common::PageTable page_table{page_bits}; 177 Common::PageTable page_table{page_bits};
174 VMAMap vma_map; 178 VMAMap vma_map;
179 VideoCore::RasterizerInterface& rasterizer;
175 180
176 Core::System& system; 181 Core::System& system;
177}; 182};
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index e60875cc4..21366869d 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -166,13 +166,13 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
166 const auto [op_rhs, test] = [&]() -> std::pair<Node, Node> { 166 const auto [op_rhs, test] = [&]() -> std::pair<Node, Node> {
167 switch (opcode->get().GetId()) { 167 switch (opcode->get().GetId()) {
168 case OpCode::Id::ICMP_CR: 168 case OpCode::Id::ICMP_CR:
169 return {GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset), 169 return {GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()),
170 GetRegister(instr.gpr39)}; 170 GetRegister(instr.gpr39)};
171 case OpCode::Id::ICMP_R: 171 case OpCode::Id::ICMP_R:
172 return {GetRegister(instr.gpr20), GetRegister(instr.gpr39)}; 172 return {GetRegister(instr.gpr20), GetRegister(instr.gpr39)};
173 case OpCode::Id::ICMP_RC: 173 case OpCode::Id::ICMP_RC:
174 return {GetRegister(instr.gpr39), 174 return {GetRegister(instr.gpr39),
175 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset)}; 175 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())};
176 case OpCode::Id::ICMP_IMM: 176 case OpCode::Id::ICMP_IMM:
177 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)}; 177 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)};
178 default: 178 default:
diff --git a/src/video_core/shader/decode/bfi.cpp b/src/video_core/shader/decode/bfi.cpp
index f992bbe2a..70d1c055b 100644
--- a/src/video_core/shader/decode/bfi.cpp
+++ b/src/video_core/shader/decode/bfi.cpp
@@ -21,7 +21,7 @@ u32 ShaderIR::DecodeBfi(NodeBlock& bb, u32 pc) {
21 switch (opcode->get().GetId()) { 21 switch (opcode->get().GetId()) {
22 case OpCode::Id::BFI_RC: 22 case OpCode::Id::BFI_RC:
23 return {GetRegister(instr.gpr39), 23 return {GetRegister(instr.gpr39),
24 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset)}; 24 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())};
25 case OpCode::Id::BFI_IMM_R: 25 case OpCode::Id::BFI_IMM_R:
26 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)}; 26 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)};
27 default: 27 default:
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 727bd8a94..3f1a94627 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -12,8 +12,8 @@
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/readable_event.h" 13#include "core/hle/kernel/readable_event.h"
14#include "core/hle/kernel/scheduler.h" 14#include "core/hle/kernel/scheduler.h"
15#include "core/hle/kernel/synchronization_object.h"
15#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
16#include "core/hle/kernel/wait_object.h"
17#include "core/memory.h" 17#include "core/memory.h"
18 18
19WaitTreeItem::WaitTreeItem() = default; 19WaitTreeItem::WaitTreeItem() = default;
@@ -133,8 +133,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
133 return list; 133 return list;
134} 134}
135 135
136WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} 136WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& o)
137WaitTreeWaitObject::~WaitTreeWaitObject() = default; 137 : object(o) {}
138WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
138 139
139WaitTreeExpandableItem::WaitTreeExpandableItem() = default; 140WaitTreeExpandableItem::WaitTreeExpandableItem() = default;
140WaitTreeExpandableItem::~WaitTreeExpandableItem() = default; 141WaitTreeExpandableItem::~WaitTreeExpandableItem() = default;
@@ -143,25 +144,26 @@ bool WaitTreeExpandableItem::IsExpandable() const {
143 return true; 144 return true;
144} 145}
145 146
146QString WaitTreeWaitObject::GetText() const { 147QString WaitTreeSynchronizationObject::GetText() const {
147 return tr("[%1]%2 %3") 148 return tr("[%1]%2 %3")
148 .arg(object.GetObjectId()) 149 .arg(object.GetObjectId())
149 .arg(QString::fromStdString(object.GetTypeName()), 150 .arg(QString::fromStdString(object.GetTypeName()),
150 QString::fromStdString(object.GetName())); 151 QString::fromStdString(object.GetName()));
151} 152}
152 153
153std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) { 154std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
155 const Kernel::SynchronizationObject& object) {
154 switch (object.GetHandleType()) { 156 switch (object.GetHandleType()) {
155 case Kernel::HandleType::ReadableEvent: 157 case Kernel::HandleType::ReadableEvent:
156 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object)); 158 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
157 case Kernel::HandleType::Thread: 159 case Kernel::HandleType::Thread:
158 return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object)); 160 return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object));
159 default: 161 default:
160 return std::make_unique<WaitTreeWaitObject>(object); 162 return std::make_unique<WaitTreeSynchronizationObject>(object);
161 } 163 }
162} 164}
163 165
164std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() const { 166std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
165 std::vector<std::unique_ptr<WaitTreeItem>> list; 167 std::vector<std::unique_ptr<WaitTreeItem>> list;
166 168
167 const auto& threads = object.GetWaitingThreads(); 169 const auto& threads = object.GetWaitingThreads();
@@ -173,8 +175,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() con
173 return list; 175 return list;
174} 176}
175 177
176WaitTreeObjectList::WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::WaitObject>>& list, 178WaitTreeObjectList::WaitTreeObjectList(
177 bool w_all) 179 const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list, bool w_all)
178 : object_list(list), wait_all(w_all) {} 180 : object_list(list), wait_all(w_all) {}
179 181
180WaitTreeObjectList::~WaitTreeObjectList() = default; 182WaitTreeObjectList::~WaitTreeObjectList() = default;
@@ -188,11 +190,12 @@ QString WaitTreeObjectList::GetText() const {
188std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const { 190std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const {
189 std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size()); 191 std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size());
190 std::transform(object_list.begin(), object_list.end(), list.begin(), 192 std::transform(object_list.begin(), object_list.end(), list.begin(),
191 [](const auto& t) { return WaitTreeWaitObject::make(*t); }); 193 [](const auto& t) { return WaitTreeSynchronizationObject::make(*t); });
192 return list; 194 return list;
193} 195}
194 196
195WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) : WaitTreeWaitObject(thread) {} 197WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread)
198 : WaitTreeSynchronizationObject(thread) {}
196WaitTreeThread::~WaitTreeThread() = default; 199WaitTreeThread::~WaitTreeThread() = default;
197 200
198QString WaitTreeThread::GetText() const { 201QString WaitTreeThread::GetText() const {
@@ -241,7 +244,8 @@ QString WaitTreeThread::GetText() const {
241 const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") 244 const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
242 .arg(context.pc, 8, 16, QLatin1Char{'0'}) 245 .arg(context.pc, 8, 16, QLatin1Char{'0'})
243 .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); 246 .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'});
244 return QStringLiteral("%1%2 (%3) ").arg(WaitTreeWaitObject::GetText(), pc_info, status); 247 return QStringLiteral("%1%2 (%3) ")
248 .arg(WaitTreeSynchronizationObject::GetText(), pc_info, status);
245} 249}
246 250
247QColor WaitTreeThread::GetColor() const { 251QColor WaitTreeThread::GetColor() const {
@@ -273,7 +277,7 @@ QColor WaitTreeThread::GetColor() const {
273} 277}
274 278
275std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { 279std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
276 std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren()); 280 std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren());
277 281
278 const auto& thread = static_cast<const Kernel::Thread&>(object); 282 const auto& thread = static_cast<const Kernel::Thread&>(object);
279 283
@@ -314,7 +318,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
314 } 318 }
315 319
316 if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { 320 if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
317 list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(), 321 list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(),
318 thread.IsSleepingOnWait())); 322 thread.IsSleepingOnWait()));
319 } 323 }
320 324
@@ -323,7 +327,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
323 return list; 327 return list;
324} 328}
325 329
326WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {} 330WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object)
331 : WaitTreeSynchronizationObject(object) {}
327WaitTreeEvent::~WaitTreeEvent() = default; 332WaitTreeEvent::~WaitTreeEvent() = default;
328 333
329WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list) 334WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list)
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 631274a5f..8e3bc4b24 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -19,7 +19,7 @@ class EmuThread;
19namespace Kernel { 19namespace Kernel {
20class HandleTable; 20class HandleTable;
21class ReadableEvent; 21class ReadableEvent;
22class WaitObject; 22class SynchronizationObject;
23class Thread; 23class Thread;
24} // namespace Kernel 24} // namespace Kernel
25 25
@@ -99,35 +99,37 @@ private:
99 const Kernel::Thread& thread; 99 const Kernel::Thread& thread;
100}; 100};
101 101
102class WaitTreeWaitObject : public WaitTreeExpandableItem { 102class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
103 Q_OBJECT 103 Q_OBJECT
104public: 104public:
105 explicit WaitTreeWaitObject(const Kernel::WaitObject& object); 105 explicit WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& object);
106 ~WaitTreeWaitObject() override; 106 ~WaitTreeSynchronizationObject() override;
107 107
108 static std::unique_ptr<WaitTreeWaitObject> make(const Kernel::WaitObject& object); 108 static std::unique_ptr<WaitTreeSynchronizationObject> make(
109 const Kernel::SynchronizationObject& object);
109 QString GetText() const override; 110 QString GetText() const override;
110 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 111 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
111 112
112protected: 113protected:
113 const Kernel::WaitObject& object; 114 const Kernel::SynchronizationObject& object;
114}; 115};
115 116
116class WaitTreeObjectList : public WaitTreeExpandableItem { 117class WaitTreeObjectList : public WaitTreeExpandableItem {
117 Q_OBJECT 118 Q_OBJECT
118public: 119public:
119 WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::WaitObject>>& list, bool wait_all); 120 WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list,
121 bool wait_all);
120 ~WaitTreeObjectList() override; 122 ~WaitTreeObjectList() override;
121 123
122 QString GetText() const override; 124 QString GetText() const override;
123 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 125 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
124 126
125private: 127private:
126 const std::vector<std::shared_ptr<Kernel::WaitObject>>& object_list; 128 const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& object_list;
127 bool wait_all; 129 bool wait_all;
128}; 130};
129 131
130class WaitTreeThread : public WaitTreeWaitObject { 132class WaitTreeThread : public WaitTreeSynchronizationObject {
131 Q_OBJECT 133 Q_OBJECT
132public: 134public:
133 explicit WaitTreeThread(const Kernel::Thread& thread); 135 explicit WaitTreeThread(const Kernel::Thread& thread);
@@ -138,7 +140,7 @@ public:
138 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 140 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
139}; 141};
140 142
141class WaitTreeEvent : public WaitTreeWaitObject { 143class WaitTreeEvent : public WaitTreeSynchronizationObject {
142 Q_OBJECT 144 Q_OBJECT
143public: 145public:
144 explicit WaitTreeEvent(const Kernel::ReadableEvent& object); 146 explicit WaitTreeEvent(const Kernel::ReadableEvent& object);