summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/arm/skyeye_common/armdefs.h34
-rw-r--r--src/core/arm/skyeye_common/armemu.h18
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp15
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/archive.cpp176
-rw-r--r--src/core/hle/kernel/archive.h23
-rw-r--r--src/core/hle/kernel/event.cpp43
-rw-r--r--src/core/hle/kernel/event.h12
-rw-r--r--src/core/hle/kernel/kernel.h44
-rw-r--r--src/core/hle/kernel/mutex.cpp35
-rw-r--r--src/core/hle/kernel/mutex.h3
-rw-r--r--src/core/hle/kernel/shared_memory.cpp43
-rw-r--r--src/core/hle/kernel/shared_memory.h5
-rw-r--r--src/core/hle/kernel/thread.cpp78
-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.h22
-rw-r--r--src/core/hle/service/srv.cpp6
-rw-r--r--src/core/hle/svc.cpp68
24 files changed, 697 insertions, 428 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 8e71948c6..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*/
802#define EQ 0 802enum ConditionCode {
803#define NE 1 803 EQ = 0,
804#define CS 2 804 NE = 1,
805#define CC 3 805 CS = 2,
806#define MI 4 806 CC = 3,
807#define PL 5 807 MI = 4,
808#define VS 6 808 PL = 5,
809#define VC 7 809 VS = 6,
810#define HI 8 810 VC = 7,
811#define LS 9 811 HI = 8,
812#define GE 10 812 LS = 9,
813#define LT 11 813 GE = 10,
814#define GT 12 814 LT = 11,
815#define LE 13 815 GT = 12,
816#define AL 14 816 LE = 13,
817#define 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/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index c0f0270fe..075fc7e9e 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -25,24 +25,6 @@
25 25
26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__) 26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__)
27 27
28/* Condition code values. */
29#define EQ 0
30#define NE 1
31#define CS 2
32#define CC 3
33#define MI 4
34#define PL 5
35#define VS 6
36#define VC 7
37#define HI 8
38#define LS 9
39#define GE 10
40#define LT 11
41#define GT 12
42#define LE 13
43#define AL 14
44#define NV 15
45
46/* Shift Opcodes. */ 28/* Shift Opcodes. */
47#define LSL 0 29#define LSL 0
48#define LSR 1 30#define LSR 1
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2b21657da..db571b895 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -25,22 +25,17 @@ public:
25 25
26 std::string name; ///< Name of address arbiter object (optional) 26 std::string name; ///< Name of address arbiter object (optional)
27 27
28 /** 28 ResultVal<bool> WaitSynchronization() override {
29 * Wait for kernel object to synchronize
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
32 */
33 Result WaitSynchronization(bool* wait) override {
34 // TODO(bunnei): ImplementMe 29 // TODO(bunnei): ImplementMe
35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 30 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
36 return 0; 31 return UnimplementedFunction(ErrorModule::OS);
37 } 32 }
38}; 33};
39 34
40//////////////////////////////////////////////////////////////////////////////////////////////////// 35////////////////////////////////////////////////////////////////////////////////////////////////////
41 36
42/// Arbitrate an address 37/// Arbitrate an address
43Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { 38ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) {
44 switch (type) { 39 switch (type) {
45 40
46 // Signal thread(s) waiting for arbitrate address... 41 // Signal thread(s) waiting for arbitrate address...
@@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va
65 60
66 default: 61 default:
67 ERROR_LOG(KERNEL, "unknown type=%d", type); 62 ERROR_LOG(KERNEL, "unknown type=%d", type);
68 return -1; 63 return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
69 } 64 }
70 return 0; 65 return RESULT_SUCCESS;
71} 66}
72 67
73/// Create an address arbiter 68/// 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..e273444c9 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
@@ -51,12 +52,7 @@ public:
51 std::string name; ///< Name of archive (optional) 52 std::string name; ///< Name of archive (optional)
52 FileSys::Archive* backend; ///< Archive backend interface 53 FileSys::Archive* backend; ///< Archive backend interface
53 54
54 /** 55 ResultVal<bool> SyncRequest() override {
55 * Synchronize kernel object
56 * @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 */
59 Result SyncRequest(bool* wait) override {
60 u32* cmd_buff = Service::GetCommandBuffer(); 56 u32* cmd_buff = Service::GetCommandBuffer();
61 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 57 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
62 58
@@ -106,22 +102,17 @@ public:
106 default: 102 default:
107 { 103 {
108 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 104 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
109 return -1; 105 return UnimplementedFunction(ErrorModule::FS);
110 } 106 }
111 } 107 }
112 cmd_buff[1] = 0; // No error 108 cmd_buff[1] = 0; // No error
113 return 0; 109 return MakeResult<bool>(false);
114 } 110 }
115 111
116 /** 112 ResultVal<bool> WaitSynchronization() override {
117 * Wait for kernel object to synchronize
118 * @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 */
121 Result WaitSynchronization(bool* wait) override {
122 // TODO(bunnei): ImplementMe 113 // TODO(bunnei): ImplementMe
123 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 114 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
124 return 0; 115 return UnimplementedFunction(ErrorModule::FS);
125 } 116 }
126}; 117};
127 118
@@ -136,12 +127,7 @@ public:
136 FileSys::Path path; ///< Path of the file 127 FileSys::Path path; ///< Path of the file
137 std::unique_ptr<FileSys::File> backend; ///< File backend interface 128 std::unique_ptr<FileSys::File> backend; ///< File backend interface
138 129
139 /** 130 ResultVal<bool> SyncRequest() override {
140 * Synchronize kernel object
141 * @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 */
144 Result SyncRequest(bool* wait) override {
145 u32* cmd_buff = Service::GetCommandBuffer(); 131 u32* cmd_buff = Service::GetCommandBuffer();
146 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 132 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
147 switch (cmd) { 133 switch (cmd) {
@@ -183,7 +169,8 @@ public:
183 case FileCommand::SetSize: 169 case FileCommand::SetSize:
184 { 170 {
185 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); 171 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); 172 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
173 GetTypeName().c_str(), GetName().c_str(), size);
187 backend->SetSize(size); 174 backend->SetSize(size);
188 break; 175 break;
189 } 176 }
@@ -198,22 +185,18 @@ public:
198 // Unknown command... 185 // Unknown command...
199 default: 186 default:
200 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 187 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
201 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 188 ResultCode error = UnimplementedFunction(ErrorModule::FS);
202 return -1; 189 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
190 return error;
203 } 191 }
204 cmd_buff[1] = 0; // No error 192 cmd_buff[1] = 0; // No error
205 return 0; 193 return MakeResult<bool>(false);
206 } 194 }
207 195
208 /** 196 ResultVal<bool> WaitSynchronization() override {
209 * Wait for kernel object to synchronize
210 * @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
212 */
213 Result WaitSynchronization(bool* wait) override {
214 // TODO(bunnei): ImplementMe 197 // TODO(bunnei): ImplementMe
215 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 198 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
216 return 0; 199 return UnimplementedFunction(ErrorModule::FS);
217 } 200 }
218}; 201};
219 202
@@ -228,12 +211,7 @@ public:
228 FileSys::Path path; ///< Path of the directory 211 FileSys::Path path; ///< Path of the directory
229 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface 212 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
230 213
231 /** 214 ResultVal<bool> SyncRequest() override {
232 * Synchronize kernel object
233 * @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
235 */
236 Result SyncRequest(bool* wait) override {
237 u32* cmd_buff = Service::GetCommandBuffer(); 215 u32* cmd_buff = Service::GetCommandBuffer();
238 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 216 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
239 switch (cmd) { 217 switch (cmd) {
@@ -243,8 +221,9 @@ public:
243 { 221 {
244 u32 count = cmd_buff[1]; 222 u32 count = cmd_buff[1];
245 u32 address = cmd_buff[3]; 223 u32 address = cmd_buff[3];
246 FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); 224 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); 225 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
226 GetTypeName().c_str(), GetName().c_str(), count);
248 227
249 // Number of entries actually read 228 // Number of entries actually read
250 cmd_buff[2] = backend->Read(count, entries); 229 cmd_buff[2] = backend->Read(count, entries);
@@ -261,22 +240,18 @@ public:
261 // Unknown command... 240 // Unknown command...
262 default: 241 default:
263 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 242 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
264 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 243 ResultCode error = UnimplementedFunction(ErrorModule::FS);
265 return -1; 244 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
245 return error;
266 } 246 }
267 cmd_buff[1] = 0; // No error 247 cmd_buff[1] = 0; // No error
268 return 0; 248 return MakeResult<bool>(false);
269 } 249 }
270 250
271 /** 251 ResultVal<bool> WaitSynchronization() override {
272 * Wait for kernel object to synchronize
273 * @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
275 */
276 Result WaitSynchronization(bool* wait) override {
277 // TODO(bunnei): ImplementMe 252 // TODO(bunnei): ImplementMe
278 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 253 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
279 return 0; 254 return UnimplementedFunction(ErrorModule::FS);
280 } 255 }
281}; 256};
282 257
@@ -284,89 +259,58 @@ public:
284 259
285std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode 260std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
286 261
287/** 262ResultVal<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); 263 auto itr = g_archive_map.find(id_code);
294 if (itr == g_archive_map.end()) { 264 if (itr == g_archive_map.end()) {
295 return 0; 265 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
266 ErrorSummary::NotFound, ErrorLevel::Permanent);
296 } 267 }
297 return itr->second; 268
269 return MakeResult<Handle>(itr->second);
298} 270}
299 271
300/** 272ResultCode 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); 273 auto itr = g_archive_map.find(id_code);
307 if (itr == g_archive_map.end()) { 274 if (itr == g_archive_map.end()) {
308 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); 275 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
309 return -1; 276 return InvalidHandle(ErrorModule::FS);
310 } 277 }
311 278
312 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); 279 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
313 return 0; 280 return RESULT_SUCCESS;
314} 281}
315 282
316/** 283/**
317 * Mounts an archive 284 * Mounts an archive
318 * @param archive Pointer to the archive to mount 285 * @param archive Pointer to the archive to mount
319 * @return Result of operation, 0 on success, otherwise error code
320 */ 286 */
321Result MountArchive(Archive* archive) { 287ResultCode MountArchive(Archive* archive) {
322 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); 288 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
323 if (0 != OpenArchive(id_code)) { 289 ResultVal<Handle> archive_handle = OpenArchive(id_code);
290 if (archive_handle.Succeeded()) {
324 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); 291 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
325 return -1; 292 return archive_handle.Code();
326 } 293 }
327 g_archive_map[id_code] = archive->GetHandle(); 294 g_archive_map[id_code] = archive->GetHandle();
328 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); 295 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
329 return 0; 296 return RESULT_SUCCESS;
330} 297}
331 298
332/** 299ResultCode 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; 300 Archive* archive = new Archive;
341 handle = Kernel::g_object_pool.Create(archive); 301 Handle handle = Kernel::g_object_pool.Create(archive);
342 archive->name = name; 302 archive->name = name;
343 archive->backend = backend; 303 archive->backend = backend;
344 304
345 MountArchive(archive); 305 ResultCode result = MountArchive(archive);
346 306 if (result.IsError()) {
347 return archive; 307 return result;
348} 308 }
349 309
350/** 310 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} 311}
361 312
362/** 313ResultVal<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 314 // 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. 315 // 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. 316 // Archives file handles are just reused and not actually freed until emulation shut down.
@@ -376,19 +320,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 320 // design. While the functionally of this is OK, our implementation decision to separate
377 // normal files from archive file pointers is very likely wrong. 321 // normal files from archive file pointers is very likely wrong.
378 // See https://github.com/citra-emu/citra/issues/205 322 // See https://github.com/citra-emu/citra/issues/205
379 return archive_handle; 323 return MakeResult<Handle>(archive_handle);
380 324
381 File* file = new File; 325 File* file = new File;
382 Handle handle = Kernel::g_object_pool.Create(file); 326 Handle handle = Kernel::g_object_pool.Create(file);
383 327
384 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 328 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
329 if (archive == nullptr) {
330 return InvalidHandle(ErrorModule::FS);
331 }
385 file->path = path; 332 file->path = path;
386 file->backend = archive->backend->OpenFile(path, mode); 333 file->backend = archive->backend->OpenFile(path, mode);
387 334
388 if (!file->backend) 335 if (!file->backend) {
389 return 0; 336 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
337 ErrorSummary::NotFound, ErrorLevel::Permanent);
338 }
390 339
391 return handle; 340 return MakeResult<Handle>(handle);
392} 341}
393 342
394/** 343/**
@@ -442,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
442 * @param path Path to the Directory inside of the Archive 391 * @param path Path to the Directory inside of the Archive
443 * @return Opened Directory object 392 * @return Opened Directory object
444 */ 393 */
445Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { 394ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
446 Directory* directory = new Directory; 395 Directory* directory = new Directory;
447 Handle handle = Kernel::g_object_pool.Create(directory); 396 Handle handle = Kernel::g_object_pool.Create(directory);
448 397
449 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 398 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
399 if (archive == nullptr) {
400 return InvalidHandle(ErrorModule::FS);
401 }
450 directory->path = path; 402 directory->path = path;
451 directory->backend = archive->backend->OpenDirectory(path); 403 directory->backend = archive->backend->OpenDirectory(path);
452 404
453 return handle; 405 return MakeResult<Handle>(handle);
454} 406}
455 407
456/// Initialize archives 408/// 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..288080209 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -30,13 +30,8 @@ public:
30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event 30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
31 std::string name; ///< Name of event (optional) 31 std::string name; ///< Name of event (optional)
32 32
33 /** 33 ResultVal<bool> WaitSynchronization() override {
34 * Wait for kernel object to synchronize 34 bool wait = locked;
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
37 */
38 Result WaitSynchronization(bool* wait) override {
39 *wait = locked;
40 if (locked) { 35 if (locked) {
41 Handle thread = GetCurrentThreadHandle(); 36 Handle thread = GetCurrentThreadHandle();
42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 37 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
@@ -47,7 +42,7 @@ public:
47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) { 42 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
48 locked = true; 43 locked = true;
49 } 44 }
50 return 0; 45 return MakeResult<bool>(wait);
51 } 46 }
52}; 47};
53 48
@@ -57,12 +52,12 @@ public:
57 * @param permanent_locked Boolean permanent locked value to set event 52 * @param permanent_locked Boolean permanent locked value to set event
58 * @return Result of operation, 0 on success, otherwise error code 53 * @return Result of operation, 0 on success, otherwise error code
59 */ 54 */
60Result SetPermanentLock(Handle handle, const bool permanent_locked) { 55ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
61 Event* evt = g_object_pool.GetFast<Event>(handle); 56 Event* evt = g_object_pool.Get<Event>(handle);
62 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 57 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
63 58
64 evt->permanent_locked = permanent_locked; 59 evt->permanent_locked = permanent_locked;
65 return 0; 60 return RESULT_SUCCESS;
66} 61}
67 62
68/** 63/**
@@ -71,14 +66,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) {
71 * @param locked Boolean locked value to set event 66 * @param locked Boolean locked value to set event
72 * @return Result of operation, 0 on success, otherwise error code 67 * @return Result of operation, 0 on success, otherwise error code
73 */ 68 */
74Result SetEventLocked(const Handle handle, const bool locked) { 69ResultCode SetEventLocked(const Handle handle, const bool locked) {
75 Event* evt = g_object_pool.GetFast<Event>(handle); 70 Event* evt = g_object_pool.Get<Event>(handle);
76 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 71 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
77 72
78 if (!evt->permanent_locked) { 73 if (!evt->permanent_locked) {
79 evt->locked = locked; 74 evt->locked = locked;
80 } 75 }
81 return 0; 76 return RESULT_SUCCESS;
82} 77}
83 78
84/** 79/**
@@ -86,9 +81,9 @@ Result SetEventLocked(const Handle handle, const bool locked) {
86 * @param handle Handle to event to signal 81 * @param handle Handle to event to signal
87 * @return Result of operation, 0 on success, otherwise error code 82 * @return Result of operation, 0 on success, otherwise error code
88 */ 83 */
89Result SignalEvent(const Handle handle) { 84ResultCode SignalEvent(const Handle handle) {
90 Event* evt = g_object_pool.GetFast<Event>(handle); 85 Event* evt = g_object_pool.Get<Event>(handle);
91 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 86 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
92 87
93 // Resume threads waiting for event to signal 88 // Resume threads waiting for event to signal
94 bool event_caught = false; 89 bool event_caught = false;
@@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) {
106 if (!evt->permanent_locked) { 101 if (!evt->permanent_locked) {
107 evt->locked = event_caught; 102 evt->locked = event_caught;
108 } 103 }
109 return 0; 104 return RESULT_SUCCESS;
110} 105}
111 106
112/** 107/**
@@ -114,14 +109,14 @@ Result SignalEvent(const Handle handle) {
114 * @param handle Handle to event to clear 109 * @param handle Handle to event to clear
115 * @return Result of operation, 0 on success, otherwise error code 110 * @return Result of operation, 0 on success, otherwise error code
116 */ 111 */
117Result ClearEvent(Handle handle) { 112ResultCode ClearEvent(Handle handle) {
118 Event* evt = g_object_pool.GetFast<Event>(handle); 113 Event* evt = g_object_pool.Get<Event>(handle);
119 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 114 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
120 115
121 if (!evt->permanent_locked) { 116 if (!evt->permanent_locked) {
122 evt->locked = true; 117 evt->locked = true;
123 } 118 }
124 return 0; 119 return RESULT_SUCCESS;
125} 120}
126 121
127/** 122/**
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 6add72897..73aec4e79 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -15,31 +15,27 @@ namespace Kernel {
15 * Changes whether an event is locked or not 15 * Changes whether an event is locked or not
16 * @param handle Handle to event to change 16 * @param handle Handle to event to change
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
19 */ 18 */
20Result SetEventLocked(const Handle handle, const bool locked); 19ResultCode SetEventLocked(const Handle handle, const bool locked);
21 20
22/** 21/**
23 * Hackish function to set an events permanent lock state, used to pass through synch blocks 22 * Hackish function to set an events permanent lock state, used to pass through synch blocks
24 * @param handle Handle to event to change 23 * @param handle Handle to event to change
25 * @param permanent_locked Boolean permanent locked value to set event 24 * @param permanent_locked Boolean permanent locked value to set event
26 * @return Result of operation, 0 on success, otherwise error code
27 */ 25 */
28Result SetPermanentLock(Handle handle, const bool permanent_locked); 26ResultCode SetPermanentLock(Handle handle, const bool permanent_locked);
29 27
30/** 28/**
31 * Signals an event 29 * Signals an event
32 * @param handle Handle to event to signal 30 * @param handle Handle to event to signal
33 * @return Result of operation, 0 on success, otherwise error code
34 */ 31 */
35Result SignalEvent(const Handle handle); 32ResultCode SignalEvent(const Handle handle);
36 33
37/** 34/**
38 * Clears an event 35 * Clears an event
39 * @param handle Handle to event to clear 36 * @param handle Handle to event to clear
40 * @return Result of operation, 0 on success, otherwise error code
41 */ 37 */
42Result ClearEvent(Handle handle); 38ResultCode ClearEvent(Handle handle);
43 39
44/** 40/**
45 * Creates an event 41 * 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..b303ba128 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -27,31 +27,20 @@ public:
27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex 27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
28 std::string name; ///< Name of mutex (optional) 28 std::string name; ///< Name of mutex (optional)
29 29
30 /** 30 ResultVal<bool> SyncRequest() override {
31 * Synchronize kernel object
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
34 */
35 Result SyncRequest(bool* wait) override {
36 // TODO(bunnei): ImplementMe 31 // TODO(bunnei): ImplementMe
37 locked = true; 32 locked = true;
38 return 0; 33 return MakeResult<bool>(false);
39 } 34 }
40 35
41 /** 36 ResultVal<bool> WaitSynchronization() override {
42 * Wait for kernel object to synchronize
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
45 */
46 Result WaitSynchronization(bool* wait) override {
47 // TODO(bunnei): ImplementMe 37 // TODO(bunnei): ImplementMe
48 *wait = locked; 38 bool wait = locked;
49
50 if (locked) { 39 if (locked) {
51 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); 40 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
52 } 41 }
53 42
54 return 0; 43 return MakeResult<bool>(wait);
55 } 44 }
56}; 45};
57 46
@@ -119,15 +108,17 @@ bool ReleaseMutex(Mutex* mutex) {
119 * Releases a mutex 108 * Releases a mutex
120 * @param handle Handle to mutex to release 109 * @param handle Handle to mutex to release
121 */ 110 */
122Result ReleaseMutex(Handle handle) { 111ResultCode ReleaseMutex(Handle handle) {
123 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); 112 Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle);
124 113 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
125 _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
126 114
127 if (!ReleaseMutex(mutex)) { 115 if (!ReleaseMutex(mutex)) {
128 return -1; 116 // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
117 // what error condition this is supposed to be signaling.
118 return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel,
119 ErrorSummary::NothingHappened, ErrorLevel::Temporary);
129 } 120 }
130 return 0; 121 return RESULT_SUCCESS;
131} 122}
132 123
133/** 124/**
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 313ba6fee..155449f95 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -13,9 +13,8 @@ namespace Kernel {
13/** 13/**
14 * Releases a mutex 14 * Releases a mutex
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
17 */ 16 */
18Result ReleaseMutex(Handle handle); 17ResultCode ReleaseMutex(Handle handle);
19 18
20/** 19/**
21 * Creates a mutex 20 * Creates a mutex
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 7ef3e54cc..cfcc0e0b7 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -16,15 +16,10 @@ public:
16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } 16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } 17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
18 18
19 /** 19 ResultVal<bool> WaitSynchronization() override {
20 * Wait for kernel object to synchronize
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
23 */
24 Result WaitSynchronization(bool* wait) override {
25 // TODO(bunnei): ImplementMe 20 // TODO(bunnei): ImplementMe
26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 21 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
27 return 0; 22 return UnimplementedFunction(ErrorModule::OS);
28 } 23 }
29 24
30 u32 base_address; ///< Address of shared memory block in RAM 25 u32 base_address; ///< Address of shared memory block in RAM
@@ -48,11 +43,6 @@ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) {
48 return shared_memory; 43 return shared_memory;
49} 44}
50 45
51/**
52 * Creates a shared memory object
53 * @param name Optional name of shared memory object
54 * @return Handle of newly created shared memory object
55 */
56Handle CreateSharedMemory(const std::string& name) { 46Handle CreateSharedMemory(const std::string& name) {
57 Handle handle; 47 Handle handle;
58 CreateSharedMemory(handle, name); 48 CreateSharedMemory(handle, name);
@@ -67,39 +57,36 @@ Handle CreateSharedMemory(const std::string& name) {
67 * @param other_permissions Memory block map other permissions (specified by SVC field) 57 * @param other_permissions Memory block map other permissions (specified by SVC field)
68 * @return Result of operation, 0 on success, otherwise error code 58 * @return Result of operation, 0 on success, otherwise error code
69 */ 59 */
70Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 60ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
71 MemoryPermission other_permissions) { 61 MemoryPermission other_permissions) {
72 62
73 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { 63 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!", 64 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
75 handle, address); 65 handle, address);
76 return -1; 66 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
67 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
77 } 68 }
78 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); 69 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
79 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); 70 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
80 71
81 shared_memory->base_address = address; 72 shared_memory->base_address = address;
82 shared_memory->permissions = permissions; 73 shared_memory->permissions = permissions;
83 shared_memory->other_permissions = other_permissions; 74 shared_memory->other_permissions = other_permissions;
84 75
85 return 0; 76 return RESULT_SUCCESS;
86} 77}
87 78
88/** 79ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
89 * Gets a pointer to the shared memory block 80 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
90 * @param handle Shared memory block handle 81 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
91 * @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 */
94u8* GetSharedMemoryPointer(Handle handle, u32 offset) {
95 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle);
96 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle);
97 82
98 if (0 != shared_memory->base_address) 83 if (0 != shared_memory->base_address)
99 return Memory::GetPointer(shared_memory->base_address + offset); 84 return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset));
100 85
101 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); 86 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle);
102 return nullptr; 87 // TODO(yuriks): Verify error code.
88 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
89 ErrorSummary::InvalidState, ErrorLevel::Permanent);
103} 90}
104 91
105} // namespace 92} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 0aec03538..304cf5b67 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -32,9 +32,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown");
32 * @param address Address in system memory to map shared memory block to 32 * @param address Address in system memory to map shared memory block to
33 * @param permissions Memory block map permissions (specified by SVC field) 33 * @param permissions Memory block map permissions (specified by SVC field)
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
36 */ 35 */
37Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 36ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions,
38 MemoryPermission other_permissions); 37 MemoryPermission other_permissions);
39 38
40/** 39/**
@@ -43,6 +42,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
43 * @param offset Offset from the start of the shared memory block to get pointer 42 * @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 43 * @return Pointer to the shared memory block from the specified offset
45 */ 44 */
46u8* GetSharedMemoryPointer(Handle handle, u32 offset); 45ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset);
47 46
48} // namespace 47} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index cc70cbca7..f3f54a4e9 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
@@ -33,21 +34,17 @@ public:
33 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } 34 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
34 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } 35 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
35 36
36 /** 37 ResultVal<bool> WaitSynchronization() override {
37 * Wait for kernel object to synchronize 38 const bool wait = status != THREADSTATUS_DORMANT;
38 * @param wait Boolean wait set if current thread should wait as a result of sync operation 39 if (wait) {
39 * @return Result of operation, 0 on success, otherwise error code
40 */
41 Result WaitSynchronization(bool* wait) override {
42 if (status != THREADSTATUS_DORMANT) {
43 Handle thread = GetCurrentThreadHandle(); 40 Handle thread = GetCurrentThreadHandle();
44 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 41 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
45 waiting_threads.push_back(thread); 42 waiting_threads.push_back(thread);
46 } 43 }
47 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); 44 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
48 *wait = true;
49 } 45 }
50 return 0; 46
47 return MakeResult<bool>(wait);
51 } 48 }
52 49
53 ThreadContext context; 50 ThreadContext context;
@@ -144,27 +141,22 @@ void ChangeReadyState(Thread* t, bool ready) {
144} 141}
145 142
146/// Verify that a thread has not been released from waiting 143/// Verify that a thread has not been released from waiting
147inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { 144inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
148 Thread* thread = g_object_pool.GetFast<Thread>(handle); 145 _dbg_assert_(KERNEL, thread != nullptr);
149 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 146 return type == thread->wait_type && wait_handle == thread->wait_handle;
150
151 if (type != thread->wait_type || wait_handle != thread->wait_handle)
152 return false;
153
154 return true;
155} 147}
156 148
157/// Stops the current thread 149/// Stops the current thread
158void StopThread(Handle handle, const char* reason) { 150ResultCode StopThread(Handle handle, const char* reason) {
159 Thread* thread = g_object_pool.GetFast<Thread>(handle); 151 Thread* thread = g_object_pool.Get<Thread>(handle);
160 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 152 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
161 153
162 ChangeReadyState(thread, false); 154 ChangeReadyState(thread, false);
163 thread->status = THREADSTATUS_DORMANT; 155 thread->status = THREADSTATUS_DORMANT;
164 for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { 156 for (Handle waiting_handle : thread->waiting_threads) {
165 const Handle waiting_thread = thread->waiting_threads[i]; 157 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
166 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { 158 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
167 ResumeThreadFromWait(waiting_thread); 159 ResumeThreadFromWait(waiting_handle);
168 } 160 }
169 } 161 }
170 thread->waiting_threads.clear(); 162 thread->waiting_threads.clear();
@@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) {
172 // Stopped threads are never waiting. 164 // Stopped threads are never waiting.
173 thread->wait_type = WAITTYPE_NONE; 165 thread->wait_type = WAITTYPE_NONE;
174 thread->wait_handle = 0; 166 thread->wait_handle = 0;
167
168 return RESULT_SUCCESS;
175} 169}
176 170
177/// Changes a threads state 171/// Changes a threads state
@@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
195 s32 priority = THREADPRIO_LOWEST; 189 s32 priority = THREADPRIO_LOWEST;
196 190
197 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 191 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
198 for (const auto& handle : thread_queue) { 192 for (Handle handle : thread_queue) {
193 Thread* thread = g_object_pool.Get<Thread>(handle);
199 194
200 // TODO(bunnei): Verify arbiter address... 195 // TODO(bunnei): Verify arbiter address...
201 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) 196 if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
202 continue; 197 continue;
203 198
204 Thread* thread = g_object_pool.GetFast<Thread>(handle); 199 if (thread == nullptr)
200 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
205 if(thread->current_priority <= priority) { 201 if(thread->current_priority <= priority) {
206 highest_priority_thread = handle; 202 highest_priority_thread = handle;
207 priority = thread->current_priority; 203 priority = thread->current_priority;
@@ -218,10 +214,11 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
218void ArbitrateAllThreads(u32 arbiter, u32 address) { 214void ArbitrateAllThreads(u32 arbiter, u32 address) {
219 215
220 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 216 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
221 for (const auto& handle : thread_queue) { 217 for (Handle handle : thread_queue) {
218 Thread* thread = g_object_pool.Get<Thread>(handle);
222 219
223 // TODO(bunnei): Verify arbiter address... 220 // TODO(bunnei): Verify arbiter address...
224 if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) 221 if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
225 ResumeThreadFromWait(handle); 222 ResumeThreadFromWait(handle);
226 } 223 }
227} 224}
@@ -272,7 +269,7 @@ Thread* NextThread() {
272 if (next == 0) { 269 if (next == 0) {
273 return nullptr; 270 return nullptr;
274 } 271 }
275 return Kernel::g_object_pool.GetFast<Thread>(next); 272 return Kernel::g_object_pool.Get<Thread>(next);
276} 273}
277 274
278/** 275/**
@@ -289,8 +286,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
289 286
290/// Resumes a thread from waiting by marking it as "ready" 287/// Resumes a thread from waiting by marking it as "ready"
291void ResumeThreadFromWait(Handle handle) { 288void ResumeThreadFromWait(Handle handle) {
292 u32 error; 289 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
293 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
294 if (thread) { 290 if (thread) {
295 thread->status &= ~THREADSTATUS_WAIT; 291 thread->status &= ~THREADSTATUS_WAIT;
296 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 292 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
@@ -378,19 +374,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
378} 374}
379 375
380/// Get the priority of the thread specified by handle 376/// Get the priority of the thread specified by handle
381u32 GetThreadPriority(const Handle handle) { 377ResultVal<u32> GetThreadPriority(const Handle handle) {
382 Thread* thread = g_object_pool.GetFast<Thread>(handle); 378 Thread* thread = g_object_pool.Get<Thread>(handle);
383 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 379 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
384 return thread->current_priority; 380
381 return MakeResult<u32>(thread->current_priority);
385} 382}
386 383
387/// Set the priority of the thread specified by handle 384/// Set the priority of the thread specified by handle
388Result SetThreadPriority(Handle handle, s32 priority) { 385ResultCode SetThreadPriority(Handle handle, s32 priority) {
389 Thread* thread = nullptr; 386 Thread* thread = nullptr;
390 if (!handle) { 387 if (!handle) {
391 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? 388 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
392 } else { 389 } else {
393 thread = g_object_pool.GetFast<Thread>(handle); 390 thread = g_object_pool.Get<Thread>(handle);
391 if (thread == nullptr) {
392 return InvalidHandle(ErrorModule::Kernel);
393 }
394 } 394 }
395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
396 396
@@ -417,7 +417,7 @@ Result SetThreadPriority(Handle handle, s32 priority) {
417 thread_ready_queue.push_back(thread->current_priority, handle); 417 thread_ready_queue.push_back(thread->current_priority, handle);
418 } 418 }
419 419
420 return 0; 420 return RESULT_SUCCESS;
421} 421}
422 422
423/// Sets up the primary application thread 423/// 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..20e7fb4d3 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -75,12 +75,7 @@ public:
75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); 75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
76 } 76 }
77 77
78 /** 78 ResultVal<bool> SyncRequest() override {
79 * Synchronize kernel object
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
82 */
83 Result SyncRequest(bool* wait) override {
84 u32* cmd_buff = GetCommandBuffer(); 79 u32* cmd_buff = GetCommandBuffer();
85 auto itr = m_functions.find(cmd_buff[0]); 80 auto itr = m_functions.find(cmd_buff[0]);
86 81
@@ -91,7 +86,7 @@ public:
91 // TODO(bunnei): Hack - ignore error 86 // TODO(bunnei): Hack - ignore error
92 u32* cmd_buff = Service::GetCommandBuffer(); 87 u32* cmd_buff = Service::GetCommandBuffer();
93 cmd_buff[1] = 0; 88 cmd_buff[1] = 0;
94 return 0; 89 return MakeResult<bool>(false);
95 } 90 }
96 if (itr->second.func == nullptr) { 91 if (itr->second.func == nullptr) {
97 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", 92 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
@@ -100,23 +95,18 @@ public:
100 // TODO(bunnei): Hack - ignore error 95 // TODO(bunnei): Hack - ignore error
101 u32* cmd_buff = Service::GetCommandBuffer(); 96 u32* cmd_buff = Service::GetCommandBuffer();
102 cmd_buff[1] = 0; 97 cmd_buff[1] = 0;
103 return 0; 98 return MakeResult<bool>(false);
104 } 99 }
105 100
106 itr->second.func(this); 101 itr->second.func(this);
107 102
108 return 0; // TODO: Implement return from actual function 103 return MakeResult<bool>(false); // TODO: Implement return from actual function
109 } 104 }
110 105
111 /** 106 ResultVal<bool> WaitSynchronization() override {
112 * Wait for kernel object to synchronize
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
115 */
116 Result WaitSynchronization(bool* wait) override {
117 // TODO(bunnei): ImplementMe 107 // TODO(bunnei): ImplementMe
118 ERROR_LOG(OSHLE, "unimplemented function"); 108 ERROR_LOG(OSHLE, "unimplemented function");
119 return 0; 109 return UnimplementedFunction(ErrorModule::OS);
120 } 110 }
121 111
122protected: 112protected:
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