void checkDispatchCases(const char *name, void (*testfunc)(int)) { int state; dispatchCheckpoint("%s without changes:", name); testfunc(0); flushschedf(); didResched = 0; schedf("\n"); dispatchCheckpoint("%s with short dispatch suspend:", name); testfunc(1); flushschedf(); didResched = 0; schedf("\n"); dispatchCheckpoint("%s while dispatch suspended:", name); // Starting a thread apparently resumes the dispatch thread. ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); testfunc(0); dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; flushschedf(); didResched = 0; schedf("\n"); dispatchCheckpoint("%s while intr suspended:", name); state = sceKernelCpuSuspendIntr(); dispatchCheckpoint("sceKernelCpuSuspendIntr: %08x", state); testfunc(1); dispatchCheckpoint("sceKernelCpuResumeIntr: %08x", sceKernelCpuResumeIntr(state)); flushschedf(); }
void displayBuffer(const char *reason) { sceKernelDcacheWritebackInvalidateAll(); sceDmacMemcpy(copybuf, drawbuf, sizeof(copybuf)); sceKernelDcacheWritebackInvalidateAll(); const u32 *buf = copybuf; checkpoint(NULL); schedf("%s: ", reason); // This prevents drawing to the screen, which makes the test faster. HAS_DISPLAY = 0; for (int y = 0; y < 1; ++y) { for (int x = 0; x < 1; ++x) { // For the purposes of this test, ignore alpha. schedf("%06x", buf[y * 512 + x] & 0x00FFFFFF); } schedf("\n"); flushschedf(); } HAS_DISPLAY = 1; // Reset. memset(copybuf, 0, sizeof(copybuf)); sceKernelDcacheWritebackInvalidateAll(); sceDmacMemcpy(drawbuf, copybuf, sizeof(copybuf)); sceKernelDcacheWritebackInvalidateAll(); }
int main(int argc, char **argv) { int result; int check_not_update_value = 7; SceKernelSemaInfo info; sema = sceKernelCreateSema("sema1", 0, 0, 2, NULL); sceKernelReferSemaStatus(sema, &info); PRINT_SEMAPHORE(sema, info); threads[0] = sceKernelCreateThread("Thread-0", (void *)&threadFunction, 0x12, 0x10000, 0, NULL); threads[1] = sceKernelCreateThread("Thread-1", (void *)&threadFunction, 0x12, 0x10000, 0, NULL); threads[2] = sceKernelCreateThread("Thread-2", (void *)&threadFunction, 0x12, 0x10000, 0, NULL); threads[3] = sceKernelCreateThread("Thread-3", (void *)&threadFunction, 0x12, 0x10000, 0, NULL); threads[4] = sceKernelCreateThread("Thread-4", (void *)&threadFunction2, 0x12, 0x10000, 0, NULL); schedf("VALUE-INVARIANT:%d\n", check_not_update_value); sceKernelStartThread(threads[0], 1, (void*)&test[1]); sceKernelStartThread(threads[1], 2, NULL); sceKernelStartThread(threads[2], 0, (void*)&test[0]); sceKernelStartThread(threads[3], sizeof(int), (void*)&test[4]); sceKernelStartThread(threads[4], sizeof(int), &check_not_update_value); sceKernelDelayThread(10 * 1000); schedf("---\n"); sceKernelReferSemaStatus(sema, &info); PRINT_SEMAPHORE(sema, info); schedf("---\n"); sceKernelSignalSema(sema, 1); sceKernelDelayThread(10 * 1000); schedf("---\n"); sceKernelReferSemaStatus(sema, &info); PRINT_SEMAPHORE(sema, info); schedf("---\n"); sceKernelSignalSema(sema, 1); sceKernelDelayThread(10 * 1000); schedf("---\n"); sceKernelReferSemaStatus(sema, &info); PRINT_SEMAPHORE(sema, info); schedf("---\n"); result = sceKernelDeleteSema(sema); schedf("%08X\n", result); result = sceKernelDeleteSema(sema); schedf("%08X\n", result); schedf("VALUE-INVARIANT:%d\n", check_not_update_value); flushschedf(); return 0; }
int main(int argc, char **argv) { SceUID sema = sceKernelCreateSema("wait1", 0, 1, 1, NULL); WAIT_TEST_SIMPLE("Signaled", sema, 1); WAIT_TEST_SIMPLE("Greater than max", sema, 100); WAIT_TEST_SIMPLE("Negative", sema, -1); sceKernelSignalSema(sema, 1); WAIT_TEST_SIMPLE_TIMEOUT("Signaled", sema, 1, 500); WAIT_TEST_SIMPLE_TIMEOUT("Never signaled", sema, 1, 500); WAIT_TEST_SIMPLE_TIMEOUT("Greater than max", sema, 100, 500); WAIT_TEST_SIMPLE_TIMEOUT("Zero", sema, 0, 500); WAIT_TEST_SIMPLE_TIMEOUT("Negative", sema, -1, 500); WAIT_TEST_SIMPLE_TIMEOUT("Zero timeout", sema, 1, 0); // Signaled off thread. printf("Wait timeout: "); schedulingPlacement = 1; SCHED_LOG(A, 1); SceUInt timeout = 5000; SceUID thread = sceKernelCreateThread("waitTest", (void *)&waitTestFunc, 0x12, 0x10000, 0, NULL); sceKernelStartThread(thread, sizeof(int), &sema); SCHED_LOG(B, 1); int result = sceKernelWaitSema(sema, 1, &timeout); SCHED_LOG(E, 1); schedf(" (thread=%08X, main=%08X, remaining=%d)\n", schedulingResult, result, timeout / 1000); flushschedf(); sceKernelDeleteSema(sema); SceUID deleteThread = CREATE_SIMPLE_THREAD(deleteMeFunc); sema = sceKernelCreateSema("wait1", 0, 0, 1, NULL); sceKernelStartThread(deleteThread, sizeof(int), &sema); sceKernelDelayThread(500); sceKernelDeleteSema(sema); flushschedf(); WAIT_TEST_SIMPLE("NULL", 0, 1); WAIT_TEST_SIMPLE("Invalid", 0xDEADBEEF, 1); WAIT_TEST_SIMPLE("Deleted", sema, 1); BASIC_SCHED_TEST("NULL", result = sceKernelWaitSema(0, 1, NULL); );
void testDiff() { SceUID vpl = sceKernelCreateVpl("vpl", PSP_MEMORY_PARTITION_USER, 0, 0x10000, NULL); char *data1, *data2, *data3; sceKernelTryAllocateVpl(vpl, 0x08, (void **) &data1); sceKernelTryAllocateVpl(vpl, 0x10, (void **) &data2); sceKernelTryAllocateVpl(vpl, 0x01, (void **) &data3); schedf("Three 0x08s: diff=%x, %x\n", data1 - data2, data2 - data3); flushschedf(); sceKernelDeleteVpl(vpl); }
int main(int argc, char **argv) { LOCK_TEST("Lock 0 => 0", PSP_MUTEX_ATTR_FIFO, 0, 0); LOCK_TEST("Lock 0 => 1", PSP_MUTEX_ATTR_FIFO, 0, 1); LOCK_TEST("Lock 0 => 2", PSP_MUTEX_ATTR_FIFO, 0, 2); LOCK_TEST("Lock 0 => -1", PSP_MUTEX_ATTR_FIFO, 0, -1); LOCK_TEST("Lock 1 => 1", PSP_MUTEX_ATTR_FIFO, 1, 1); LOCK_TEST("Lock 0 => 2 (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 0, 2); LOCK_TEST("Lock 0 => -1 (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 0, -1); LOCK_TEST("Lock 1 => 1 (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 1, 1); LOCK_TEST("Lock 1 => INT_MAX - 1 (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 1, INT_MAX - 1); LOCK_TEST("Lock 1 => INT_MAX (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 1, INT_MAX); LOCK_TEST("Lock INT_MAX => INT_MAX (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, INT_MAX, INT_MAX); flushschedf(); SceUID lockThread = CREATE_SIMPLE_THREAD(lockFunc); LOCK_TEST_THREAD("Locked 1 => 1", PSP_MUTEX_ATTR_FIFO, 1, 1); LOCK_TEST_THREAD("Locked 0 => 1", PSP_MUTEX_ATTR_FIFO, 0, 1); LOCK_TEST_THREAD("Locked 1 => 1 (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 1, 1); LOCK_TEST_THREAD("Locked 0 => 1 (recursive)", PSP_MUTEX_ATTR_ALLOW_RECURSIVE, 0, 1); // Probably we can't manage to delete it at the same time. SceUID deleteThread = CREATE_SIMPLE_THREAD(deleteMeFunc); SceLwMutexWorkarea workarea; sceKernelCreateLwMutex(&workarea, "lock", 0, 1, NULL); void *workareaPtr = &workarea; sceKernelStartThread(deleteThread, sizeof(int), &workareaPtr); sceKernelDeleteLwMutex(&workarea); flushschedf(); // Crashes. //LOCK_TEST_SIMPLE("NULL => 0", 0, 0); //LOCK_TEST_SIMPLE("NULL => 1", 0, 1); //LOCK_TEST_SIMPLE("Invalid => 1", (void*) 0xDEADBEEF, 1); LOCK_TEST_SIMPLE("Deleted => 1", &workarea, 1); BASIC_SCHED_TEST("Zero", result = sceKernelTryLockLwMutex(&workarea2, 0); );
int main(int argc, char **argv) { SceUID vpl = sceKernelCreateVpl("vpl", PSP_MEMORY_PARTITION_USER, 0, 0x10000, NULL); void *data; testTryAlloc("More than free", vpl, 0xFFE1, 1); testTryAlloc("0 bytes", vpl, 0, 1); testTryAlloc("1 byte", vpl, 1, 1); testTryAlloc("-1 bytes", vpl, -1, 1); testTryAlloc("16 bytes", vpl, 16, 1); testTryAlloc("8 bytes", vpl, 8, 1); // Crashes. //testTryAlloc("Into NULL", vpl, 8, 0); testTryAlloc("Most remaining", vpl, 0xFF00, 1); testTryAlloc("More than remaining", vpl, 0xA1, 1); testTryAlloc("All remaining", vpl, 0xA0, 1); testTryAlloc("All remaining - 7", vpl, 0xA0 - 7, 1); testTryAlloc("All remaining - 8", vpl, 0xA0 - 8, 1); testTryAlloc("1 byte (none left)", vpl, 1, 1); sceKernelDeleteVpl(vpl); testTryAlloc("NULL", 0, 0x100, 1); testTryAlloc("NULL with invalid", 0, 0, 0); testTryAlloc("Invalid", 0xDEADBEEF, 0x100, 1); testTryAlloc("Deleted", vpl, 0x100, 1); flushschedf(); testDiff(); u32 attrs[] = {PSP_VPL_ATTR_FIFO, PSP_VPL_ATTR_PRIORITY, PSP_VPL_ATTR_SMALLEST, PSP_VPL_ATTR_HIGHMEM}; int i; for (i = 0; i < sizeof(attrs) / sizeof(attrs[0]); ++i) { schedf("Attr %x:\n", attrs[i]); testTryAllocThread(" Alloc 0x20 of 0x00/0xE0", attrs[i], 0x20, 0xE0 - 0x08); testTryAllocThread(" Alloc 0x20 of 0x20/0xE0", attrs[i], 0x20, 0xE0 - 0x08 - (0x20 + 0x08)); testTryAllocThread(" Alloc 0x20 of 0x40/0xE0", attrs[i], 0x20, 0xE0 - 0x08 - (0x20 + 0x08) * 2); schedf("\n"); } BASIC_SCHED_TEST("Zero", result = sceKernelTryAllocateVpl(vpl1, 0, &data); );
void displayBuffer(const char *reason) { sceKernelDcacheWritebackInvalidateAll(); sceDmacMemcpy(copybuf, drawbuf, sizeof(copybuf)); sceKernelDcacheWritebackInvalidateAll(); const u32 *buf = copybuf; checkpoint(reason); // This prevents drawing to the screen, which makes the test faster. HAS_DISPLAY = 0; for (int y = 0; y < 272; ++y) { for (int x = 0; x < 480; ++x) { if (buf[y * 512 + x] != 0) { schedf("%x", buf[y * 512 + x]); } else { schedf(" "); } } schedf("\n"); flushschedf(); } HAS_DISPLAY = 1; }
void checkDispatchInterrupt() { dispatchCheckpoint("Interrupts while dispatch disabled:"); sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, &vblankCallback, NULL); sceKernelEnableSubIntr(PSP_VBLANK_INT, 0); ++ignoreResched; int state = sceKernelSuspendDispatchThread(); int base = sceDisplayGetVcount(); int i, j; for (i = 0; i < 1000; ++i) { if (sceDisplayGetVcount() > base + 3) { break; } for (j = 0; j < 10000; ++j) continue; } dispatchCheckpoint("vblanks=%d", sceDisplayGetVcount() - base); sceKernelResumeDispatchThread(state); --ignoreResched; base = sceDisplayGetVcount(); for (i = 0; i < 1000; ++i) { if (sceDisplayGetVcount() > base + 3) { break; } for (j = 0; j < 10000; ++j) continue; } dispatchCheckpoint("vblanks=%d", sceDisplayGetVcount() - base); sceKernelDisableSubIntr(PSP_VBLANK_INT, 0); sceKernelReleaseSubIntrHandler(PSP_VBLANK_INT, 0); flushschedf(); }
void runReferTests() { SceKernelThreadInfo2 info; int i; SceUID delayThread = sceKernelCreateThread("delay", &delayFunc, sceKernelGetThreadCurrentPriority(), 0x1000, PSP_THREAD_ATTR_VFPU, NULL); SceUID deletedThread = sceKernelCreateThread("deleted", &delayFunc, sceKernelGetThreadCurrentPriority(), 0x1000, 0, NULL); sceKernelDeleteThread(deletedThread); info.size = sizeof(info); checkpointNext("Thread IDs:"); checkpoint(" NULL: %08x", sceKernelReferThreadStatus(0, &info)); checkpoint(" Current: %08x", sceKernelReferThreadStatus(sceKernelGetThreadId(), &info)); checkpoint(" Deleted: %08x", sceKernelReferThreadStatus(deletedThread, &info)); checkpoint(" Invalid: %08x", sceKernelReferThreadStatus(0xDEADBEEF, &info)); // Crashes. //checkpointNext("sceKernelReferThreadStatus info ptr:"); //checkpoint(" NULL info: %08x", sceKernelReferThreadStatus(0, NULL)); checkpointNext("Sizes:"); int sizes[] = {-1, 0, 1, 2, 3, 4, 5, 8, 16, 32, 64, 80, 82, 108, 128, 1024}; for (i = 0; i < ARRAY_SIZE(sizes); ++i) { memset(&info, 0xff, sizeof(info)); info.size = sizes[i]; int result = sceKernelReferThreadStatus(0, &info); checkpoint(" %d: %08x => %d (exit: %x)", sizes[i], result, info.size, info.exitStatus); } info.size = sizeof(info); sceKernelStartThread(delayThread, 0, NULL); sceKernelReferThreadStatus(delayThread, &info); checkpointNext("Values:"); schedfThreadInfo(&info, &delayFunc); SceUID slumberThread = sceKernelCreateThread("slumber", &slumberFunc, sceKernelGetThreadCurrentPriority() - 1, 0x1000, 0, NULL); checkpoint(" slumber before start:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelStartThread(slumberThread, 0, NULL); checkpoint(" started slumber"); checkpoint(" slumber after start:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelTerminateThread(slumberThread); checkpoint(" terminated slumber"); checkpoint(" slumber after terminate:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelStartThread(slumberThread, 0, NULL); checkpoint(" started slumber"); checkpoint(" slumber after start:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); checkpoint(" woke slumber: %08x", sceKernelWakeupThread(slumberThread)); checkpoint(" slumber after wake:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelTerminateDeleteThread(slumberThread); checkpoint(" terminated and deleted slumber"); // TODO: Test more cases. flushschedf(); }
int main(int argc, char **argv) { SceUID vpl = sceKernelCreateVpl("vpl", PSP_MEMORY_PARTITION_USER, 0, 0x10000, NULL); void *data; schedf("No timeout:\n"); testAlloc(" More than free", vpl, 0xFFE1, 1); testAlloc(" 0 bytes", vpl, 0, 1); testAlloc(" 1 byte", vpl, 1, 1); testAlloc(" -1 bytes", vpl, -1, 1); testAlloc(" 16 bytes", vpl, 16, 1); testAlloc(" 8 bytes", vpl, 8, 1); schedf("\nWith timeout:\n"); testAllocTimeout(" More than free", vpl, 0xFFE1, 500, 1); testAllocTimeout(" 0 bytes", vpl, 0, 500, 1); testAllocTimeout(" 1 byte", vpl, 1, 500, 1); testAllocTimeout(" -1 bytes", vpl, -1, 500, 1); testAllocTimeout(" 16 bytes", vpl, 16, 500, 1); testAllocTimeout(" 8 bytes", vpl, 8, 500, 1); schedf("\nErrors:\n"); // Crashes. //testAllocTimeout("Into NULL", vpl, 8, 500, 0); testAllocTimeout(" Into NULL", vpl, 0xFFE0, 500, 0); testAllocTimeout(" Most remaining", vpl, 0xFF00, 500, 1); testAllocTimeout(" More than remaining", vpl, 0xA1, 500, 1); testAllocTimeout(" All remaining", vpl, 0x68, 500, 1); testAllocTimeout(" All remaining - 7", vpl, 0x68 - 7, 500, 1); testAllocTimeout(" All remaining - 8", vpl, 0x68 - 8, 500, 1); testAllocTimeout(" 1 byte (none left)", vpl, 1, 500, 1); testAllocTimeout(" 1 byte (none left, 0 timeout)", vpl, 1, 0, 1); sceKernelDeleteVpl(vpl); testAllocTimeout(" NULL", 0, 0x100, 500, 1); testAllocTimeout(" NULL with invalid", 0, 0, 500, 0); testAllocTimeout(" Invalid", 0xDEADBEEF, 0x100, 500, 1); testAllocTimeout(" Deleted", vpl, 0x100, 500, 1); schedf("\n"); testDiff(); u32 attrs[] = {PSP_VPL_ATTR_FIFO, PSP_VPL_ATTR_PRIORITY, PSP_VPL_ATTR_SMALLEST, PSP_VPL_ATTR_HIGHMEM}; int i; for (i = 0; i < sizeof(attrs) / sizeof(attrs[0]); ++i) { schedf("Attr %x:\n", attrs[i]); testAllocThread(" Alloc 0x10 of 0x00/0xE0", attrs[i], 0x20, 0xE0 - 0x08); testAllocThread(" Alloc 0x10 of 0x20/0xE0", attrs[i], 0x20, 0xE0 - 0x08 - (0x20 + 0x08)); testAllocThread(" Alloc 0x10 of 0x40/0xE0", attrs[i], 0x20, 0xE0 - 0x08 - (0x20 + 0x08) * 2); schedf("\n"); } flushschedf(); SceUID deleteThread = CREATE_SIMPLE_THREAD(deleteMeFunc); vpl = sceKernelCreateVpl("vpl", PSP_MEMORY_PARTITION_USER, 0, 0x10000, NULL); sceKernelAllocateVpl(vpl, 0x10000 - 0x20 - 0x08, &data, NULL); sceKernelStartThread(deleteThread, sizeof(SceUID), &vpl); sceKernelDeleteVpl(vpl); flushschedf(); unsigned int timeout; BASIC_SCHED_TEST("Zero", timeout = 500; result = sceKernelAllocateVpl(vpl1, 0, &data, &timeout); );