{"action":"created","comment":{"url":"https://api.github.com/repos/citra-emu/hwtests/pulls/comments/24637333","id":24637333,"diff_hunk":"@@ -0,0 +1,1133 @@\n+// Copyright 2015 Citra Emulator Project\n+// Licensed under GPLv2 or any later version\n+// Refer to the license.txt file included.\n+\n+#include <memory>\n+#include <limits>\n+#include <string>\n+#include <cstring>\n+#include <stdio.h>\n+#include <3ds.h>\n+\n+#include \"output.h\"\n+#include \"common/string_funcs.h\"\n+#include \"common/scope_exit.h\"\n+#include \"tests/test.h\"\n+#include \"tests/waitsynch/waitsynch.h\"\n+\n+namespace WaitSynch {\n+\n+static Handle events[4];\n+static Handle threads[13];\n+static Handle mutexes[4];\n+static Handle semaphore;\n+\n+static u32 thread0_stack[0x400];\n+static u32 thread1_stack[0x400];\n+static u32 thread2_stack[0x400];\n+static u32 thread3_stack[0x400];\n+static u32 thread4_stack[0x400];\n+static u32 thread5_stack[0x400];\n+static u32 thread6_stack[0x400];\n+static u32 thread7_stack[0x400];\n+static u32 thread8_stack[0x400];\n+static u32 thread9_stack[0x400];\n+static u32 thread10_stack[0x400];\n+static u32 thread11_stack[0x400];\n+static u32 thread12_stack[0x400];\n+\n+void thread0_handler(void*) {\n+    svcSignalEvent(events[0]);\n+    svcExitThread();\n+}\n+\n+void thread1_handler(void*) {\n+    svcSignalEvent(events[1]);\n+    svcExitThread();\n+}\n+\n+void thread2_handler(void*) {\n+    svcSignalEvent(events[2]);\n+    svcExitThread();\n+}\n+\n+void thread3_handler(void*) {\n+    svcSignalEvent(events[3]);\n+    svcExitThread();\n+}\n+\n+////////////////////////////////////////////////////////////////////////////////////////////////////\n+\n+#define ONE_SECOND (1000 * 1000 * 1000)\n+\n+// Test WaitSynchN with wait_all=0, wait=0\n+\n+bool Test_WaitSynchN_00() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    svcSignalEvent(events[2]);\n+    res = svcWaitSynchronizationN(&output, events, 4, 0, U64_MAX);\n+    SoftAssert(output == 2);\n+    SoftAssert(res == 0);\n+\n+    svcSignalEvent(events[0]);\n+    res = svcWaitSynchronizationN(&output, events, 4, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with wait_all=0, wait=1\n+\n+bool Test_WaitSynchN_01() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    svcCreateThread(&threads[3], thread3_handler, 0x0, (u32*)(&thread3_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[3]); });\n+\n+    res = svcWaitSynchronizationN(&output, events, 4, 0, U64_MAX);\n+    SoftAssert(output == 3);\n+    SoftAssert(res == 0);\n+\n+    svcClearEvent(events[3]);\n+\n+    svcCreateThread(&threads[0], thread0_handler, 0x0, (u32*)(&thread0_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[0]); });\n+\n+    res = svcWaitSynchronizationN(&output, events, 4, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[3], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[0], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with wait_all=1, wait=0\n+\n+bool Test_WaitSynchN_02() {\n+    s32 output = -1;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    svcSignalEvent(events[0]);\n+    svcSignalEvent(events[1]);\n+    svcSignalEvent(events[2]);\n+    svcSignalEvent(events[3]);\n+\n+    // TODO: Figure out how output is set\n+    res = svcWaitSynchronizationN(&output, events, 4, 1, U64_MAX);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with wait_all=1, wait=1\n+\n+bool Test_WaitSynchN_03() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    svcCreateThread(&threads[0], thread0_handler, 0x0, (u32*)(&thread0_stack[0x400]), 0x2F, 0xfffffffe);\n+    svcCreateThread(&threads[1], thread1_handler, 0x0, (u32*)(&thread1_stack[0x400]), 0x30, 0xfffffffe);\n+    svcCreateThread(&threads[2], thread2_handler, 0x0, (u32*)(&thread2_stack[0x400]), 0x31, 0xfffffffe);\n+    svcCreateThread(&threads[3], thread3_handler, 0x0, (u32*)(&thread3_stack[0x400]), 0x32, 0xfffffffe);\n+\n+    SCOPE_EXIT({ svcCloseHandle(threads[0]); });\n+    SCOPE_EXIT({ svcCloseHandle(threads[1]); });\n+    SCOPE_EXIT({ svcCloseHandle(threads[2]); });\n+    SCOPE_EXIT({ svcCloseHandle(threads[3]); });\n+\n+    res = svcWaitSynchronizationN(&output, threads, 4, 1, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with wait_all=0, wait=1, timeout=1/2 sec\n+\n+bool Test_WaitSynchN_04() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    res = svcWaitSynchronizationN(&output, events, 4, 0, ONE_SECOND / 2); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with wait_all=1, wait=1, timeout=1/2 sec\n+\n+bool Test_WaitSynchN_05() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    res = svcWaitSynchronizationN(&output, events, 4, 1, ONE_SECOND / 2); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with invalid handle\n+\n+bool Test_WaitSynchN_06() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    res = svcWaitSynchronizationN(&output, &threads[4], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0xD8E007F7);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with duplicate handles (two events signaled, no wait)\n+\n+bool Test_WaitSynchN_07() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    Handle handles[] = {events[0], events[1], events[1], events[0], events[1], events[2]};\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcClearEvent(events[2]);\n+    svcClearEvent(events[3]);\n+\n+    svcSignalEvent(events[1]);\n+    svcSignalEvent(events[2]);\n+\n+    res = svcWaitSynchronizationN(&output, handles, 6, 0, U64_MAX);\n+    SoftAssert(output == 1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with duplicate handles (one event signaled, no wait)\n+\n+bool Test_WaitSynchN_08() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle handles[] = {events[0], events[1], events[1], events[0], events[1]};\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, handles, 5, 0, U64_MAX);\n+    SoftAssert(output == 1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with duplicate handles (one event signaled, with a wait)\n+\n+bool Test_WaitSynchN_09() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle handles[] = {events[0], events[1], events[1], events[0], events[1]};\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcCreateThread(&threads[1], thread1_handler, 0x0, (u32*)(&thread1_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[1]); });\n+\n+    res = svcWaitSynchronizationN(&output, handles, 5, 0, U64_MAX);\n+    SoftAssert(output == 4);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[1], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with svcDuplicateHandle (one event signaled, with wait)\n+\n+bool Test_WaitSynchN_10() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle duplicate0, duplicate1;\n+\n+    svcDuplicateHandle(&duplicate0, events[1]);\n+    svcDuplicateHandle(&duplicate1, events[1]);\n+\n+    SCOPE_EXIT({ svcCloseHandle(duplicate0); });\n+    SCOPE_EXIT({ svcCloseHandle(duplicate1); });\n+\n+    Handle handles[] = {events[0], duplicate0, events[1], events[0], duplicate1};\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcCreateThread(&threads[1], thread1_handler, 0x0, (u32*)(&thread1_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[1]); });\n+\n+    res = svcWaitSynchronizationN(&output, handles, 5, 0, U64_MAX);\n+    SoftAssert(output == 4);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[1], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with svcDuplicateHandle (one event signaled, with wait)\n+\n+bool Test_WaitSynchN_11() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle duplicate0, duplicate1;\n+\n+    svcDuplicateHandle(&duplicate0, events[1]);\n+    svcDuplicateHandle(&duplicate1, events[1]);\n+\n+    SCOPE_EXIT({ svcCloseHandle(duplicate0); });\n+    SCOPE_EXIT({ svcCloseHandle(duplicate1); });\n+\n+    Handle handles[] = {events[0], duplicate0, events[1], events[0], duplicate1};\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, handles, 5, 0, U64_MAX);\n+    SoftAssert(output == 1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with zero handles, wait_all=false\n+\n+bool Test_WaitSynchN_12() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    // Should hang, hence the timeout\n+    res = svcWaitSynchronizationN(&output, events, 0, 0, ONE_SECOND / 2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with zero handles, wait_all=true\n+\n+bool Test_WaitSynchN_13() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    // Should pass right through\n+    res = svcWaitSynchronizationN(&output, events, 0, 1, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with invalid handle count\n+\n+bool Test_WaitSynchN_14() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    res = svcWaitSynchronizationN(&output, events, -1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0xE0E01BFD);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with wait_all=true; 2 events; signal one of them in another thread, clear that\n+// same event in that same thread, then signal the other one\n+\n+void thread4_handler(void*)\n+{\n+    svcSignalEvent(events[0]);\n+    svcClearEvent(events[0]);\n+    svcSignalEvent(events[1]);\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_15() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcCreateThread(&threads[4], thread4_handler, 0x0, (u32*)(&thread4_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[4]); });\n+\n+    // Should timeout\n+    res = svcWaitSynchronizationN(&output, events, 2, 1, ONE_SECOND / 2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[4], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynchN with invalid handles pointer\n+\n+bool Test_WaitSynchN_16() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    res = svcWaitSynchronizationN(&output, nullptr, 0, 0, ONE_SECOND / 2);\n+    //SoftAssert(output == 0); // TODO: Figure out how output is set, same as Test_WaitSynchN_02\n+    SoftAssert(res == 0xD8E007F6);\n+\n+    res = svcWaitSynchronizationN(&output, nullptr, 0, 1, ONE_SECOND / 2);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0xD8E007F6);\n+\n+    res = svcWaitSynchronizationN(&output, nullptr, 1, 0, ONE_SECOND / 2);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0xD8E007F6);\n+\n+    res = svcWaitSynchronizationN(&output, nullptr, 1, 1, ONE_SECOND / 2);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0xD8E007F6);\n+\n+    return true;\n+}\n+\n+// WaitSynchN wait_all=false; unlocked mutex0, unlocked mutex1; Make sure only mutex0 is locked and\n+// it does not wait\n+\n+void thread5_handler(void*) {\n+    s32 output = 0;\n+    svcWaitSynchronizationN(&output, mutexes, 2, 0, U64_MAX);\n+    svcSignalEvent(events[0]);\n+    svcWaitSynchronization(events[1], U64_MAX);\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_17() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcReleaseMutex(mutexes[0]);\n+    svcReleaseMutex(mutexes[1]);\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcCreateThread(&threads[5], thread5_handler, 0x0, (u32*)(&thread5_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[5]); });\n+\n+    svcWaitSynchronization(events[0], U64_MAX);\n+\n+    // Make sure we cant get mutex 0\n+    res = svcWaitSynchronizationN(&output, mutexes, 1, 0, ONE_SECOND / 2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+    \n+    // Make sure we do get mutex 1\n+    res = svcWaitSynchronizationN(&output, mutexes, 2, 0, U64_MAX);\n+    SoftAssert(output == 1);\n+    SoftAssert(res == 0);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[5], 1, 1, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// WaitSynchN tests that the thread does not wait on a mutex if it already acquired it as well as\n+// the recursive nature of acquiring a mutex\n+\n+void thread5b_handler(void*) {\n+    svcWaitSynchronization(mutexes[0], U64_MAX);\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_18() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcReleaseMutex(mutexes[0]);\n+    svcReleaseMutex(mutexes[1]);\n+\n+    res = svcWaitSynchronizationN(&output, mutexes, 2, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, mutexes, 2, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, mutexes, 2, 1, U64_MAX);\n+    // TODO: Figure out how output is set\n+    SoftAssert(res == 0);\n+\n+    svcReleaseMutex(mutexes[0]);\n+    svcReleaseMutex(mutexes[0]);\n+\n+    svcReleaseMutex(mutexes[1]);\n+    svcReleaseMutex(mutexes[1]);\n+\n+    res = svcReleaseMutex(mutexes[0]);\n+    SoftAssert(res == 0);\n+\n+    svcCreateThread(&threads[5], thread5b_handler, 0x0, (u32*)(&thread5_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[5]); });\n+\n+    res = svcWaitSynchronization(mutexes[0], U64_MAX);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronization(mutexes[0], U64_MAX);\n+    SoftAssert(res == 0);\n+\n+    res = svcReleaseMutex(mutexes[0]);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[5], 1, 0, ONE_SECOND/2); // Wait for all threads to complete\n+    SoftAssert(res == 0x09401BFE);\n+\n+    res = svcReleaseMutex(mutexes[0]);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[5], 1, 0, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// WaitSynchN wait_all=true; unlocked mutex0, unlocked mutex1; Make sure both mutexes are locked and\n+// it does not wait \n+\n+void thread6_handler(void*) {\n+    s32 output = 0;\n+\n+    svcWaitSynchronizationN(&output, mutexes, 2, 1, U64_MAX);\n+\n+    svcSignalEvent(events[0]);\n+\n+    svcWaitSynchronization(events[1], U64_MAX);\n+\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_19() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcReleaseMutex(mutexes[0]);\n+    svcReleaseMutex(mutexes[1]);\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcCreateThread(&threads[6], thread6_handler, 0x0, (u32*)(&thread6_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[6]); });\n+\n+    svcWaitSynchronization(events[0], U64_MAX);\n+\n+    // Make sure we cant get either mutex\n+    res = svcWaitSynchronizationN(&output, mutexes, 2, 1, ONE_SECOND / 2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[6], 1, 1, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// WaitSynchN wait_all=false; signaled event0, unlocked mutex0; Make sure mutex0 does not lock and\n+// it does not wait\n+\n+void thread7_handler(void*) {\n+    s32 output = 0;\n+    Handle handles[] = { events[2], mutexes[0] };\n+\n+    svcWaitSynchronizationN(&output, handles, 2, 0, U64_MAX);\n+    svcSignalEvent(events[0]);\n+    svcWaitSynchronization(events[1], U64_MAX);\n+\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_20() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle handles[] = { events[2], mutexes[0] };\n+\n+    svcReleaseMutex(mutexes[0]);\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcSignalEvent(events[2]);\n+\n+    svcCreateThread(&threads[7], thread7_handler, 0x0, (u32*)(&thread7_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[7]); });\n+\n+    svcWaitSynchronization(events[0], U64_MAX);\n+    svcClearEvent(events[2]);\n+\n+    // Make sure we can still get the mutex\n+    res = svcWaitSynchronizationN(&output, handles, 2, 0, U64_MAX);\n+    SoftAssert(output == 1);\n+    SoftAssert(res == 0);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[7], 1, 1, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+void thread8_handler(void*) {\n+    s32 output = 0;\n+    Handle handles[] = { events[2], mutexes[0] };\n+\n+    svcWaitSynchronizationN(&output, handles, 2, 1, U64_MAX);\n+    svcSignalEvent(events[0]);\n+    svcWaitSynchronization(events[1], U64_MAX);\n+\n+    svcExitThread();\n+}\n+\n+// WaitSynchN wait_all=true; signaled event0, unlocked mutex0; Make sure mutex0 locks and it does\n+// not wait  \n+\n+bool Test_WaitSynchN_21() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle handles[] = { events[2], mutexes[0] };\n+\n+    svcReleaseMutex(mutexes[0]);\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcSignalEvent(events[2]);\n+\n+    svcCreateThread(&threads[8], thread8_handler, 0x0, (u32*)(&thread8_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[8]); });\n+\n+    svcWaitSynchronization(events[0], U64_MAX);\n+    svcClearEvent(events[2]);\n+\n+    // Make sure we can't get the mutex\n+    res = svcWaitSynchronizationN(&output, handles, 2, 0, ONE_SECOND/2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[8], 1, 1, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// WaitSynchN with wait_all=true, 2 objects, 1 ready, 1 not, set the first one not and the second\n+// one ready in a thread\n+\n+void thread9_handler(void*) {\n+    svcSignalEvent(events[0]);\n+    svcClearEvent(events[1]);\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_22() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+    svcSignalEvent(events[1]);\n+\n+    svcCreateThread(&threads[9], thread9_handler, 0x0, (u32*)(&thread9_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[9]); });\n+\n+    // Make sure we don't timeout\n+    res = svcWaitSynchronizationN(&output, events, 2, 1, ONE_SECOND/2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[9], 1, 1, U64_MAX); // Wait for all threads to complete\n+\n+    // NOTE: We won't pass this test correctly until we improve our scheduling. On real HW, the\n+    // thread will have already finished, and this will be 0. On Citra, the thread finishes on this\n+    // Wait, and the result is -1\n+    //SoftAssert(output == 0);\n+\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Call WaitSynchN with a service handle\n+\n+bool Test_WaitSynchN_23() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    Handle service = 0;\n+    SoftAssert(srvGetServiceHandle(&service, \"APT:U\") == 0);\n+    SoftAssert(service != 0);\n+    SCOPE_EXIT({ svcCloseHandle(service); });\n+\n+    // Make sure we don't timeout\n+    res = svcWaitSynchronizationN(&output, &service, 1, 0, ONE_SECOND/2);\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    return true;\n+}\n+\n+// WaitSynchN with an invalid handle passed in, nothing should wait\n+\n+bool Test_WaitSynchN_24() {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle handles[] = { events[0], 0xDEADBEEF };\n+\n+    svcSignalEvent(events[0]);\n+\n+    res = svcWaitSynchronizationN(&output, handles, 2, 0, U64_MAX);\n+    SoftAssert(res == 0xD8E007F7);\n+\n+    res = svcWaitSynchronizationN(&output, handles, 2, 1, ONE_SECOND / 2);\n+    SoftAssert(res == 0xD8E007F7);\n+\n+    return true;\n+}\n+\n+// WaitSynchN with an invalid handle passed in, nothing should lock\n+\n+void thread10_handler(void*) {\n+    s32 output = 0;\n+    s32 res = 0;\n+    Handle handles[] = { mutexes[0], 0xDEADBEEF };\n+\n+    res = svcWaitSynchronizationN(&output, handles, 2, 0, U64_MAX);\n+\n+    svcSignalEvent(events[0]);\n+\n+    svcWaitSynchronization(events[1], U64_MAX);\n+\n+    svcExitThread();\n+}\n+\n+bool Test_WaitSynchN_25() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcReleaseMutex(mutexes[0]);\n+\n+    svcClearEvent(events[0]);\n+    svcClearEvent(events[1]);\n+\n+    svcCreateThread(&threads[10], thread10_handler, 0x0, (u32*)(&thread10_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[10]); });\n+\n+    svcWaitSynchronization(events[0], U64_MAX);\n+\n+    // Make sure we can still get mutex 0 due to the invalid handle\n+    res = svcWaitSynchronizationN(&output, mutexes, 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    svcSignalEvent(events[1]);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[10], 1, 1, U64_MAX); // Wait for all threads to complete\n+    SoftAssert(output == -1);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynch1 with a timeout and with wait=0\n+\n+bool Test_WaitSynch1_00() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+\n+    res = svcWaitSynchronization(events[0], ONE_SECOND / 2);\n+    SoftAssert(res == 0x09401BFE);\n+\n+    svcSignalEvent(events[0]);\n+    res = svcWaitSynchronization(events[0], U64_MAX);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynch1 with wait=1\n+\n+bool Test_WaitSynch1_01() {\n+    s32 output = 0;\n+    s32 res = 0;\n+\n+    svcClearEvent(events[0]);\n+\n+    svcCreateThread(&threads[0], thread0_handler, 0x0, (u32*)(&thread0_stack[0x400]), 0x31, 0xfffffffe);\n+    SCOPE_EXIT({ svcCloseHandle(threads[0]); });\n+\n+    res = svcWaitSynchronization(events[0], U64_MAX);\n+    SoftAssert(output == 0);\n+\n+    res = svcWaitSynchronizationN(&output, &threads[0], 1, 0, U64_MAX);\n+    SoftAssert(output == 0);\n+    SoftAssert(res == 0);\n+\n+    return true;\n+}\n+\n+// Test WaitSynch1 with an invalid handle\n+\n+bool Test_WaitSynch1_02() {\n+    s32 res = svcWaitSynchronization(0xDEADBEEF, U64_MAX);\n+    SoftAssert(res == 0xD8E007F7);\n+    return true;\n+}\n+\n+// Test WaitSynch1 with a service handle\n+\n+bool Test_WaitSynch1_03() {\n+    s32 res = 0;\n+    Handle service = 0;\n+\n+    srvGetServiceHandle(&service, \"soc:U\");\n+    SCOPE_EXIT({ svcCloseHandle(service); });\n+\n+    res = svcWaitSynchronization(service, ONE_SECOND/2);\n+    SoftAssert(res == 0x09401BFE);","path":"source/tests/waitsynch/waitsynch.cpp","position":860,"original_position":860,"commit_id":"6d44c655c4d09b73ec6fe517f131b08b8dc6f1b7","original_commit_id":"6d44c655c4d09b73ec6fe517f131b08b8dc6f1b7","user":{"login":"yuriks","id":341401,"avatar_url":"https://avatars.githubusercontent.com/u/341401?v=3","gravatar_id":"","url":"https://api.github.com/users/yuriks","html_url":"https://github.com/yuriks","followers_url":"https://api.github.com/users/yuriks/followers","following_url":"https://api.github.com/users/yuriks/following{/other_user}","gists_url":"https://api.github.com/users/yuriks/gists{/gist_id}","starred_url":"https://api.github.com/users/yuriks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yuriks/subscriptions","organizations_url":"https://api.github.com/users/yuriks/orgs","repos_url":"https://api.github.com/users/yuriks/repos","events_url":"https://api.github.com/users/yuriks/events{/privacy}","received_events_url":"https://api.github.com/users/yuriks/received_events","type":"User","site_admin":false},"body":"Name this","created_at":"2015-02-13T01:14:12Z","updated_at":"2015-02-13T01:14:12Z","html_url":"https://github.com/citra-emu/hwtests/pull/22#discussion_r24637333","pull_request_url":"https://api.github.com/repos/citra-emu/hwtests/pulls/22","_links":{"self":{"href":"https://api.github.com/repos/citra-emu/hwtests/pulls/comments/24637333"},"html":{"href":"https://github.com/citra-emu/hwtests/pull/22#discussion_r24637333"},"pull_request":{"href":"https://api.github.com/repos/citra-emu/hwtests/pulls/22"}}},"pull_request":{"url":"https://api.github.com/repos/citra-emu/hwtests/pulls/22","id":29151568,"html_url":"https://github.com/citra-emu/hwtests/pull/22","diff_url":"https://github.com/citra-emu/hwtests/pull/22.diff","patch_url":"https://github.com/citra-emu/hwtests/pull/22.patch","issue_url":"https://api.github.com/repos/citra-emu/hwtests/issues/22","number":22,"state":"open","locked":false,"title":"Added WaitSynchN/WaitSynch1 tests","user":{"login":"bunnei","id":6956688,"avatar_url":"https://avatars.githubusercontent.com/u/6956688?v=3","gravatar_id":"","url":"https://api.github.com/users/bunnei","html_url":"https://github.com/bunnei","followers_url":"https://api.github.com/users/bunnei/followers","following_url":"https://api.github.com/users/bunnei/following{/other_user}","gists_url":"https://api.github.com/users/bunnei/gists{/gist_id}","starred_url":"https://api.github.com/users/bunnei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bunnei/subscriptions","organizations_url":"https://api.github.com/users/bunnei/orgs","repos_url":"https://api.github.com/users/bunnei/repos","events_url":"https://api.github.com/users/bunnei/events{/privacy}","received_events_url":"https://api.github.com/users/bunnei/received_events","type":"User","site_admin":false},"body":"When fixing up our implementations of the WaitSynhronizationN and WaitSynchronization1 SVCs, I wrote a ton of tests to make sure I didn't introduce any regressions. These have been sitting around collecting dust for a while because 1) there was a bug that made them not all run sequentially on hardware, and 2) they were messy.. At any rate, I found the solution to 1) when https://github.com/citra-emu/citra/pull/551 was merged (as Citra started hanging like hardware, so I was able to fix the issue), so I'd rather just see these become part of hwtests (to prevent any future regressions) despite the fact that the code isn't super great. These tests exercise a lot of corner cases. At the very least, I spent a bit of time making the code not horrible, but yeah, I don't really plan on spending more time on this in the near term (except maybe adding new tests in the future to help me fix things I know Citra does not do correctly, such as WaitSynch on a Session object).","created_at":"2015-02-12T04:07:54Z","updated_at":"2015-02-13T01:14:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fe355ae5d2fcf6466cf8e02291695bb09a58b6fc","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/citra-emu/hwtests/pulls/22/commits","review_comments_url":"https://api.github.com/repos/citra-emu/hwtests/pulls/22/comments","review_comment_url":"https://api.github.com/repos/citra-emu/hwtests/pulls/comments/{number}","comments_url":"https://api.github.com/repos/citra-emu/hwtests/issues/22/comments","statuses_url":"https://api.github.com/repos/citra-emu/hwtests/statuses/6d44c655c4d09b73ec6fe517f131b08b8dc6f1b7","head":{"label":"bunnei:waitsynch-tests","ref":"waitsynch-tests","sha":"6d44c655c4d09b73ec6fe517f131b08b8dc6f1b7","user":{"login":"bunnei","id":6956688,"avatar_url":"https://avatars.githubusercontent.com/u/6956688?v=3","gravatar_id":"","url":"https://api.github.com/users/bunnei","html_url":"https://github.com/bunnei","followers_url":"https://api.github.com/users/bunnei/followers","following_url":"https://api.github.com/users/bunnei/following{/other_user}","gists_url":"https://api.github.com/users/bunnei/gists{/gist_id}","starred_url":"https://api.github.com/users/bunnei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bunnei/subscriptions","organizations_url":"https://api.github.com/users/bunnei/orgs","repos_url":"https://api.github.com/users/bunnei/repos","events_url":"https://api.github.com/users/bunnei/events{/privacy}","received_events_url":"https://api.github.com/users/bunnei/received_events","type":"User","site_admin":false},"repo":{"id":27853244,"name":"hwtests","full_name":"bunnei/hwtests","owner":{"login":"bunnei","id":6956688,"avatar_url":"https://avatars.githubusercontent.com/u/6956688?v=3","gravatar_id":"","url":"https://api.github.com/users/bunnei","html_url":"https://github.com/bunnei","followers_url":"https://api.github.com/users/bunnei/followers","following_url":"https://api.github.com/users/bunnei/following{/other_user}","gists_url":"https://api.github.com/users/bunnei/gists{/gist_id}","starred_url":"https://api.github.com/users/bunnei/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bunnei/subscriptions","organizations_url":"https://api.github.com/users/bunnei/orgs","repos_url":"https://api.github.com/users/bunnei/repos","events_url":"https://api.github.com/users/bunnei/events{/privacy}","received_events_url":"https://api.github.com/users/bunnei/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bunnei/hwtests","description":"Beginnings of a hwtest suite for Citra","fork":true,"url":"https://api.github.com/repos/bunnei/hwtests","forks_url":"https://api.github.com/repos/bunnei/hwtests/forks","keys_url":"https://api.github.com/repos/bunnei/hwtests/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bunnei/hwtests/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bunnei/hwtests/teams","hooks_url":"https://api.github.com/repos/bunnei/hwtests/hooks","issue_events_url":"https://api.github.com/repos/bunnei/hwtests/issues/events{/number}","events_url":"https://api.github.com/repos/bunnei/hwtests/events","assignees_url":"https://api.github.com/repos/bunnei/hwtests/assignees{/user}","branches_url":"https://api.github.com/repos/bunnei/hwtests/branches{/branch}","tags_url":"https://api.github.com/repos/bunnei/hwtests/tags","blobs_url":"https://api.github.com/repos/bunnei/hwtests/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bunnei/hwtests/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bunnei/hwtests/git/refs{/sha}","trees_url":"https://api.github.com/repos/bunnei/hwtests/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bunnei/hwtests/statuses/{sha}","languages_url":"https://api.github.com/repos/bunnei/hwtests/languages","stargazers_url":"https://api.github.com/repos/bunnei/hwtests/stargazers","contributors_url":"https://api.github.com/repos/bunnei/hwtests/contributors","subscribers_url":"https://api.github.com/repos/bunnei/hwtests/subscribers","subscription_url":"https://api.github.com/repos/bunnei/hwtests/subscription","commits_url":"https://api.github.com/repos/bunnei/hwtests/commits{/sha}","git_commits_url":"https://api.github.com/repos/bunnei/hwtests/git/commits{/sha}","comments_url":"https://api.github.com/repos/bunnei/hwtests/comments{/number}","issue_comment_url":"https://api.github.com/repos/bunnei/hwtests/issues/comments/{number}","contents_url":"https://api.github.com/repos/bunnei/hwtests/contents/{+path}","compare_url":"https://api.github.com/repos/bunnei/hwtests/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bunnei/hwtests/merges","archive_url":"https://api.github.com/repos/bunnei/hwtests/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bunnei/hwtests/downloads","issues_url":"https://api.github.com/repos/bunnei/hwtests/issues{/number}","pulls_url":"https://api.github.com/repos/bunnei/hwtests/pulls{/number}","milestones_url":"https://api.github.com/repos/bunnei/hwtests/milestones{/number}","notifications_url":"https://api.github.com/repos/bunnei/hwtests/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bunnei/hwtests/labels{/name}","releases_url":"https://api.github.com/repos/bunnei/hwtests/releases{/id}","created_at":"2014-12-11T03:59:05Z","updated_at":"2014-12-18T15:05:27Z","pushed_at":"2015-02-13T00:56:08Z","git_url":"git://github.com/bunnei/hwtests.git","ssh_url":"git@github.com:bunnei/hwtests.git","clone_url":"https://github.com/bunnei/hwtests.git","svn_url":"https://github.com/bunnei/hwtests","homepage":"http://citra-emu.org","size":104,"stargazers_count":1,"watchers_count":1,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"citra-emu:master","ref":"master","sha":"b3e1617c8229750c7ab18958e1621549ca30b138","user":{"login":"citra-emu","id":7605670,"avatar_url":"https://avatars.githubusercontent.com/u/7605670?v=3","gravatar_id":"","url":"https://api.github.com/users/citra-emu","html_url":"https://github.com/citra-emu","followers_url":"https://api.github.com/users/citra-emu/followers","following_url":"https://api.github.com/users/citra-emu/following{/other_user}","gists_url":"https://api.github.com/users/citra-emu/gists{/gist_id}","starred_url":"https://api.github.com/users/citra-emu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citra-emu/subscriptions","organizations_url":"https://api.github.com/users/citra-emu/orgs","repos_url":"https://api.github.com/users/citra-emu/repos","events_url":"https://api.github.com/users/citra-emu/events{/privacy}","received_events_url":"https://api.github.com/users/citra-emu/received_events","type":"Organization","site_admin":false},"repo":{"id":27095065,"name":"hwtests","full_name":"citra-emu/hwtests","owner":{"login":"citra-emu","id":7605670,"avatar_url":"https://avatars.githubusercontent.com/u/7605670?v=3","gravatar_id":"","url":"https://api.github.com/users/citra-emu","html_url":"https://github.com/citra-emu","followers_url":"https://api.github.com/users/citra-emu/followers","following_url":"https://api.github.com/users/citra-emu/following{/other_user}","gists_url":"https://api.github.com/users/citra-emu/gists{/gist_id}","starred_url":"https://api.github.com/users/citra-emu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citra-emu/subscriptions","organizations_url":"https://api.github.com/users/citra-emu/orgs","repos_url":"https://api.github.com/users/citra-emu/repos","events_url":"https://api.github.com/users/citra-emu/events{/privacy}","received_events_url":"https://api.github.com/users/citra-emu/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/citra-emu/hwtests","description":"Beginnings of a hwtest suite for Citra","fork":false,"url":"https://api.github.com/repos/citra-emu/hwtests","forks_url":"https://api.github.com/repos/citra-emu/hwtests/forks","keys_url":"https://api.github.com/repos/citra-emu/hwtests/keys{/key_id}","collaborators_url":"https://api.github.com/repos/citra-emu/hwtests/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/citra-emu/hwtests/teams","hooks_url":"https://api.github.com/repos/citra-emu/hwtests/hooks","issue_events_url":"https://api.github.com/repos/citra-emu/hwtests/issues/events{/number}","events_url":"https://api.github.com/repos/citra-emu/hwtests/events","assignees_url":"https://api.github.com/repos/citra-emu/hwtests/assignees{/user}","branches_url":"https://api.github.com/repos/citra-emu/hwtests/branches{/branch}","tags_url":"https://api.github.com/repos/citra-emu/hwtests/tags","blobs_url":"https://api.github.com/repos/citra-emu/hwtests/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/citra-emu/hwtests/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/citra-emu/hwtests/git/refs{/sha}","trees_url":"https://api.github.com/repos/citra-emu/hwtests/git/trees{/sha}","statuses_url":"https://api.github.com/repos/citra-emu/hwtests/statuses/{sha}","languages_url":"https://api.github.com/repos/citra-emu/hwtests/languages","stargazers_url":"https://api.github.com/repos/citra-emu/hwtests/stargazers","contributors_url":"https://api.github.com/repos/citra-emu/hwtests/contributors","subscribers_url":"https://api.github.com/repos/citra-emu/hwtests/subscribers","subscription_url":"https://api.github.com/repos/citra-emu/hwtests/subscription","commits_url":"https://api.github.com/repos/citra-emu/hwtests/commits{/sha}","git_commits_url":"https://api.github.com/repos/citra-emu/hwtests/git/commits{/sha}","comments_url":"https://api.github.com/repos/citra-emu/hwtests/comments{/number}","issue_comment_url":"https://api.github.com/repos/citra-emu/hwtests/issues/comments/{number}","contents_url":"https://api.github.com/repos/citra-emu/hwtests/contents/{+path}","compare_url":"https://api.github.com/repos/citra-emu/hwtests/compare/{base}...{head}","merges_url":"https://api.github.com/repos/citra-emu/hwtests/merges","archive_url":"https://api.github.com/repos/citra-emu/hwtests/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/citra-emu/hwtests/downloads","issues_url":"https://api.github.com/repos/citra-emu/hwtests/issues{/number}","pulls_url":"https://api.github.com/repos/citra-emu/hwtests/pulls{/number}","milestones_url":"https://api.github.com/repos/citra-emu/hwtests/milestones{/number}","notifications_url":"https://api.github.com/repos/citra-emu/hwtests/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/citra-emu/hwtests/labels{/name}","releases_url":"https://api.github.com/repos/citra-emu/hwtests/releases{/id}","created_at":"2014-11-24T21:03:20Z","updated_at":"2015-02-06T14:00:35Z","pushed_at":"2015-01-30T20:50:20Z","git_url":"git://github.com/citra-emu/hwtests.git","ssh_url":"git@github.com:citra-emu/hwtests.git","clone_url":"https://github.com/citra-emu/hwtests.git","svn_url":"https://github.com/citra-emu/hwtests","homepage":"http://citra-emu.org","size":442,"stargazers_count":1,"watchers_count":1,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":7,"mirror_url":null,"open_issues_count":2,"forks":7,"open_issues":2,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/citra-emu/hwtests/pulls/22"},"html":{"href":"https://github.com/citra-emu/hwtests/pull/22"},"issue":{"href":"https://api.github.com/repos/citra-emu/hwtests/issues/22"},"comments":{"href":"https://api.github.com/repos/citra-emu/hwtests/issues/22/comments"},"review_comments":{"href":"https://api.github.com/repos/citra-emu/hwtests/pulls/22/comments"},"review_comment":{"href":"https://api.github.com/repos/citra-emu/hwtests/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/citra-emu/hwtests/pulls/22/commits"},"statuses":{"href":"https://api.github.com/repos/citra-emu/hwtests/statuses/6d44c655c4d09b73ec6fe517f131b08b8dc6f1b7"}}}}