summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2014-10-23 01:20:01 -0200
committerGravatar Yuri Kunde Schlesner2014-11-24 17:08:36 -0200
commitc2588403c0b8cf198f13f903f626851c7e94266c (patch)
tree09d26cdae187a47338caf94943291c60b4a40a4c /src
parentChange some SkyEye defines to const ints (diff)
downloadyuzu-c2588403c0b8cf198f13f903f626851c7e94266c.tar.gz
yuzu-c2588403c0b8cf198f13f903f626851c7e94266c.tar.xz
yuzu-c2588403c0b8cf198f13f903f626851c7e94266c.zip
HLE: Revamp error handling throrough the HLE code
All service calls in the CTR OS return result codes indicating the success or failure of the call. Previous to this commit, Citra's HLE emulation of services and the kernel universally either ignored errors or returned dummy -1 error codes. This commit makes an initial effort to provide an infrastructure for error reporting and propagation which can be use going forward to make HLE calls accurately return errors as the original system. A few parts of the code have been updated to use the new system where applicable. One part of this effort is the definition of the `ResultCode` type, which provides facilities for constructing and parsing error codes in the structured format used by the CTR. The `ResultVal` type builds on `ResultCode` by providing a container for values returned by function that can report errors. It enforces that correct error checking will be done on function returns by preventing the use of the return value if the function returned an error code. Currently this change is mostly internal since errors are still suppressed on the ARM<->HLE border, as a temporary compatibility hack. As functionality is implemented and tested this hack can be eventually removed.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/arm/skyeye_common/armdefs.h34
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp10
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/archive.cpp147
-rw-r--r--src/core/hle/kernel/archive.h23
-rw-r--r--src/core/hle/kernel/event.cpp38
-rw-r--r--src/core/hle/kernel/event.h8
-rw-r--r--src/core/hle/kernel/kernel.h44
-rw-r--r--src/core/hle/kernel/mutex.cpp25
-rw-r--r--src/core/hle/kernel/mutex.h2
-rw-r--r--src/core/hle/kernel/shared_memory.cpp27
-rw-r--r--src/core/hle/kernel/shared_memory.h4
-rw-r--r--src/core/hle/kernel/thread.cpp51
-rw-r--r--src/core/hle/kernel/thread.h7
-rw-r--r--src/core/hle/result.h400
-rw-r--r--src/core/hle/service/fs_user.cpp66
-rw-r--r--src/core/hle/service/gsp_gpu.cpp17
-rw-r--r--src/core/hle/service/hid_user.cpp5
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/service.h12
-rw-r--r--src/core/hle/service/srv.cpp6
-rw-r--r--src/core/hle/svc.cpp68
23 files changed, 689 insertions, 310 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index b3bfbca9e..48241c3d4 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -133,6 +133,7 @@ set(HEADERS
133 hle/service/srv.h 133 hle/service/srv.h
134 hle/service/ssl_c.h 134 hle/service/ssl_c.h
135 hle/config_mem.h 135 hle/config_mem.h
136 hle/result.h
136 hle/function_wrappers.h 137 hle/function_wrappers.h
137 hle/hle.h 138 hle/hle.h
138 hle/svc.h 139 hle/svc.h
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 6e8187c8e..8343aaa01 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -799,22 +799,24 @@ pascal void SpinCursor (short increment); /* copied from CursorCtl.h */
799#include "list.h" 799#include "list.h"
800#include "tb.h" 800#include "tb.h"
801*/ 801*/
802const int EQ = 0; 802enum ConditionCode {
803const int NE = 1; 803 EQ = 0,
804const int CS = 2; 804 NE = 1,
805const int CC = 3; 805 CS = 2,
806const int MI = 4; 806 CC = 3,
807const int PL = 5; 807 MI = 4,
808const int VS = 6; 808 PL = 5,
809const int VC = 7; 809 VS = 6,
810const int HI = 8; 810 VC = 7,
811const int LS = 9; 811 HI = 8,
812const int GE = 10; 812 LS = 9,
813const int LT = 11; 813 GE = 10,
814const int GT = 12; 814 LT = 11,
815const int LE = 13; 815 GT = 12,
816const int AL = 14; 816 LE = 13,
817const int NV = 15; 817 AL = 14,
818 NV = 15,
819};
818 820
819#ifndef NFLAG 821#ifndef NFLAG
820#define NFLAG state->NFlag 822#define NFLAG state->NFlag
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2b21657da..1e697fac1 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -30,17 +30,17 @@ public:
30 * @param wait Boolean wait set if current thread should wait as a result of sync operation 30 * @param wait Boolean wait set if current thread should wait as a result of sync operation
31 * @return Result of operation, 0 on success, otherwise error code 31 * @return Result of operation, 0 on success, otherwise error code
32 */ 32 */
33 Result WaitSynchronization(bool* wait) override { 33 ResultVal<bool> WaitSynchronization() override {
34 // TODO(bunnei): ImplementMe 34 // TODO(bunnei): ImplementMe
35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
36 return 0; 36 return UnimplementedFunction(ErrorModule::OS);
37 } 37 }
38}; 38};
39 39
40//////////////////////////////////////////////////////////////////////////////////////////////////// 40////////////////////////////////////////////////////////////////////////////////////////////////////
41 41
42/// Arbitrate an address 42/// Arbitrate an address
43Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { 43ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) {
44 switch (type) { 44 switch (type) {
45 45
46 // Signal thread(s) waiting for arbitrate address... 46 // Signal thread(s) waiting for arbitrate address...
@@ -65,9 +65,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va
65 65
66 default: 66 default:
67 ERROR_LOG(KERNEL, "unknown type=%d", type); 67 ERROR_LOG(KERNEL, "unknown type=%d", type);
68 return -1; 68 return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
69 } 69 }
70 return 0; 70 return RESULT_SUCCESS;
71} 71}
72 72
73/// Create an address arbiter 73/// Create an address arbiter
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 6886e479d..8a5fb10b4 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -28,7 +28,7 @@ enum class ArbitrationType : u32 {
28}; 28};
29 29
30/// Arbitrate an address 30/// Arbitrate an address
31Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); 31ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value);
32 32
33/// Create an address arbiter 33/// Create an address arbiter
34Handle CreateAddressArbiter(const std::string& name = "Unknown"); 34Handle CreateAddressArbiter(const std::string& name = "Unknown");
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 900f484c7..e11dddc84 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -9,8 +9,9 @@
9#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h" 11#include "core/file_sys/directory.h"
12#include "core/hle/service/service.h"
13#include "core/hle/kernel/archive.h" 12#include "core/hle/kernel/archive.h"
13#include "core/hle/result.h"
14#include "core/hle/service/service.h"
14 15
15//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
16// Kernel namespace 17// Kernel namespace
@@ -56,7 +57,7 @@ public:
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation 57 * @param wait Boolean wait set if current thread should wait as a result of sync operation
57 * @return Result of operation, 0 on success, otherwise error code 58 * @return Result of operation, 0 on success, otherwise error code
58 */ 59 */
59 Result SyncRequest(bool* wait) override { 60 ResultVal<bool> SyncRequest() override {
60 u32* cmd_buff = Service::GetCommandBuffer(); 61 u32* cmd_buff = Service::GetCommandBuffer();
61 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 62 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
62 63
@@ -106,11 +107,11 @@ public:
106 default: 107 default:
107 { 108 {
108 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 109 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
109 return -1; 110 return UnimplementedFunction(ErrorModule::FS);
110 } 111 }
111 } 112 }
112 cmd_buff[1] = 0; // No error 113 cmd_buff[1] = 0; // No error
113 return 0; 114 return MakeResult<bool>(false);
114 } 115 }
115 116
116 /** 117 /**
@@ -118,10 +119,10 @@ public:
118 * @param wait Boolean wait set if current thread should wait as a result of sync operation 119 * @param wait Boolean wait set if current thread should wait as a result of sync operation
119 * @return Result of operation, 0 on success, otherwise error code 120 * @return Result of operation, 0 on success, otherwise error code
120 */ 121 */
121 Result WaitSynchronization(bool* wait) override { 122 ResultVal<bool> WaitSynchronization() override {
122 // TODO(bunnei): ImplementMe 123 // TODO(bunnei): ImplementMe
123 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 124 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
124 return 0; 125 return UnimplementedFunction(ErrorModule::FS);
125 } 126 }
126}; 127};
127 128
@@ -141,7 +142,7 @@ public:
141 * @param wait Boolean wait set if current thread should wait as a result of sync operation 142 * @param wait Boolean wait set if current thread should wait as a result of sync operation
142 * @return Result of operation, 0 on success, otherwise error code 143 * @return Result of operation, 0 on success, otherwise error code
143 */ 144 */
144 Result SyncRequest(bool* wait) override { 145 ResultVal<bool> SyncRequest() override {
145 u32* cmd_buff = Service::GetCommandBuffer(); 146 u32* cmd_buff = Service::GetCommandBuffer();
146 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 147 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
147 switch (cmd) { 148 switch (cmd) {
@@ -183,7 +184,8 @@ public:
183 case FileCommand::SetSize: 184 case FileCommand::SetSize:
184 { 185 {
185 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); 186 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
186 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); 187 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
188 GetTypeName().c_str(), GetName().c_str(), size);
187 backend->SetSize(size); 189 backend->SetSize(size);
188 break; 190 break;
189 } 191 }
@@ -198,11 +200,12 @@ public:
198 // Unknown command... 200 // Unknown command...
199 default: 201 default:
200 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 202 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
201 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 203 ResultCode error = UnimplementedFunction(ErrorModule::FS);
202 return -1; 204 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
205 return error;
203 } 206 }
204 cmd_buff[1] = 0; // No error 207 cmd_buff[1] = 0; // No error
205 return 0; 208 return MakeResult<bool>(false);
206 } 209 }
207 210
208 /** 211 /**
@@ -210,10 +213,10 @@ public:
210 * @param wait Boolean wait set if current thread should wait as a result of sync operation 213 * @param wait Boolean wait set if current thread should wait as a result of sync operation
211 * @return Result of operation, 0 on success, otherwise error code 214 * @return Result of operation, 0 on success, otherwise error code
212 */ 215 */
213 Result WaitSynchronization(bool* wait) override { 216 ResultVal<bool> WaitSynchronization() override {
214 // TODO(bunnei): ImplementMe 217 // TODO(bunnei): ImplementMe
215 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 218 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
216 return 0; 219 return UnimplementedFunction(ErrorModule::FS);
217 } 220 }
218}; 221};
219 222
@@ -233,7 +236,7 @@ public:
233 * @param wait Boolean wait set if current thread should wait as a result of sync operation 236 * @param wait Boolean wait set if current thread should wait as a result of sync operation
234 * @return Result of operation, 0 on success, otherwise error code 237 * @return Result of operation, 0 on success, otherwise error code
235 */ 238 */
236 Result SyncRequest(bool* wait) override { 239 ResultVal<bool> SyncRequest() override {
237 u32* cmd_buff = Service::GetCommandBuffer(); 240 u32* cmd_buff = Service::GetCommandBuffer();
238 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 241 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
239 switch (cmd) { 242 switch (cmd) {
@@ -243,8 +246,9 @@ public:
243 { 246 {
244 u32 count = cmd_buff[1]; 247 u32 count = cmd_buff[1];
245 u32 address = cmd_buff[3]; 248 u32 address = cmd_buff[3];
246 FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); 249 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
247 DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); 250 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
251 GetTypeName().c_str(), GetName().c_str(), count);
248 252
249 // Number of entries actually read 253 // Number of entries actually read
250 cmd_buff[2] = backend->Read(count, entries); 254 cmd_buff[2] = backend->Read(count, entries);
@@ -261,11 +265,12 @@ public:
261 // Unknown command... 265 // Unknown command...
262 default: 266 default:
263 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 267 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
264 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 268 ResultCode error = UnimplementedFunction(ErrorModule::FS);
265 return -1; 269 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
270 return error;
266 } 271 }
267 cmd_buff[1] = 0; // No error 272 cmd_buff[1] = 0; // No error
268 return 0; 273 return MakeResult<bool>(false);
269 } 274 }
270 275
271 /** 276 /**
@@ -273,10 +278,10 @@ public:
273 * @param wait Boolean wait set if current thread should wait as a result of sync operation 278 * @param wait Boolean wait set if current thread should wait as a result of sync operation
274 * @return Result of operation, 0 on success, otherwise error code 279 * @return Result of operation, 0 on success, otherwise error code
275 */ 280 */
276 Result WaitSynchronization(bool* wait) override { 281 ResultVal<bool> WaitSynchronization() override {
277 // TODO(bunnei): ImplementMe 282 // TODO(bunnei): ImplementMe
278 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 283 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
279 return 0; 284 return UnimplementedFunction(ErrorModule::FS);
280 } 285 }
281}; 286};
282 287
@@ -284,89 +289,59 @@ public:
284 289
285std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode 290std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
286 291
287/** 292ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
288 * Opens an archive
289 * @param id_code IdCode of the archive to open
290 * @return Handle to archive if it exists, otherwise a null handle (0)
291 */
292Handle OpenArchive(FileSys::Archive::IdCode id_code) {
293 auto itr = g_archive_map.find(id_code); 293 auto itr = g_archive_map.find(id_code);
294 if (itr == g_archive_map.end()) { 294 if (itr == g_archive_map.end()) {
295 return 0; 295 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
296 ErrorSummary::NotFound, ErrorLevel::Permanent);
296 } 297 }
297 return itr->second; 298
299 return MakeResult<Handle>(itr->second);
298} 300}
299 301
300/** 302ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
301 * Closes an archive
302 * @param id_code IdCode of the archive to open
303 * @return Result of operation, 0 on success, otherwise error code
304 */
305Result CloseArchive(FileSys::Archive::IdCode id_code) {
306 auto itr = g_archive_map.find(id_code); 303 auto itr = g_archive_map.find(id_code);
307 if (itr == g_archive_map.end()) { 304 if (itr == g_archive_map.end()) {
308 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); 305 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
309 return -1; 306 return InvalidHandle(ErrorModule::FS);
310 } 307 }
311 308
312 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); 309 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
313 return 0; 310 return RESULT_SUCCESS;
314} 311}
315 312
316/** 313/**
317 * Mounts an archive 314 * Mounts an archive
318 * @param archive Pointer to the archive to mount 315 * @param archive Pointer to the archive to mount
319 * @return Result of operation, 0 on success, otherwise error code 316 * @return Result of operation
320 */ 317 */
321Result MountArchive(Archive* archive) { 318ResultCode MountArchive(Archive* archive) {
322 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); 319 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
323 if (0 != OpenArchive(id_code)) { 320 ResultVal<Handle> archive_handle = OpenArchive(id_code);
321 if (archive_handle.Succeeded()) {
324 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); 322 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
325 return -1; 323 return archive_handle.Code();
326 } 324 }
327 g_archive_map[id_code] = archive->GetHandle(); 325 g_archive_map[id_code] = archive->GetHandle();
328 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); 326 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
329 return 0; 327 return RESULT_SUCCESS;
330} 328}
331 329
332/** 330ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
333 * Creates an Archive
334 * @param handle Handle to newly created archive object
335 * @param backend File system backend interface to the archive
336 * @param name Optional name of Archive
337 * @return Newly created Archive object
338 */
339Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) {
340 Archive* archive = new Archive; 331 Archive* archive = new Archive;
341 handle = Kernel::g_object_pool.Create(archive); 332 Handle handle = Kernel::g_object_pool.Create(archive);
342 archive->name = name; 333 archive->name = name;
343 archive->backend = backend; 334 archive->backend = backend;
344 335
345 MountArchive(archive); 336 ResultCode result = MountArchive(archive);
346 337 if (result.IsError()) {
347 return archive; 338 return result;
348} 339 }
349 340
350/** 341 return RESULT_SUCCESS;
351 * Creates an Archive
352 * @param backend File system backend interface to the archive
353 * @param name Optional name of Archive
354 * @return Handle to newly created Archive object
355 */
356Handle CreateArchive(FileSys::Archive* backend, const std::string& name) {
357 Handle handle;
358 CreateArchive(handle, backend, name);
359 return handle;
360} 342}
361 343
362/** 344ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
363 * Open a File from an Archive
364 * @param archive_handle Handle to an open Archive object
365 * @param path Path to the File inside of the Archive
366 * @param mode Mode under which to open the File
367 * @return Opened File object
368 */
369Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
370 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create 345 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
371 // the archive file handles at app loading, and then keep them persistent throughout execution. 346 // the archive file handles at app loading, and then keep them persistent throughout execution.
372 // Archives file handles are just reused and not actually freed until emulation shut down. 347 // Archives file handles are just reused and not actually freed until emulation shut down.
@@ -376,19 +351,24 @@ Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, con
376 // design. While the functionally of this is OK, our implementation decision to separate 351 // design. While the functionally of this is OK, our implementation decision to separate
377 // normal files from archive file pointers is very likely wrong. 352 // normal files from archive file pointers is very likely wrong.
378 // See https://github.com/citra-emu/citra/issues/205 353 // See https://github.com/citra-emu/citra/issues/205
379 return archive_handle; 354 return MakeResult<Handle>(archive_handle);
380 355
381 File* file = new File; 356 File* file = new File;
382 Handle handle = Kernel::g_object_pool.Create(file); 357 Handle handle = Kernel::g_object_pool.Create(file);
383 358
384 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 359 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
360 if (archive == nullptr) {
361 return InvalidHandle(ErrorModule::FS);
362 }
385 file->path = path; 363 file->path = path;
386 file->backend = archive->backend->OpenFile(path, mode); 364 file->backend = archive->backend->OpenFile(path, mode);
387 365
388 if (!file->backend) 366 if (!file->backend) {
389 return 0; 367 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
368 ErrorSummary::NotFound, ErrorLevel::Permanent);
369 }
390 370
391 return handle; 371 return MakeResult<Handle>(handle);
392} 372}
393 373
394/** 374/**
@@ -442,15 +422,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
442 * @param path Path to the Directory inside of the Archive 422 * @param path Path to the Directory inside of the Archive
443 * @return Opened Directory object 423 * @return Opened Directory object
444 */ 424 */
445Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { 425ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
446 Directory* directory = new Directory; 426 Directory* directory = new Directory;
447 Handle handle = Kernel::g_object_pool.Create(directory); 427 Handle handle = Kernel::g_object_pool.Create(directory);
448 428
449 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 429 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
430 if (archive == nullptr) {
431 return InvalidHandle(ErrorModule::FS);
432 }
450 directory->path = path; 433 directory->path = path;
451 directory->backend = archive->backend->OpenDirectory(path); 434 directory->backend = archive->backend->OpenDirectory(path);
452 435
453 return handle; 436 return MakeResult<Handle>(handle);
454} 437}
455 438
456/// Initialize archives 439/// Initialize archives
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
index 95b3c6656..6fc4f0f25 100644
--- a/src/core/hle/kernel/archive.h
+++ b/src/core/hle/kernel/archive.h
@@ -6,8 +6,9 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/hle/kernel/kernel.h"
10#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// Kernel namespace 14// Kernel namespace
@@ -17,33 +18,31 @@ namespace Kernel {
17/** 18/**
18 * Opens an archive 19 * Opens an archive
19 * @param id_code IdCode of the archive to open 20 * @param id_code IdCode of the archive to open
20 * @return Handle to archive if it exists, otherwise a null handle (0) 21 * @return Handle to the opened archive
21 */ 22 */
22Handle OpenArchive(FileSys::Archive::IdCode id_code); 23ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code);
23 24
24/** 25/**
25 * Closes an archive 26 * Closes an archive
26 * @param id_code IdCode of the archive to open 27 * @param id_code IdCode of the archive to open
27 * @return true if it worked fine
28 */ 28 */
29Result CloseArchive(FileSys::Archive::IdCode id_code); 29ResultCode CloseArchive(FileSys::Archive::IdCode id_code);
30 30
31/** 31/**
32 * Creates an Archive 32 * Creates an Archive
33 * @param backend File system backend interface to the archive 33 * @param backend File system backend interface to the archive
34 * @param name Optional name of Archive 34 * @param name Name of Archive
35 * @return Handle to newly created Archive object
36 */ 35 */
37Handle CreateArchive(FileSys::Archive* backend, const std::string& name); 36ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);
38 37
39/** 38/**
40 * Open a File from an Archive 39 * Open a File from an Archive
41 * @param archive_handle Handle to an open Archive object 40 * @param archive_handle Handle to an open Archive object
42 * @param path Path to the File inside of the Archive 41 * @param path Path to the File inside of the Archive
43 * @param mode Mode under which to open the File 42 * @param mode Mode under which to open the File
44 * @return Opened File object 43 * @return Handle to the opened File object
45 */ 44 */
46Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); 45ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);
47 46
48/** 47/**
49 * Delete a File from an Archive 48 * Delete a File from an Archive
@@ -73,9 +72,9 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
73 * Open a Directory from an Archive 72 * Open a Directory from an Archive
74 * @param archive_handle Handle to an open Archive object 73 * @param archive_handle Handle to an open Archive object
75 * @param path Path to the Directory inside of the Archive 74 * @param path Path to the Directory inside of the Archive
76 * @return Opened Directory object 75 * @return Handle to the opened File object
77 */ 76 */
78Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); 77ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
79 78
80/// Initialize archives 79/// Initialize archives
81void ArchiveInit(); 80void ArchiveInit();
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index e0117c0bc..8a2925a3c 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -35,8 +35,8 @@ public:
35 * @param wait Boolean wait set if current thread should wait as a result of sync operation 35 * @param wait Boolean wait set if current thread should wait as a result of sync operation
36 * @return Result of operation, 0 on success, otherwise error code 36 * @return Result of operation, 0 on success, otherwise error code
37 */ 37 */
38 Result WaitSynchronization(bool* wait) override { 38 ResultVal<bool> WaitSynchronization() override {
39 *wait = locked; 39 bool wait = locked;
40 if (locked) { 40 if (locked) {
41 Handle thread = GetCurrentThreadHandle(); 41 Handle thread = GetCurrentThreadHandle();
42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
@@ -47,7 +47,7 @@ public:
47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) { 47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
48 locked = true; 48 locked = true;
49 } 49 }
50 return 0; 50 return MakeResult<bool>(wait);
51 } 51 }
52}; 52};
53 53
@@ -57,12 +57,12 @@ public:
57 * @param permanent_locked Boolean permanent locked value to set event 57 * @param permanent_locked Boolean permanent locked value to set event
58 * @return Result of operation, 0 on success, otherwise error code 58 * @return Result of operation, 0 on success, otherwise error code
59 */ 59 */
60Result SetPermanentLock(Handle handle, const bool permanent_locked) { 60ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
61 Event* evt = g_object_pool.GetFast<Event>(handle); 61 Event* evt = g_object_pool.Get<Event>(handle);
62 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 62 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
63 63
64 evt->permanent_locked = permanent_locked; 64 evt->permanent_locked = permanent_locked;
65 return 0; 65 return RESULT_SUCCESS;
66} 66}
67 67
68/** 68/**
@@ -71,14 +71,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) {
71 * @param locked Boolean locked value to set event 71 * @param locked Boolean locked value to set event
72 * @return Result of operation, 0 on success, otherwise error code 72 * @return Result of operation, 0 on success, otherwise error code
73 */ 73 */
74Result SetEventLocked(const Handle handle, const bool locked) { 74ResultCode SetEventLocked(const Handle handle, const bool locked) {
75 Event* evt = g_object_pool.GetFast<Event>(handle); 75 Event* evt = g_object_pool.Get<Event>(handle);
76 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 76 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
77 77
78 if (!evt->permanent_locked) { 78 if (!evt->permanent_locked) {
79 evt->locked = locked; 79 evt->locked = locked;
80 } 80 }
81 return 0; 81 return RESULT_SUCCESS;
82} 82}
83 83
84/** 84/**
@@ -86,9 +86,9 @@ Result SetEventLocked(const Handle handle, const bool locked) {
86 * @param handle Handle to event to signal 86 * @param handle Handle to event to signal
87 * @return Result of operation, 0 on success, otherwise error code 87 * @return Result of operation, 0 on success, otherwise error code
88 */ 88 */
89Result SignalEvent(const Handle handle) { 89ResultCode SignalEvent(const Handle handle) {
90 Event* evt = g_object_pool.GetFast<Event>(handle); 90 Event* evt = g_object_pool.Get<Event>(handle);
91 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 91 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
92 92
93 // Resume threads waiting for event to signal 93 // Resume threads waiting for event to signal
94 bool event_caught = false; 94 bool event_caught = false;
@@ -106,7 +106,7 @@ Result SignalEvent(const Handle handle) {
106 if (!evt->permanent_locked) { 106 if (!evt->permanent_locked) {
107 evt->locked = event_caught; 107 evt->locked = event_caught;
108 } 108 }
109 return 0; 109 return RESULT_SUCCESS;
110} 110}
111 111
112/** 112/**
@@ -114,14 +114,14 @@ Result SignalEvent(const Handle handle) {
114 * @param handle Handle to event to clear 114 * @param handle Handle to event to clear
115 * @return Result of operation, 0 on success, otherwise error code 115 * @return Result of operation, 0 on success, otherwise error code
116 */ 116 */
117Result ClearEvent(Handle handle) { 117ResultCode ClearEvent(Handle handle) {
118 Event* evt = g_object_pool.GetFast<Event>(handle); 118 Event* evt = g_object_pool.Get<Event>(handle);
119 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 119 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
120 120
121 if (!evt->permanent_locked) { 121 if (!evt->permanent_locked) {
122 evt->locked = true; 122 evt->locked = true;
123 } 123 }
124 return 0; 124 return RESULT_SUCCESS;
125} 125}
126 126
127/** 127/**
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 6add72897..6c17ed232 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -17,7 +17,7 @@ namespace Kernel {
17 * @param locked Boolean locked value to set event 17 * @param locked Boolean locked value to set event
18 * @return Result of operation, 0 on success, otherwise error code 18 * @return Result of operation, 0 on success, otherwise error code
19 */ 19 */
20Result SetEventLocked(const Handle handle, const bool locked); 20ResultCode SetEventLocked(const Handle handle, const bool locked);
21 21
22/** 22/**
23 * Hackish function to set an events permanent lock state, used to pass through synch blocks 23 * Hackish function to set an events permanent lock state, used to pass through synch blocks
@@ -25,21 +25,21 @@ Result SetEventLocked(const Handle handle, const bool locked);
25 * @param permanent_locked Boolean permanent locked value to set event 25 * @param permanent_locked Boolean permanent locked value to set event
26 * @return Result of operation, 0 on success, otherwise error code 26 * @return Result of operation, 0 on success, otherwise error code
27 */ 27 */
28Result SetPermanentLock(Handle handle, const bool permanent_locked); 28ResultCode SetPermanentLock(Handle handle, const bool permanent_locked);
29 29
30/** 30/**
31 * Signals an event 31 * Signals an event
32 * @param handle Handle to event to signal 32 * @param handle Handle to event to signal
33 * @return Result of operation, 0 on success, otherwise error code 33 * @return Result of operation, 0 on success, otherwise error code
34 */ 34 */
35Result SignalEvent(const Handle handle); 35ResultCode SignalEvent(const Handle handle);
36 36
37/** 37/**
38 * Clears an event 38 * Clears an event
39 * @param handle Handle to event to clear 39 * @param handle Handle to event to clear
40 * @return Result of operation, 0 on success, otherwise error code 40 * @return Result of operation, 0 on success, otherwise error code
41 */ 41 */
42Result ClearEvent(Handle handle); 42ResultCode ClearEvent(Handle handle);
43 43
44/** 44/**
45 * Creates an event 45 * Creates an event
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index e0c94f186..8d3937ce8 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <string> 8#include <string>
9#include "common/common.h" 9#include "common/common.h"
10#include "core/hle/result.h"
10 11
11typedef u32 Handle; 12typedef u32 Handle;
12typedef s32 Result; 13typedef s32 Result;
@@ -52,21 +53,19 @@ public:
52 virtual Kernel::HandleType GetHandleType() const = 0; 53 virtual Kernel::HandleType GetHandleType() const = 0;
53 54
54 /** 55 /**
55 * Synchronize kernel object 56 * Synchronize kernel object.
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation 57 * @return True if the current thread should wait as a result of the sync
57 * @return Result of operation, 0 on success, otherwise error code
58 */ 58 */
59 virtual Result SyncRequest(bool* wait) { 59 virtual ResultVal<bool> SyncRequest() {
60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); 60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
61 return -1; 61 return UnimplementedFunction(ErrorModule::Kernel);
62 } 62 }
63 63
64 /** 64 /**
65 * Wait for kernel object to synchronize 65 * Wait for kernel object to synchronize.
66 * @param wait Boolean wait set if current thread should wait as a result of sync operation 66 * @return True if the current thread should wait as a result of the wait
67 * @return Result of operation, 0 on success, otherwise error code
68 */ 67 */
69 virtual Result WaitSynchronization(bool* wait) = 0; 68 virtual ResultVal<bool> WaitSynchronization() = 0;
70}; 69};
71 70
72class ObjectPool : NonCopyable { 71class ObjectPool : NonCopyable {
@@ -80,38 +79,29 @@ public:
80 static Object* CreateByIDType(int type); 79 static Object* CreateByIDType(int type);
81 80
82 template <class T> 81 template <class T>
83 u32 Destroy(Handle handle) { 82 void Destroy(Handle handle) {
84 u32 error; 83 if (Get<T>(handle)) {
85 if (Get<T>(handle, error)) {
86 occupied[handle - HANDLE_OFFSET] = false; 84 occupied[handle - HANDLE_OFFSET] = false;
87 delete pool[handle - HANDLE_OFFSET]; 85 delete pool[handle - HANDLE_OFFSET];
88 } 86 }
89 return error;
90 } 87 }
91 88
92 bool IsValid(Handle handle); 89 bool IsValid(Handle handle);
93 90
94 template <class T> 91 template <class T>
95 T* Get(Handle handle, u32& outError) { 92 T* Get(Handle handle) {
96 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 93 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
97 // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP 94 if (handle != 0) {
98 if (handle != 0 && (u32)handle != 0x80020001) {
99 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 95 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
100 } 96 }
101 outError = 0;//T::GetMissingErrorCode(); 97 return nullptr;
102 return 0;
103 } else { 98 } else {
104 // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, 99 Object* t = pool[handle - HANDLE_OFFSET];
105 // it just acted as a static case and everything worked. This means that we will never 100 if (t->GetHandleType() != T::GetStaticHandleType()) {
106 // see the Wrong type object error below, but we'll just have to live with that danger.
107 T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]);
108 if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) {
109 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); 101 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
110 outError = 0;//T::GetMissingErrorCode(); 102 return nullptr;
111 return 0;
112 } 103 }
113 outError = 0;//SCE_KERNEL_ERROR_OK; 104 return static_cast<T*>(t);
114 return t;
115 } 105 }
116 } 106 }
117 107
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 31129fd86..e4ff1ef40 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -32,10 +32,10 @@ public:
32 * @param wait Boolean wait set if current thread should wait as a result of sync operation 32 * @param wait Boolean wait set if current thread should wait as a result of sync operation
33 * @return Result of operation, 0 on success, otherwise error code 33 * @return Result of operation, 0 on success, otherwise error code
34 */ 34 */
35 Result SyncRequest(bool* wait) override { 35 ResultVal<bool> SyncRequest() override {
36 // TODO(bunnei): ImplementMe 36 // TODO(bunnei): ImplementMe
37 locked = true; 37 locked = true;
38 return 0; 38 return MakeResult<bool>(false);
39 } 39 }
40 40
41 /** 41 /**
@@ -43,15 +43,14 @@ public:
43 * @param wait Boolean wait set if current thread should wait as a result of sync operation 43 * @param wait Boolean wait set if current thread should wait as a result of sync operation
44 * @return Result of operation, 0 on success, otherwise error code 44 * @return Result of operation, 0 on success, otherwise error code
45 */ 45 */
46 Result WaitSynchronization(bool* wait) override { 46 ResultVal<bool> WaitSynchronization() override {
47 // TODO(bunnei): ImplementMe 47 // TODO(bunnei): ImplementMe
48 *wait = locked; 48 bool wait = locked;
49
50 if (locked) { 49 if (locked) {
51 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); 50 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
52 } 51 }
53 52
54 return 0; 53 return MakeResult<bool>(wait);
55 } 54 }
56}; 55};
57 56
@@ -119,15 +118,17 @@ bool ReleaseMutex(Mutex* mutex) {
119 * Releases a mutex 118 * Releases a mutex
120 * @param handle Handle to mutex to release 119 * @param handle Handle to mutex to release
121 */ 120 */
122Result ReleaseMutex(Handle handle) { 121ResultCode ReleaseMutex(Handle handle) {
123 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); 122 Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle);
124 123 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
125 _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
126 124
127 if (!ReleaseMutex(mutex)) { 125 if (!ReleaseMutex(mutex)) {
128 return -1; 126 // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
127 // what error condition this is supposed to be signaling.
128 return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel,
129 ErrorSummary::NothingHappened, ErrorLevel::Temporary);
129 } 130 }
130 return 0; 131 return RESULT_SUCCESS;
131} 132}
132 133
133/** 134/**
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 313ba6fee..233d8c420 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -15,7 +15,7 @@ namespace Kernel {
15 * @param handle Handle to mutex to release 15 * @param handle Handle to mutex to release
16 * @return Result of operation, 0 on success, otherwise error code 16 * @return Result of operation, 0 on success, otherwise error code
17 */ 17 */
18Result ReleaseMutex(Handle handle); 18ResultCode ReleaseMutex(Handle handle);
19 19
20/** 20/**
21 * Creates a mutex 21 * Creates a mutex
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 7ef3e54cc..b91fc98da 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -21,10 +21,10 @@ public:
21 * @param wait Boolean wait set if current thread should wait as a result of sync operation 21 * @param wait Boolean wait set if current thread should wait as a result of sync operation
22 * @return Result of operation, 0 on success, otherwise error code 22 * @return Result of operation, 0 on success, otherwise error code
23 */ 23 */
24 Result WaitSynchronization(bool* wait) override { 24 ResultVal<bool> WaitSynchronization() override {
25 // TODO(bunnei): ImplementMe 25 // TODO(bunnei): ImplementMe
26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
27 return 0; 27 return UnimplementedFunction(ErrorModule::OS);
28 } 28 }
29 29
30 u32 base_address; ///< Address of shared memory block in RAM 30 u32 base_address; ///< Address of shared memory block in RAM
@@ -67,22 +67,23 @@ Handle CreateSharedMemory(const std::string& name) {
67 * @param other_permissions Memory block map other permissions (specified by SVC field) 67 * @param other_permissions Memory block map other permissions (specified by SVC field)
68 * @return Result of operation, 0 on success, otherwise error code 68 * @return Result of operation, 0 on success, otherwise error code
69 */ 69 */
70Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 70ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
71 MemoryPermission other_permissions) { 71 MemoryPermission other_permissions) {
72 72
73 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { 73 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
74 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", 74 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
75 handle, address); 75 handle, address);
76 return -1; 76 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
77 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
77 } 78 }
78 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); 79 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
79 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); 80 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
80 81
81 shared_memory->base_address = address; 82 shared_memory->base_address = address;
82 shared_memory->permissions = permissions; 83 shared_memory->permissions = permissions;
83 shared_memory->other_permissions = other_permissions; 84 shared_memory->other_permissions = other_permissions;
84 85
85 return 0; 86 return RESULT_SUCCESS;
86} 87}
87 88
88/** 89/**
@@ -91,15 +92,17 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
91 * @param offset Offset from the start of the shared memory block to get pointer 92 * @param offset Offset from the start of the shared memory block to get pointer
92 * @return Pointer to the shared memory block from the specified offset 93 * @return Pointer to the shared memory block from the specified offset
93 */ 94 */
94u8* GetSharedMemoryPointer(Handle handle, u32 offset) { 95ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
95 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); 96 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
96 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); 97 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
97 98
98 if (0 != shared_memory->base_address) 99 if (0 != shared_memory->base_address)
99 return Memory::GetPointer(shared_memory->base_address + offset); 100 return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset));
100 101
101 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); 102 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle);
102 return nullptr; 103 // TODO(yuriks): Verify error code.
104 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
105 ErrorSummary::InvalidState, ErrorLevel::Permanent);
103} 106}
104 107
105} // namespace 108} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 0aec03538..6ed427088 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -34,7 +34,7 @@ Handle CreateSharedMemory(const std::string& name="Unknown");
34 * @param other_permissions Memory block map other permissions (specified by SVC field) 34 * @param other_permissions Memory block map other permissions (specified by SVC field)
35 * @return Result of operation, 0 on success, otherwise error code 35 * @return Result of operation, 0 on success, otherwise error code
36 */ 36 */
37Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 37ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions,
38 MemoryPermission other_permissions); 38 MemoryPermission other_permissions);
39 39
40/** 40/**
@@ -43,6 +43,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
43 * @param offset Offset from the start of the shared memory block to get pointer 43 * @param offset Offset from the start of the shared memory block to get pointer
44 * @return Pointer to the shared memory block from the specified offset 44 * @return Pointer to the shared memory block from the specified offset
45 */ 45 */
46u8* GetSharedMemoryPointer(Handle handle, u32 offset); 46ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset);
47 47
48} // namespace 48} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index cc70cbca7..b01779f2e 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -11,10 +11,11 @@
11#include "common/thread_queue_list.h" 11#include "common/thread_queue_list.h"
12 12
13#include "core/core.h" 13#include "core/core.h"
14#include "core/mem_map.h"
15#include "core/hle/hle.h" 14#include "core/hle/hle.h"
16#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "core/hle/result.h"
18#include "core/mem_map.h"
18 19
19namespace Kernel { 20namespace Kernel {
20 21
@@ -38,16 +39,17 @@ public:
38 * @param wait Boolean wait set if current thread should wait as a result of sync operation 39 * @param wait Boolean wait set if current thread should wait as a result of sync operation
39 * @return Result of operation, 0 on success, otherwise error code 40 * @return Result of operation, 0 on success, otherwise error code
40 */ 41 */
41 Result WaitSynchronization(bool* wait) override { 42 ResultVal<bool> WaitSynchronization() override {
42 if (status != THREADSTATUS_DORMANT) { 43 if (status != THREADSTATUS_DORMANT) {
43 Handle thread = GetCurrentThreadHandle(); 44 Handle thread = GetCurrentThreadHandle();
44 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 45 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
45 waiting_threads.push_back(thread); 46 waiting_threads.push_back(thread);
46 } 47 }
47 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); 48 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
48 *wait = true; 49 return MakeResult<bool>(true);
50 } else {
51 return MakeResult<bool>(false);
49 } 52 }
50 return 0;
51 } 53 }
52 54
53 ThreadContext context; 55 ThreadContext context;
@@ -144,9 +146,9 @@ void ChangeReadyState(Thread* t, bool ready) {
144} 146}
145 147
146/// Verify that a thread has not been released from waiting 148/// Verify that a thread has not been released from waiting
147inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { 149inline bool VerifyWait(Handle handle, WaitType type, Handle wait_handle) {
148 Thread* thread = g_object_pool.GetFast<Thread>(handle); 150 Thread* thread = g_object_pool.Get<Thread>(handle);
149 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 151 _dbg_assert_(KERNEL, thread != nullptr);
150 152
151 if (type != thread->wait_type || wait_handle != thread->wait_handle) 153 if (type != thread->wait_type || wait_handle != thread->wait_handle)
152 return false; 154 return false;
@@ -155,9 +157,9 @@ inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle)
155} 157}
156 158
157/// Stops the current thread 159/// Stops the current thread
158void StopThread(Handle handle, const char* reason) { 160ResultCode StopThread(Handle handle, const char* reason) {
159 Thread* thread = g_object_pool.GetFast<Thread>(handle); 161 Thread* thread = g_object_pool.Get<Thread>(handle);
160 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 162 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
161 163
162 ChangeReadyState(thread, false); 164 ChangeReadyState(thread, false);
163 thread->status = THREADSTATUS_DORMANT; 165 thread->status = THREADSTATUS_DORMANT;
@@ -172,6 +174,8 @@ void StopThread(Handle handle, const char* reason) {
172 // Stopped threads are never waiting. 174 // Stopped threads are never waiting.
173 thread->wait_type = WAITTYPE_NONE; 175 thread->wait_type = WAITTYPE_NONE;
174 thread->wait_handle = 0; 176 thread->wait_handle = 0;
177
178 return RESULT_SUCCESS;
175} 179}
176 180
177/// Changes a threads state 181/// Changes a threads state
@@ -201,7 +205,9 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
201 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) 205 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter))
202 continue; 206 continue;
203 207
204 Thread* thread = g_object_pool.GetFast<Thread>(handle); 208 Thread* thread = g_object_pool.Get<Thread>(handle);
209 if (thread == nullptr)
210 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
205 if(thread->current_priority <= priority) { 211 if(thread->current_priority <= priority) {
206 highest_priority_thread = handle; 212 highest_priority_thread = handle;
207 priority = thread->current_priority; 213 priority = thread->current_priority;
@@ -272,7 +278,7 @@ Thread* NextThread() {
272 if (next == 0) { 278 if (next == 0) {
273 return nullptr; 279 return nullptr;
274 } 280 }
275 return Kernel::g_object_pool.GetFast<Thread>(next); 281 return Kernel::g_object_pool.Get<Thread>(next);
276} 282}
277 283
278/** 284/**
@@ -289,8 +295,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
289 295
290/// Resumes a thread from waiting by marking it as "ready" 296/// Resumes a thread from waiting by marking it as "ready"
291void ResumeThreadFromWait(Handle handle) { 297void ResumeThreadFromWait(Handle handle) {
292 u32 error; 298 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
293 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
294 if (thread) { 299 if (thread) {
295 thread->status &= ~THREADSTATUS_WAIT; 300 thread->status &= ~THREADSTATUS_WAIT;
296 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 301 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
@@ -378,19 +383,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
378} 383}
379 384
380/// Get the priority of the thread specified by handle 385/// Get the priority of the thread specified by handle
381u32 GetThreadPriority(const Handle handle) { 386ResultVal<u32> GetThreadPriority(const Handle handle) {
382 Thread* thread = g_object_pool.GetFast<Thread>(handle); 387 Thread* thread = g_object_pool.Get<Thread>(handle);
383 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 388 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
384 return thread->current_priority; 389
390 return MakeResult<u32>(thread->current_priority);
385} 391}
386 392
387/// Set the priority of the thread specified by handle 393/// Set the priority of the thread specified by handle
388Result SetThreadPriority(Handle handle, s32 priority) { 394ResultCode SetThreadPriority(Handle handle, s32 priority) {
389 Thread* thread = nullptr; 395 Thread* thread = nullptr;
390 if (!handle) { 396 if (!handle) {
391 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? 397 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
392 } else { 398 } else {
393 thread = g_object_pool.GetFast<Thread>(handle); 399 thread = g_object_pool.Get<Thread>(handle);
400 if (thread == nullptr) {
401 return InvalidHandle(ErrorModule::Kernel);
402 }
394 } 403 }
395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 404 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
396 405
@@ -417,7 +426,7 @@ Result SetThreadPriority(Handle handle, s32 priority) {
417 thread_ready_queue.push_back(thread->current_priority, handle); 426 thread_ready_queue.push_back(thread->current_priority, handle);
418 } 427 }
419 428
420 return 0; 429 return RESULT_SUCCESS;
421} 430}
422 431
423/// Sets up the primary application thread 432/// Sets up the primary application thread
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 2a43797ee..ce63a70d3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/result.h"
9 10
10enum ThreadPriority { 11enum ThreadPriority {
11 THREADPRIO_HIGHEST = 0, ///< Highest thread priority 12 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
@@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
55void Reschedule(); 56void Reschedule();
56 57
57/// Stops the current thread 58/// Stops the current thread
58void StopThread(Handle thread, const char* reason); 59ResultCode StopThread(Handle thread, const char* reason);
59 60
60/// Resumes a thread from waiting by marking it as "ready" 61/// Resumes a thread from waiting by marking it as "ready"
61void ResumeThreadFromWait(Handle handle); 62void ResumeThreadFromWait(Handle handle);
@@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa
80void WaitThread_Synchronization(); 81void WaitThread_Synchronization();
81 82
82/// Get the priority of the thread specified by handle 83/// Get the priority of the thread specified by handle
83u32 GetThreadPriority(const Handle handle); 84ResultVal<u32> GetThreadPriority(const Handle handle);
84 85
85/// Set the priority of the thread specified by handle 86/// Set the priority of the thread specified by handle
86Result SetThreadPriority(Handle handle, s32 priority); 87ResultCode SetThreadPriority(Handle handle, s32 priority);
87 88
88/// Initialize threading 89/// Initialize threading
89void ThreadingInit(); 90void ThreadingInit();
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
new file mode 100644
index 000000000..15c4a2677
--- /dev/null
+++ b/src/core/hle/result.h
@@ -0,0 +1,400 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <type_traits>
10#include <utility>
11
12#include "common/common_types.h"
13#include "common/bit_field.h"
14
15// All the constants in this file come from http://3dbrew.org/wiki/Error_codes
16
17/// Detailed description of the error. This listing is likely incomplete.
18enum class ErrorDescription : u32 {
19 Success = 0,
20 InvalidSection = 1000,
21 TooLarge = 1001,
22 NotAuthorized = 1002,
23 AlreadyDone = 1003,
24 InvalidSize = 1004,
25 InvalidEnumValue = 1005,
26 InvalidCombination = 1006,
27 NoData = 1007,
28 Busy = 1008,
29 MisalignedAddress = 1009,
30 MisalignedSize = 1010,
31 OutOfMemory = 1011,
32 NotImplemented = 1012,
33 InvalidAddress = 1013,
34 InvalidPointer = 1014,
35 InvalidHandle = 1015,
36 NotInitialized = 1016,
37 AlreadyInitialized = 1017,
38 NotFound = 1018,
39 CancelRequested = 1019,
40 AlreadyExists = 1020,
41 OutOfRange = 1021,
42 Timeout = 1022,
43 InvalidResultValue = 1023,
44};
45
46/**
47 * Identifies the module which caused the error. Error codes can be propagated through a call
48 * chain, meaning that this doesn't always correspond to the module where the API call made is
49 * contained.
50 */
51enum class ErrorModule : u32 {
52 Common = 0,
53 Kernel = 1,
54 Util = 2,
55 FileServer = 3,
56 LoaderServer = 4,
57 TCB = 5,
58 OS = 6,
59 DBG = 7,
60 DMNT = 8,
61 PDN = 9,
62 GX = 10,
63 I2C = 11,
64 GPIO = 12,
65 DD = 13,
66 CODEC = 14,
67 SPI = 15,
68 PXI = 16,
69 FS = 17,
70 DI = 18,
71 HID = 19,
72 CAM = 20,
73 PI = 21,
74 PM = 22,
75 PM_LOW = 23,
76 FSI = 24,
77 SRV = 25,
78 NDM = 26,
79 NWM = 27,
80 SOC = 28,
81 LDR = 29,
82 ACC = 30,
83 RomFS = 31,
84 AM = 32,
85 HIO = 33,
86 Updater = 34,
87 MIC = 35,
88 FND = 36,
89 MP = 37,
90 MPWL = 38,
91 AC = 39,
92 HTTP = 40,
93 DSP = 41,
94 SND = 42,
95 DLP = 43,
96 HIO_LOW = 44,
97 CSND = 45,
98 SSL = 46,
99 AM_LOW = 47,
100 NEX = 48,
101 Friends = 49,
102 RDT = 50,
103 Applet = 51,
104 NIM = 52,
105 PTM = 53,
106 MIDI = 54,
107 MC = 55,
108 SWC = 56,
109 FatFS = 57,
110 NGC = 58,
111 CARD = 59,
112 CARDNOR = 60,
113 SDMC = 61,
114 BOSS = 62,
115 DBM = 63,
116 Config = 64,
117 PS = 65,
118 CEC = 66,
119 IR = 67,
120 UDS = 68,
121 PL = 69,
122 CUP = 70,
123 Gyroscope = 71,
124 MCU = 72,
125 NS = 73,
126 News = 74,
127 RO_1 = 75,
128 GD = 76,
129 CardSPI = 77,
130 EC = 78,
131 RO_2 = 79,
132 WebBrowser = 80,
133 Test = 81,
134 ENC = 82,
135 PIA = 83,
136
137 Application = 254,
138 InvalidResult = 255
139};
140
141/// A less specific error cause.
142enum class ErrorSummary : u32 {
143 Success = 0,
144 NothingHappened = 1,
145 WouldBlock = 2,
146 OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
147 ///< execute the operation.
148 NotFound = 4, ///< A file or resource was not found.
149 InvalidState = 5,
150 NotSupported = 6, ///< The operation is not supported or not implemented.
151 InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
152 ///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
153 WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
154 ///< with the function. (E.g. Invalid enum value)
155 Canceled = 9,
156 StatusChanged = 10,
157 Internal = 11,
158
159 InvalidResult = 63
160};
161
162/// The severity of the error.
163enum class ErrorLevel : u32 {
164 Success = 0,
165 Info = 1,
166
167 Status = 25,
168 Temporary = 26,
169 Permanent = 27,
170 Usage = 28,
171 Reinitialize = 29,
172 Reset = 30,
173 Fatal = 31
174};
175
176/// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields.
177union ResultCode {
178 u32 raw;
179
180 BitField<0, 10, ErrorDescription> description;
181 BitField<10, 8, ErrorModule> module;
182
183 BitField<21, 6, ErrorSummary> summary;
184 BitField<27, 5, ErrorLevel> level;
185
186 // The last bit of `level` is checked by apps and the kernel to determine if a result code is an error
187 BitField<31, 1, u32> is_error;
188
189 explicit ResultCode(u32 raw) : raw(raw) {}
190 ResultCode(ErrorDescription description_, ErrorModule module_,
191 ErrorSummary summary_, ErrorLevel level_) : raw(0) {
192 description = description_;
193 module = module_;
194 summary = summary_;
195 level = level_;
196 }
197
198 ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; }
199
200 bool IsSuccess() const {
201 return is_error == 0;
202 }
203
204 bool IsError() const {
205 return is_error == 1;
206 }
207};
208
209inline bool operator==(const ResultCode a, const ResultCode b) {
210 return a.raw == b.raw;
211}
212
213inline bool operator!=(const ResultCode a, const ResultCode b) {
214 return a.raw != b.raw;
215}
216
217// Convenience functions for creating some common kinds of errors:
218
219/// The default success `ResultCode`.
220const ResultCode RESULT_SUCCESS(0);
221
222/// Might be returned instead of a dummy success for unimplemented APIs.
223inline ResultCode UnimplementedFunction(ErrorModule module) {
224 return ResultCode(ErrorDescription::NotImplemented, module,
225 ErrorSummary::NotSupported, ErrorLevel::Permanent);
226}
227/// Returned when a function is passed an invalid handle.
228inline ResultCode InvalidHandle(ErrorModule module) {
229 return ResultCode(ErrorDescription::InvalidHandle, module,
230 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
231}
232
233/**
234 * This is an optional value type. It holds a `ResultCode` and, if that code is a success code,
235 * also holds a result of type `T`. If the code is an error code then trying to access the inner
236 * value fails, thus ensuring that the ResultCode of functions is always checked properly before
237 * their return value is used. It is similar in concept to the `std::optional` type
238 * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in
239 * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html).
240 *
241 * An example of how it could be used:
242 * \code
243 * ResultVal<int> Frobnicate(float strength) {
244 * if (strength < 0.f || strength > 1.0f) {
245 * // Can't frobnicate too weakly or too strongly
246 * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common,
247 * ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
248 * } else {
249 * // Frobnicated! Give caller a cookie
250 * return MakeResult<int>(42);
251 * }
252 * }
253 * \endcode
254 *
255 * \code
256 * ResultVal<int> frob_result = Frobnicate(0.75f);
257 * if (frob_result) {
258 * // Frobbed ok
259 * printf("My cookie is %d\n", *frob_result);
260 * } else {
261 * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex);
262 * }
263 * \endcode
264 */
265template <typename T>
266class ResultVal {
267public:
268 /// Constructs an empty `ResultVal` with the given error code. The code must not be a success code.
269 ResultVal(ResultCode error_code = ResultCode(-1))
270 : result_code(error_code)
271 {
272 assert(error_code.IsError());
273 UpdateDebugPtr();
274 }
275
276 /**
277 * Similar to the non-member function `MakeResult`, with the exception that you can manually
278 * specify the success code. `success_code` must not be an error code.
279 */
280 template <typename... Args>
281 static ResultVal WithCode(ResultCode success_code, Args&&... args) {
282 ResultVal<T> result;
283 result.emplace(success_code, std::forward<Args>(args)...);
284 return result;
285 }
286
287 ResultVal(const ResultVal& o)
288 : result_code(o.result_code)
289 {
290 if (!o.empty()) {
291 new (&storage) T(*o.GetPointer());
292 }
293 UpdateDebugPtr();
294 }
295
296 ResultVal(ResultVal&& o)
297 : result_code(o.result_code)
298 {
299 if (!o.empty()) {
300 new (&storage) T(std::move(*o.GetPointer()));
301 }
302 UpdateDebugPtr();
303 }
304
305 ~ResultVal() {
306 if (!empty()) {
307 GetPointer()->~T();
308 }
309 }
310
311 ResultVal& operator=(const ResultVal& o) {
312 if (*this) {
313 if (o) {
314 *GetPointer() = *o.GetPointer();
315 } else {
316 GetPointer()->~T();
317 }
318 } else {
319 if (o) {
320 new (&storage) T(*o.GetPointer());
321 }
322 }
323 result_code = o.result_code;
324 UpdateDebugPtr();
325
326 return *this;
327 }
328
329 /**
330 * Replaces the current result with a new constructed result value in-place. The code must not
331 * be an error code.
332 */
333 template <typename... Args>
334 void emplace(ResultCode success_code, Args&&... args) {
335 assert(success_code.IsSuccess());
336 if (!empty()) {
337 GetPointer()->~T();
338 }
339 new (&storage) T(std::forward<Args>(args)...);
340 result_code = success_code;
341 UpdateDebugPtr();
342 }
343
344 /// Returns true if the `ResultVal` contains an error code and no value.
345 bool empty() const { return result_code.IsError(); }
346
347 /// Returns true if the `ResultVal` contains a return value.
348 bool Succeeded() const { return result_code.IsSuccess(); }
349 /// Returns true if the `ResultVal` contains an error code and no value.
350 bool Failed() const { return empty(); }
351
352 ResultCode Code() const { return result_code; }
353
354 const T& operator* () const { return *GetPointer(); }
355 T& operator* () { return *GetPointer(); }
356 const T* operator->() const { return GetPointer(); }
357 T* operator->() { return GetPointer(); }
358
359 /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
360 template <typename U>
361 T ValueOr(U&& value) const {
362 return !empty() ? *GetPointer() : std::move(value);
363 }
364
365private:
366 typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType;
367
368 StorageType storage;
369 ResultCode result_code;
370#if _DEBUG
371 // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the
372 // need to cast `storage` to a pointer or pay attention to `result_code`.
373 const T* debug_ptr;
374#endif
375
376 void UpdateDebugPtr() {
377#if _DEBUG
378 debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage));
379#endif
380 }
381
382 const T* GetPointer() const {
383 assert(!empty());
384 return static_cast<const T*>(static_cast<const void*>(&storage));
385 }
386
387 T* GetPointer() {
388 assert(!empty());
389 return static_cast<T*>(static_cast<void*>(&storage));
390 }
391};
392
393/**
394 * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct
395 * `T` with and creates a success `ResultVal` contained the constructed value.
396 */
397template <typename T, typename... Args>
398ResultVal<T> MakeResult(Args&&... args) {
399 return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...);
400}
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp
index 2aec1a52a..435be5b5d 100644
--- a/src/core/hle/service/fs_user.cpp
+++ b/src/core/hle/service/fs_user.cpp
@@ -4,26 +4,24 @@
4 4
5#include "common/common.h" 5#include "common/common.h"
6 6
7#include "fs_user.h"
8#include "common/string_util.h" 7#include "common/string_util.h"
9#include "core/settings.h"
10#include "core/hle/kernel/archive.h" 8#include "core/hle/kernel/archive.h"
9#include "core/hle/kernel/archive.h"
10#include "core/hle/result.h"
11#include "core/hle/service/fs_user.h"
12#include "core/settings.h"
11 13
12//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace FS_User 15// Namespace FS_User
14 16
15namespace FS_User { 17namespace FS_User {
16 18
17// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it
18// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
19// sure we don't mislead the application into thinking something worked.
20
21static void Initialize(Service::Interface* self) { 19static void Initialize(Service::Interface* self) {
22 u32* cmd_buff = Service::GetCommandBuffer(); 20 u32* cmd_buff = Service::GetCommandBuffer();
23 21
24 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per 22 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
25 // http://3dbrew.org/wiki/FS:Initialize#Request 23 // http://3dbrew.org/wiki/FS:Initialize#Request
26 cmd_buff[1] = 0; 24 cmd_buff[1] = RESULT_SUCCESS.raw;
27 25
28 DEBUG_LOG(KERNEL, "called"); 26 DEBUG_LOG(KERNEL, "called");
29} 27}
@@ -59,14 +57,12 @@ static void OpenFile(Service::Interface* self) {
59 57
60 DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%d", file_path.DebugStr().c_str(), mode, attributes); 58 DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%d", file_path.DebugStr().c_str(), mode, attributes);
61 59
62 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); 60 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode);
63 if (handle) { 61 cmd_buff[1] = handle.Code().raw;
64 cmd_buff[1] = 0; 62 if (handle.Succeeded()) {
65 cmd_buff[3] = handle; 63 cmd_buff[3] = *handle;
66 } else { 64 } else {
67 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 65 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
68 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
69 cmd_buff[1] = -1;
70 } 66 }
71 67
72 DEBUG_LOG(KERNEL, "called"); 68 DEBUG_LOG(KERNEL, "called");
@@ -111,27 +107,27 @@ static void OpenFileDirectly(Service::Interface* self) {
111 107
112 if (archive_path.GetType() != FileSys::Empty) { 108 if (archive_path.GetType() != FileSys::Empty) {
113 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); 109 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
114 cmd_buff[1] = -1; 110 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
115 return; 111 return;
116 } 112 }
117 113
118 // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it 114 // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it
119 Handle archive_handle = Kernel::OpenArchive(archive_id); 115 // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here?
120 if (!archive_handle) { 116 ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id);
117 cmd_buff[1] = archive_handle.Code().raw;
118 if (archive_handle.Failed()) {
121 ERROR_LOG(KERNEL, "failed to get a handle for archive"); 119 ERROR_LOG(KERNEL, "failed to get a handle for archive");
122 // TODO(Link Mauve): Check for the actual error values, this one was just chosen arbitrarily
123 cmd_buff[1] = -1;
124 return; 120 return;
125 } 121 }
122 // cmd_buff[2] isn't used according to 3dmoo's implementation.
123 cmd_buff[3] = *archive_handle;
126 124
127 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); 125 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode);
128 if (handle) { 126 cmd_buff[1] = handle.Code().raw;
129 cmd_buff[1] = 0; 127 if (handle.Succeeded()) {
130 cmd_buff[3] = handle; 128 cmd_buff[3] = *handle;
131 } else { 129 } else {
132 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 130 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
133 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
134 cmd_buff[1] = -1;
135 } 131 }
136 132
137 DEBUG_LOG(KERNEL, "called"); 133 DEBUG_LOG(KERNEL, "called");
@@ -243,14 +239,12 @@ static void OpenDirectory(Service::Interface* self) {
243 239
244 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); 240 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
245 241
246 Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); 242 ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path);
247 if (handle) { 243 cmd_buff[1] = handle.Code().raw;
248 cmd_buff[1] = 0; 244 if (handle.Succeeded()) {
249 cmd_buff[3] = handle; 245 cmd_buff[3] = *handle;
250 } else { 246 } else {
251 ERROR_LOG(KERNEL, "failed to get a handle for directory"); 247 ERROR_LOG(KERNEL, "failed to get a handle for directory");
252 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
253 cmd_buff[1] = -1;
254 } 248 }
255 249
256 DEBUG_LOG(KERNEL, "called"); 250 DEBUG_LOG(KERNEL, "called");
@@ -282,19 +276,17 @@ static void OpenArchive(Service::Interface* self) {
282 276
283 if (archive_path.GetType() != FileSys::Empty) { 277 if (archive_path.GetType() != FileSys::Empty) {
284 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); 278 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
285 cmd_buff[1] = -1; 279 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
286 return; 280 return;
287 } 281 }
288 282
289 Handle handle = Kernel::OpenArchive(archive_id); 283 ResultVal<Handle> handle = Kernel::OpenArchive(archive_id);
290 if (handle) { 284 cmd_buff[1] = handle.Code().raw;
291 cmd_buff[1] = 0; 285 if (handle.Succeeded()) {
292 // cmd_buff[2] isn't used according to 3dmoo's implementation. 286 // cmd_buff[2] isn't used according to 3dmoo's implementation.
293 cmd_buff[3] = handle; 287 cmd_buff[3] = *handle;
294 } else { 288 } else {
295 ERROR_LOG(KERNEL, "failed to get a handle for archive"); 289 ERROR_LOG(KERNEL, "failed to get a handle for archive");
296 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
297 cmd_buff[1] = -1;
298 } 290 }
299 291
300 DEBUG_LOG(KERNEL, "called"); 292 DEBUG_LOG(KERNEL, "called");
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 66daded94..de1bd3f61 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -28,28 +28,23 @@ u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1
28 28
29/// Gets a pointer to a thread command buffer in GSP shared memory 29/// Gets a pointer to a thread command buffer in GSP shared memory
30static inline u8* GetCommandBuffer(u32 thread_id) { 30static inline u8* GetCommandBuffer(u32 thread_id) {
31 if (0 == g_shared_memory) 31 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer)));
32 return nullptr; 32 return ptr.ValueOr(nullptr);
33
34 return Kernel::GetSharedMemoryPointer(g_shared_memory,
35 0x800 + (thread_id * sizeof(CommandBuffer)));
36} 33}
37 34
38static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 35static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
39 if (0 == g_shared_memory)
40 return nullptr;
41
42 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); 36 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index");
43 37
44 // For each thread there are two FrameBufferUpdate fields 38 // For each thread there are two FrameBufferUpdate fields
45 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); 39 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
46 return (FrameBufferUpdate*)Kernel::GetSharedMemoryPointer(g_shared_memory, offset); 40 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset);
41 return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr));
47} 42}
48 43
49/// Gets a pointer to the interrupt relay queue for a given thread index 44/// Gets a pointer to the interrupt relay queue for a given thread index
50static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { 45static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
51 return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory, 46 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id);
52 sizeof(InterruptRelayQueue) * thread_id); 47 return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
53} 48}
54 49
55static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 50static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp
index 5f6bf1eff..d29de1a52 100644
--- a/src/core/hle/service/hid_user.cpp
+++ b/src/core/hle/service/hid_user.cpp
@@ -34,10 +34,7 @@ static s16 next_circle_y = 0;
34 * Gets a pointer to the PadData structure inside HID shared memory 34 * Gets a pointer to the PadData structure inside HID shared memory
35 */ 35 */
36static inline PadData* GetPadData() { 36static inline PadData* GetPadData() {
37 if (0 == shared_mem) 37 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr));
38 return nullptr;
39
40 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
41} 38}
42 39
43/** 40/**
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index abc8d5edb..fed2268a0 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -62,7 +62,7 @@ void Manager::DeleteService(const std::string& port_name) {
62 62
63/// Get a Service Interface from its Handle 63/// Get a Service Interface from its Handle
64Interface* Manager::FetchFromHandle(Handle handle) { 64Interface* Manager::FetchFromHandle(Handle handle) {
65 return Kernel::g_object_pool.GetFast<Interface>(handle); 65 return Kernel::g_object_pool.Get<Interface>(handle);
66} 66}
67 67
68/// Get a Service Interface from its port 68/// Get a Service Interface from its port
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 55aa84e83..136984b93 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -80,7 +80,7 @@ public:
80 * @param wait Boolean wait set if current thread should wait as a result of sync operation 80 * @param wait Boolean wait set if current thread should wait as a result of sync operation
81 * @return Result of operation, 0 on success, otherwise error code 81 * @return Result of operation, 0 on success, otherwise error code
82 */ 82 */
83 Result SyncRequest(bool* wait) override { 83 ResultVal<bool> SyncRequest() override {
84 u32* cmd_buff = GetCommandBuffer(); 84 u32* cmd_buff = GetCommandBuffer();
85 auto itr = m_functions.find(cmd_buff[0]); 85 auto itr = m_functions.find(cmd_buff[0]);
86 86
@@ -91,7 +91,7 @@ public:
91 // TODO(bunnei): Hack - ignore error 91 // TODO(bunnei): Hack - ignore error
92 u32* cmd_buff = Service::GetCommandBuffer(); 92 u32* cmd_buff = Service::GetCommandBuffer();
93 cmd_buff[1] = 0; 93 cmd_buff[1] = 0;
94 return 0; 94 return MakeResult<bool>(false);
95 } 95 }
96 if (itr->second.func == nullptr) { 96 if (itr->second.func == nullptr) {
97 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", 97 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
@@ -100,12 +100,12 @@ public:
100 // TODO(bunnei): Hack - ignore error 100 // TODO(bunnei): Hack - ignore error
101 u32* cmd_buff = Service::GetCommandBuffer(); 101 u32* cmd_buff = Service::GetCommandBuffer();
102 cmd_buff[1] = 0; 102 cmd_buff[1] = 0;
103 return 0; 103 return MakeResult<bool>(false);
104 } 104 }
105 105
106 itr->second.func(this); 106 itr->second.func(this);
107 107
108 return 0; // TODO: Implement return from actual function 108 return MakeResult<bool>(false); // TODO: Implement return from actual function
109 } 109 }
110 110
111 /** 111 /**
@@ -113,10 +113,10 @@ public:
113 * @param wait Boolean wait set if current thread should wait as a result of sync operation 113 * @param wait Boolean wait set if current thread should wait as a result of sync operation
114 * @return Result of operation, 0 on success, otherwise error code 114 * @return Result of operation, 0 on success, otherwise error code
115 */ 115 */
116 Result WaitSynchronization(bool* wait) override { 116 ResultVal<bool> WaitSynchronization() override {
117 // TODO(bunnei): ImplementMe 117 // TODO(bunnei): ImplementMe
118 ERROR_LOG(OSHLE, "unimplemented function"); 118 ERROR_LOG(OSHLE, "unimplemented function");
119 return 0; 119 return UnimplementedFunction(ErrorModule::OS);
120 } 120 }
121 121
122protected: 122protected:
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index df38bd93c..0e7fa9e3b 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -35,7 +35,7 @@ static void GetProcSemaphore(Service::Interface* self) {
35} 35}
36 36
37static void GetServiceHandle(Service::Interface* self) { 37static void GetServiceHandle(Service::Interface* self) {
38 Result res = 0; 38 ResultCode res = RESULT_SUCCESS;
39 u32* cmd_buff = Service::GetCommandBuffer(); 39 u32* cmd_buff = Service::GetCommandBuffer();
40 40
41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
@@ -46,9 +46,9 @@ static void GetServiceHandle(Service::Interface* self) {
46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); 46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
47 } else { 47 } else {
48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); 48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
49 res = -1; 49 res = UnimplementedFunction(ErrorModule::SRV);
50 } 50 }
51 cmd_buff[1] = res; 51 cmd_buff[1] = res.raw;
52} 52}
53 53
54const Interface::FunctionInfo FunctionTable[] = { 54const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 3a06d6765..87d768856 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17 17
18#include "core/hle/function_wrappers.h" 18#include "core/hle/function_wrappers.h"
19#include "core/hle/result.h"
19#include "core/hle/service/service.h" 20#include "core/hle/service/service.h"
20 21
21//////////////////////////////////////////////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -86,18 +87,22 @@ static Result ConnectToPort(Handle* out, const char* port_name) {
86 87
87/// Synchronize to an OS service 88/// Synchronize to an OS service
88static Result SendSyncRequest(Handle handle) { 89static Result SendSyncRequest(Handle handle) {
90 // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object,
91 // so we are forced to use GetFast and manually verify the handle.
92 if (!Kernel::g_object_pool.IsValid(handle)) {
93 return InvalidHandle(ErrorModule::Kernel).raw;
94 }
89 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 95 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
90 96
91 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 97 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
92 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); 98 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str());
93 99
94 bool wait = false; 100 ResultVal<bool> wait = object->SyncRequest();
95 Result res = object->SyncRequest(&wait); 101 if (wait.Succeeded() && *wait) {
96 if (wait) {
97 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? 102 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
98 } 103 }
99 104
100 return res; 105 return wait.Code().raw;
101} 106}
102 107
103/// Close a handle 108/// Close a handle
@@ -110,25 +115,25 @@ static Result CloseHandle(Handle handle) {
110/// Wait for a handle to synchronize, timeout after the specified nanoseconds 115/// Wait for a handle to synchronize, timeout after the specified nanoseconds
111static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { 116static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
112 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 117 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
113 bool wait = false;
114 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 118 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
115 119
120 if (!Kernel::g_object_pool.IsValid(handle)) {
121 return InvalidHandle(ErrorModule::Kernel).raw;
122 }
116 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 123 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
124 _dbg_assert_(KERNEL, object != nullptr);
117 125
118 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), 126 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
119 object->GetName().c_str(), nano_seconds); 127 object->GetName().c_str(), nano_seconds);
120 128
121 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 129 ResultVal<bool> wait = object->WaitSynchronization();
122
123 Result res = object->WaitSynchronization(&wait);
124 130
125 // Check for next thread to schedule 131 // Check for next thread to schedule
126 if (wait) { 132 if (wait.Succeeded() && *wait) {
127 HLE::Reschedule(__func__); 133 HLE::Reschedule(__func__);
128 return 0;
129 } 134 }
130 135
131 return res; 136 return wait.Code().raw;
132} 137}
133 138
134/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 139/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
@@ -143,20 +148,21 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
143 148
144 // Iterate through each handle, synchronize kernel object 149 // Iterate through each handle, synchronize kernel object
145 for (s32 i = 0; i < handle_count; i++) { 150 for (s32 i = 0; i < handle_count; i++) {
146 bool wait = false; 151 if (!Kernel::g_object_pool.IsValid(handles[i])) {
152 return InvalidHandle(ErrorModule::Kernel).raw;
153 }
147 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); 154 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
148 155
149 _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object "
150 "is nullptr!", handles[i]);
151
152 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), 156 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(),
153 object->GetName().c_str()); 157 object->GetName().c_str());
154 158
155 Result res = object->WaitSynchronization(&wait); 159 // TODO(yuriks): Verify how the real function behaves when an error happens here
160 ResultVal<bool> wait_result = object->WaitSynchronization();
161 bool wait = wait_result.Succeeded() && *wait_result;
156 162
157 if (!wait && !wait_all) { 163 if (!wait && !wait_all) {
158 *out = i; 164 *out = i;
159 return 0; 165 return RESULT_SUCCESS.raw;
160 } else { 166 } else {
161 unlock_all = false; 167 unlock_all = false;
162 } 168 }
@@ -164,13 +170,13 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
164 170
165 if (wait_all && unlock_all) { 171 if (wait_all && unlock_all) {
166 *out = handle_count; 172 *out = handle_count;
167 return 0; 173 return RESULT_SUCCESS.raw;
168 } 174 }
169 175
170 // Check for next thread to schedule 176 // Check for next thread to schedule
171 HLE::Reschedule(__func__); 177 HLE::Reschedule(__func__);
172 178
173 return 0; 179 return RESULT_SUCCESS.raw;
174} 180}
175 181
176/// Create an address arbiter (to allocate access to shared resources) 182/// Create an address arbiter (to allocate access to shared resources)
@@ -183,8 +189,8 @@ static Result CreateAddressArbiter(u32* arbiter) {
183 189
184/// Arbitrate address 190/// Arbitrate address
185static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { 191static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) {
186 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address, 192 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type),
187 value); 193 address, value).raw;
188} 194}
189 195
190/// Used to output a message on a debug hardware unit - does nothing on a retail unit 196/// Used to output a message on a debug hardware unit - does nothing on a retail unit
@@ -246,13 +252,16 @@ static u32 ExitThread() {
246 252
247/// Gets the priority for the specified thread 253/// Gets the priority for the specified thread
248static Result GetThreadPriority(s32* priority, Handle handle) { 254static Result GetThreadPriority(s32* priority, Handle handle) {
249 *priority = Kernel::GetThreadPriority(handle); 255 ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle);
250 return 0; 256 if (priority_result.Succeeded()) {
257 *priority = *priority_result;
258 }
259 return priority_result.Code().raw;
251} 260}
252 261
253/// Sets the priority for the specified thread 262/// Sets the priority for the specified thread
254static Result SetThreadPriority(Handle handle, s32 priority) { 263static Result SetThreadPriority(Handle handle, s32 priority) {
255 return Kernel::SetThreadPriority(handle, priority); 264 return Kernel::SetThreadPriority(handle, priority).raw;
256} 265}
257 266
258/// Create a mutex 267/// Create a mutex
@@ -266,9 +275,8 @@ static Result CreateMutex(Handle* mutex, u32 initial_locked) {
266/// Release a mutex 275/// Release a mutex
267static Result ReleaseMutex(Handle handle) { 276static Result ReleaseMutex(Handle handle) {
268 DEBUG_LOG(SVC, "called handle=0x%08X", handle); 277 DEBUG_LOG(SVC, "called handle=0x%08X", handle);
269 _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); 278 ResultCode res = Kernel::ReleaseMutex(handle);
270 Kernel::ReleaseMutex(handle); 279 return res.raw;
271 return 0;
272} 280}
273 281
274/// Get current thread ID 282/// Get current thread ID
@@ -310,16 +318,14 @@ static Result DuplicateHandle(Handle* out, Handle handle) {
310 318
311/// Signals an event 319/// Signals an event
312static Result SignalEvent(Handle evt) { 320static Result SignalEvent(Handle evt) {
313 Result res = Kernel::SignalEvent(evt);
314 DEBUG_LOG(SVC, "called event=0x%08X", evt); 321 DEBUG_LOG(SVC, "called event=0x%08X", evt);
315 return res; 322 return Kernel::SignalEvent(evt).raw;
316} 323}
317 324
318/// Clears an event 325/// Clears an event
319static Result ClearEvent(Handle evt) { 326static Result ClearEvent(Handle evt) {
320 Result res = Kernel::ClearEvent(evt);
321 DEBUG_LOG(SVC, "called event=0x%08X", evt); 327 DEBUG_LOG(SVC, "called event=0x%08X", evt);
322 return res; 328 return Kernel::ClearEvent(evt).raw;
323} 329}
324 330
325/// Sleep the current thread 331/// Sleep the current thread