Rewrite psp1 libco

Major differences:

1. Use of SceUID casted to void* as cothread_t. This fixes semantics of
   co_active which now cann be called several times with results staying valid
   and removes bunch of malloc and free
2. In co_create immediately suspend new thread to avoid it running
   simultaneoulsy with creating thread
This commit is contained in:
Vladimir Serbinenko 2020-04-27 21:09:54 +02:00
parent 5baa0fc101
commit 1c38a2289a

View File

@ -4,42 +4,38 @@
#include <stdlib.h> #include <stdlib.h>
#include <pspthreadman.h> #include <pspthreadman.h>
/* Since cothread_t is a void pointer it must contain an address. We can't return a reference to a local variable typedef void (*entrypoint_t)(void);
* because it would go out of scope, so we create a static variable instead so we can return a reference to it.
*/
static SceUID active_thread_id = 0;
cothread_t co_active() cothread_t co_active()
{ {
active_thread_id = sceKernelGetThreadId(); return (void *) sceKernelGetThreadId();
return &active_thread_id; }
static int thread_wrap(unsigned int argc, void *argp)
{
entrypoint_t entrypoint = *(entrypoint_t *) argp;
sceKernelSleepThread();
entrypoint();
return 0;
} }
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) cothread_t co_create(unsigned int size, void (*entrypoint)(void))
{ {
/* Similar scenario as with active_thread_id except there will only be one active_thread_id while there could be many SceUID new_thread_id = sceKernelCreateThread("cothread", thread_wrap, 0x12, size, 0, NULL);
* new threads each with their own handle, so we create them on the heap instead and delete them manually when they're sceKernelStartThread(new_thread_id, sizeof (entrypoint), &entrypoint);
* no longer needed in co_delete(). return (void *) new_thread_id;
*/
cothread_t handle = malloc(sizeof(cothread_t));
/* SceKernelThreadEntry has a different signature than entrypoint, but in practice this seems to work */
SceUID new_thread_id = sceKernelCreateThread("cothread", (SceKernelThreadEntry)entrypoint, 0x12, size, 0, NULL);
sceKernelStartThread(new_thread_id, 0, NULL);
*(SceUID *)handle = new_thread_id;
return handle;
} }
void co_delete(cothread_t handle) void co_delete(cothread_t handle)
{ {
sceKernelTerminateDeleteThread(*(SceUID *)handle); SceUID id = (SceUID) handle;
free(handle); sceKernelTerminateDeleteThread(id);
} }
void co_switch(cothread_t handle) void co_switch(cothread_t handle)
{ {
sceKernelWakeupThread(*(SceUID *)handle); SceUID id = (SceUID) handle;
sceKernelWakeupThread(id);
/* Sleep the currently active thread so the new thread can start */ /* Sleep the currently active thread so the new thread can start */
sceKernelSleepThread(); sceKernelSleepThread();
} }