void checkIo(int doDispatch) { char temp[128]; SceUID fd = sceIoOpen("dispatch.prx", PSP_O_RDONLY, 0777); dispatchCheckpoint("sceIoOpen: %08x", fd >= 0 ? 1 : fd); dispatchCheckpoint("sceIoRead: %08x", sceIoRead(fd, temp, sizeof(temp))); dispatchCheckpoint("sceIoClose: %08x", sceIoClose(fd)); int state; if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } fd = sceIoOpen("dispatch.prx", PSP_O_RDONLY, 0777); dispatchCheckpoint("sceIoOpen: %08x", fd >= 0 ? 1 : fd); dispatchCheckpoint("sceIoRead: %08x", sceIoRead(fd, temp, sizeof(temp))); dispatchCheckpoint("sceIoClose: %08x", sceIoClose(fd)); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } SceInt64 res = -1; int result = -1; fd = sceIoOpenAsync("dispatch.prx", PSP_O_RDONLY, 0777); dispatchCheckpoint("sceIoOpenAsync: %08x", fd >= 0 ? 1 : fd); if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } result = sceIoPollAsync(fd, &res); dispatchCheckpoint("sceIoPollAsync: %08x / %016llx", result, res >= 0 ? 1LL : res); result = sceIoGetAsyncStat(fd, 1, &res); dispatchCheckpoint("sceIoGetAsyncStat: %08x / %016llx", result, res >= 0 ? 1LL : res); result = sceIoGetAsyncStat(fd, 0, &res); dispatchCheckpoint("sceIoGetAsyncStat: %08x / %016llx", result, res >= 0 ? 1LL : res); result = sceIoWaitAsync(fd, &res); dispatchCheckpoint("sceIoWaitAsync: %08x / %016llx", result, res >= 0 ? 1LL : res); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } result = sceIoWaitAsync(fd, &res); dispatchCheckpoint("sceIoWaitAsync: %08x / %016llx", result, res >= 0 ? 1LL : res); if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } dispatchCheckpoint("sceIoRead: %08x", sceIoRead(fd, temp, sizeof(temp))); dispatchCheckpoint("sceIoWrite: %08x", sceIoWrite(1, "Hello.", sizeof("Hello."))); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } dispatchCheckpoint("sceIoCloseAsync: %08x", sceIoCloseAsync(fd)); result = sceIoWaitAsync(fd, &res); dispatchCheckpoint("sceIoWaitAsync: %08x / %016llx", result, res); }
void checkSema(int doDispatch) { SceUID sema = sceKernelCreateSema("sema", 0, 0, 1, NULL); dispatchCheckpoint("sceKernelCreateSema: %08x", sema >= 0 ? 1 : sema); dispatchCheckpoint("sceKernelSignalSema: %08x", sceKernelSignalSema(sema, 1)); dispatchCheckpoint("sceKernelWaitSema: %08x", sceKernelWaitSema(sema, 1, NULL)); dispatchCheckpoint("sceKernelWaitSema too much: %08x", sceKernelWaitSema(sema, 9, NULL)); dispatchCheckpoint("sceKernelDeleteSema: %08x", sceKernelDeleteSema(sema)); sema = sceKernelCreateSema("test", 0, 1, 2, NULL); dispatchCheckpoint("sceKernelCreateSema: %08x", sema >= 0 ? 1 : sema); startLockThreadSema(sema); int state; if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } SceUInt timeout = 300; dispatchCheckpoint("sceKernelWaitSema: %08x", sceKernelWaitSema(sema, 1, &timeout)); dispatchCheckpoint("sceKernelSignalSema: %08x", sceKernelSignalSema(sema, 1)); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } endLockThreadSema(sema); dispatchCheckpoint("sceKernelPollSema: %08x", sceKernelPollSema(sema, 1)); dispatchCheckpoint("sceKernelDeleteSema: %08x", sceKernelDeleteSema(sema)); }
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 checkEventFlag(int doDispatch) { SceUID flag = sceKernelCreateEventFlag("eventflag", 0, 0xFFFFFFFF, NULL); dispatchCheckpoint("sceKernelCreateEventFlag: %08x", flag >= 0 ? 1 : flag); dispatchCheckpoint("sceKernelClearEventFlag: %08x", sceKernelClearEventFlag(flag, 1)); dispatchCheckpoint("sceKernelWaitEventFlag: %08x", sceKernelWaitEventFlag(flag, 1, PSP_EVENT_WAITAND, NULL, NULL)); dispatchCheckpoint("sceKernelWaitEventFlag invalid: %08x", sceKernelWaitEventFlag(flag, 0, 0, NULL, NULL)); dispatchCheckpoint("sceKernelDeleteEventFlag: %08x", sceKernelDeleteEventFlag(flag)); flag = sceKernelCreateEventFlag("test", 0, 0xFFFFFFFF, NULL); dispatchCheckpoint("sceKernelCreateEventFlag: %08x", flag >= 0 ? 1 : flag); startLockThreadEventFlag(flag); int state; if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } SceUInt timeout = 300; dispatchCheckpoint("sceKernelWaitEventFlag: %08x", sceKernelWaitEventFlag(flag, 1, PSP_EVENT_WAITAND, NULL, &timeout)); dispatchCheckpoint("sceKernelClearEventFlag: %08x", sceKernelClearEventFlag(flag, 1)); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } endLockThreadEventFlag(flag); dispatchCheckpoint("sceKernelPollEventFlag: %08x", sceKernelPollEventFlag(flag, 1, PSP_EVENT_WAITAND, NULL)); dispatchCheckpoint("sceKernelDeleteEventFlag: %08x", sceKernelDeleteEventFlag(flag)); }
void checkLwMutex(int doDispatch) { SceLwMutexWorkarea workarea; dispatchCheckpoint("sceKernelCreateLwMutex: %08x", sceKernelCreateLwMutex(&workarea, "lwmutex", 0, 1, NULL)); dispatchCheckpoint("sceKernelUnlockLwMutex: %08x", sceKernelUnlockLwMutex(&workarea, 1)); dispatchCheckpoint("sceKernelLockLwMutex: %08x", sceKernelLockLwMutex(&workarea, 1, NULL)); dispatchCheckpoint("sceKernelLockLwMutex invalid: %08x", sceKernelLockLwMutex(&workarea, -1, NULL)); dispatchCheckpoint("sceKernelDeleteLwMutex: %08x", sceKernelDeleteLwMutex(&workarea)); dispatchCheckpoint("sceKernelCreateLwMutex: %08x", sceKernelCreateLwMutex(&workarea, "lwmutex", 0, 1, NULL)); startLockThreadLwMutex(&workarea); int state; if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } SceUInt timeout = 300; dispatchCheckpoint("sceKernelLockLwMutex: %08x", sceKernelLockLwMutex(&workarea, 1, &timeout)); dispatchCheckpoint("sceKernelUnlockLwMutex: %08x", sceKernelUnlockLwMutex(&workarea, 1)); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } endLockThreadLwMutex(&workarea); dispatchCheckpoint("sceKernelTryLockLwMutex: %08x", sceKernelTryLockLwMutex_600(&workarea, 1)); dispatchCheckpoint("sceKernelDeleteLwMutex: %08x", sceKernelDeleteLwMutex(&workarea)); }
void checkMutex(int doDispatch) { SceUID mutex = sceKernelCreateMutex("mutex", 0, 1, NULL); dispatchCheckpoint("sceKernelCreateMutex: %08x", mutex >= 0 ? 1 : mutex); dispatchCheckpoint("sceKernelUnlockMutex: %08x", sceKernelUnlockMutex(mutex, 1)); dispatchCheckpoint("sceKernelLockMutex: %08x", sceKernelLockMutex(mutex, 1, NULL)); dispatchCheckpoint("sceKernelLockMutex invalid: %08x", sceKernelLockMutex(mutex, -1, NULL)); dispatchCheckpoint("sceKernelDeleteMutex: %08x", sceKernelDeleteMutex(mutex)); mutex = sceKernelCreateMutex("test", 0, 1, NULL); dispatchCheckpoint("sceKernelCreateMutex: %08x", mutex >= 0 ? 1 : mutex); startLockThreadMutex(mutex); int state; if (doDispatch) { ++ignoreResched; state = sceKernelSuspendDispatchThread(); dispatchCheckpoint("sceKernelSuspendDispatchThread: %08x", state); } SceUInt timeout = 300; dispatchCheckpoint("sceKernelLockMutex: %08x", sceKernelLockMutex(mutex, 1, &timeout)); dispatchCheckpoint("sceKernelUnlockMutex: %08x", sceKernelUnlockMutex(mutex, 1)); if (doDispatch) { dispatchCheckpoint("sceKernelResumeDispatchThread: %08x", sceKernelResumeDispatchThread(state)); --ignoreResched; } endLockThreadMutex(mutex); dispatchCheckpoint("sceKernelTryLockMutex: %08x", sceKernelTryLockMutex(mutex, 1)); dispatchCheckpoint("sceKernelDeleteMutex: %08x", sceKernelDeleteMutex(mutex)); }
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 dispatchCheckpoint(const char *format, ...) { int state = sceKernelSuspendDispatchThread(); sceKernelResumeDispatchThread(state); schedf("[%s/%s] ", ignoreResched == 0 ? (didResched ? "r" : "x") : "?", state == 1 ? "y" : "n"); if (ignoreResched == 0) { sceKernelTerminateThread(reschedThread); } va_list args; va_start(args, format); schedfBufferPos += vsprintf(schedfBuffer + schedfBufferPos, format, args); // This is easier to debug in the emulator, but printf() reschedules on the real PSP. //vprintf(format, args); va_end(args); schedf("\n"); didResched = 0; if (ignoreResched == 0) { sceKernelStartThread(reschedThread, 0, NULL); } }
int main(int argc, char *argv[]) { SceCtrlData pad; int oldButtons = 0; #define SECOND 1000000 #define REPEAT_START (1 * SECOND) #define REPEAT_DELAY (SECOND / 5) struct timeval repeatStart; struct timeval repeatDelay; repeatStart.tv_sec = 0; repeatStart.tv_usec = 0; repeatDelay.tv_sec = 0; repeatDelay.tv_usec = 0; pspDebugScreenInit(); pspDebugScreenPrintf("Press Cross to start the Task Scheduler Test\n"); pspDebugScreenPrintf("Press Circle to start the CpuSuspendIntr/CpuResumeIntr Test\n"); pspDebugScreenPrintf("Press Square to start the Task with thread of same priority\n"); pspDebugScreenPrintf("Press Left to start the Task Dispatcher Test\n"); pspDebugScreenPrintf("Press Triangle to Exit\n"); while(!done) { sceCtrlReadBufferPositive(&pad, 1); int buttonDown = (oldButtons ^ pad.Buttons) & pad.Buttons; if (pad.Buttons == oldButtons) { struct timeval now; gettimeofday(&now, NULL); if (repeatStart.tv_sec == 0) { repeatStart.tv_sec = now.tv_sec; repeatStart.tv_usec = now.tv_usec; repeatDelay.tv_sec = 0; repeatDelay.tv_usec = 0; } else { long usec = (now.tv_sec - repeatStart.tv_sec) * SECOND; usec += (now.tv_usec - repeatStart.tv_usec); if (usec >= REPEAT_START) { if (repeatDelay.tv_sec != 0) { usec = (now.tv_sec - repeatDelay.tv_sec) * SECOND; usec += (now.tv_usec - repeatDelay.tv_usec); if (usec >= REPEAT_DELAY) { repeatDelay.tv_sec = 0; } } if (repeatDelay.tv_sec == 0) { buttonDown = pad.Buttons; repeatDelay.tv_sec = now.tv_sec; repeatDelay.tv_usec = now.tv_usec; } } } } else { repeatStart.tv_sec = 0; } if (buttonDown & PSP_CTRL_CROSS) { SceUID lowThid = sceKernelCreateThread("Low Prio Thread", threadLowPrio, 0x70, 0x1000, 0, 0); SceUID mediumThid = sceKernelCreateThread("Medium Prio Thread", threadMediumPrio, 0x30, 0x1000, 0, 0); SceUID highThid = sceKernelCreateThread("High Prio Thread", threadHighPrio, 0x10, 0x1000, 0, 0); SceUID busyThid = sceKernelCreateThread("Busy Thread", threadBusy, 0x30, 0x1000, 0, 0); testDone = 0; highPrioCounter = 0; mediumPrioCounter = 0; lowPrioCounter = 0; sceKernelStartThread(lowThid, 0, 0); sceKernelStartThread(mediumThid, 0, 0); sceKernelStartThread(busyThid, 0, 0); sceKernelStartThread(highThid, 0, 0); int totalDelay = 5000000; sceKernelDelayThread(totalDelay); testDone = 1; sceKernelWaitThreadEnd(busyThid, NULL); sceKernelWaitThreadEnd(mediumThid, NULL); sceKernelWaitThreadEnd(highThid, NULL); sceKernelWaitThreadEnd(lowThid, NULL); pspDebugScreenPrintf("Counters: high=%d (%d us), medium=%d, low=%d\n", highPrioCounter, (totalDelay / highPrioCounter), mediumPrioCounter, lowPrioCounter); } if (buttonDown & PSP_CTRL_CIRCLE) { msg = buffer; strcpy(msg, ""); SceUID sleepingThid = sceKernelCreateThread("Sleeping Thread", sleepingThread, 0x10, 0x1000, 0, 0); sceKernelStartThread(sleepingThid, 0, 0); sceKernelDelayThread(100000); int intr = sceKernelCpuSuspendIntr(); sceKernelWakeupThread(sleepingThid); strcat(msg, "Main Thread with disabled interrupts\n"); sceKernelCpuResumeIntr(intr); strcat(msg, "Main Thread with enabled interrupts\n"); pspDebugScreenPrintf("%s", msg); } if (buttonDown & PSP_CTRL_SQUARE) { msg = buffer; strcpy(msg, ""); // Two threads having the same priority SceUID thread1 = sceKernelCreateThread("Thread 1", threadPrio_1, sceKernelGetThreadCurrentPriority(), 0x1000, 0, 0); SceUID thread2 = sceKernelCreateThread("Thread 2", threadPrio_2, sceKernelGetThreadCurrentPriority(), 0x1000, 0, 0); // Test that thread1 will be scheduled before thread2 sceKernelStartThread(thread1, 0, 0); sceKernelStartThread(thread2, 0, 0); strcat(msg, "1 "); sceKernelDelayThread(10000); strcat(msg, "4"); sceKernelWaitThreadEnd(thread1, NULL); sceKernelWaitThreadEnd(thread2, NULL); pspDebugScreenPrintf("Starting 2 threads at same priority: %s\n", msg); // Now with a different order for create & start strcpy(msg, ""); SceUID thread3 = sceKernelCreateThread("Thread 3", threadPrio_3, sceKernelGetThreadCurrentPriority(), 0x1000, 0, 0); SceUID thread4 = sceKernelCreateThread("Thread 4", threadPrio_4, sceKernelGetThreadCurrentPriority(), 0x1000, 0, 0); // Test that thread4 will be scheduled before thread3 sceKernelStartThread(thread4, 0, 0); sceKernelStartThread(thread3, 0, 0); strcat(msg, "1 "); sceKernelDelayThread(10000); strcat(msg, "4"); sceKernelWaitThreadEnd(thread3, NULL); sceKernelWaitThreadEnd(thread4, NULL); pspDebugScreenPrintf("Starting 2 threads with a different order create/start: %s\n", msg); } if (buttonDown & PSP_CTRL_LEFT) { msg = buffer; strcpy(msg, ""); int state = sceKernelSuspendDispatchThread(); // High priority thread SceUID thread = sceKernelCreateThread("Thread 1", threadHello, 0x10, 0x1000, 0, 0); strcat(msg, "1 "); // sceKernelStartThread resumes the thread dispatcher sceKernelStartThread(thread, 0, 0); strcat(msg, "2 "); sceKernelDelayThread(10000); strcat(msg, "3 "); sceKernelResumeDispatchThread(state); sceKernelWaitThreadEnd(thread, NULL); pspDebugScreenPrintf("Starting high prio thread with a disabled dispatcher (state=0x%X): %s\n", state, msg); msg = buffer; strcpy(msg, ""); state = sceKernelSuspendDispatchThread(); // Low priority thread thread = sceKernelCreateThread("Thread 1", threadHello, 0x70, 0x1000, 0, 0); strcat(msg, "1 "); // sceKernelStartThread resumes the thread dispatcher sceKernelStartThread(thread, 0, 0); strcat(msg, "2 "); sceKernelDelayThread(10000); strcat(msg, "3 "); sceKernelResumeDispatchThread(state); sceKernelWaitThreadEnd(thread, NULL); pspDebugScreenPrintf("Starting low prio thread with a disabled dispatcher (state=0x%X): %s\n", state, msg); } if (buttonDown & PSP_CTRL_TRIANGLE) { done = 1; } oldButtons = pad.Buttons; } sceGuTerm(); sceKernelExitGame(); return 0; }