jak-project/game/system/IOP_Kernel.h

194 lines
3.7 KiB
C
Raw Normal View History

#pragma once
2020-08-22 22:30:12 -04:00
#ifndef JAK_IOP_KERNEL_H
#define JAK_IOP_KERNEL_H
#include <atomic>
#include <condition_variable>
#include <mutex>
2020-08-22 22:30:12 -04:00
#include <queue>
#include <string>
#include <thread>
#include <utility>
2020-08-22 22:30:12 -04:00
#include <vector>
2020-08-22 22:30:12 -04:00
#include "common/common_types.h"
#include "common/util/Assert.h"
2022-05-19 16:54:36 -04:00
#include "game/sce/iop.h"
2020-08-22 22:30:12 -04:00
#include "third-party/libco/libco.h"
2020-08-22 22:30:12 -04:00
class IOP_Kernel;
namespace iop {
2020-08-26 01:21:33 -04:00
struct sceSifQueueData;
2020-08-22 22:30:12 -04:00
}
using time_stamp = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
2020-08-22 22:30:12 -04:00
struct SifRpcCommand {
bool started = true;
bool finished = true;
void* buff;
int fno;
int size;
void* copy_back_buff;
int copy_back_size;
};
struct SifRecord {
iop::sceSifQueueData* qd;
SifRpcCommand cmd;
u32 thread_to_wake;
};
struct IopThread {
enum class State {
Run,
Ready,
Wait,
WaitSuspend,
Suspend,
Dormant,
};
enum class Wait {
None,
Semaphore,
Delay,
};
IopThread(std::string n, void (*f)(), s32 ID, u32 priority)
: name(std::move(n)), function(f), priority(priority), thID(ID) {
thread = co_create(0x300000, functionWrapper);
2020-08-22 22:30:12 -04:00
}
~IopThread() { co_delete(thread); }
2020-08-22 22:30:12 -04:00
static void functionWrapper();
2020-08-22 22:30:12 -04:00
std::string name;
void (*function)();
cothread_t thread;
State state = State::Dormant;
Wait waitType = Wait::None;
time_stamp resumeTime = {};
u32 priority = 0;
2020-08-22 22:30:12 -04:00
s32 thID = -1;
};
2020-08-22 22:30:12 -04:00
struct Semaphore {
u32 option;
u32 attr;
s32 count;
s32 maxCount;
s32 initCount;
2020-08-22 22:30:12 -04:00
};
class IOP_Kernel {
2020-08-26 01:21:33 -04:00
public:
2020-08-22 22:30:12 -04:00
IOP_Kernel() {
// this ugly hack
threads.reserve(16);
CreateThread("null-thread", nullptr, 0);
2020-08-22 22:30:12 -04:00
CreateMbx();
kernel_thread = co_active();
2020-08-22 22:30:12 -04:00
}
~IOP_Kernel();
s32 CreateThread(std::string n, void (*f)(), u32 priority);
s32 ExitThread();
2020-08-22 22:30:12 -04:00
void StartThread(s32 id);
void DelayThread(u32 usec);
2020-08-22 22:30:12 -04:00
void SleepThread();
void WakeupThread(s32 id);
time_stamp dispatch();
2020-08-26 01:21:33 -04:00
void set_rpc_queue(iop::sceSifQueueData* qd, u32 thread);
2020-08-22 22:30:12 -04:00
void rpc_loop(iop::sceSifQueueData* qd);
void shutdown();
/*!
* Get current thread ID.
*/
s32 getCurrentThread() {
ASSERT(_currentThread);
return _currentThread->thID;
}
2020-08-22 22:30:12 -04:00
/*!
* Create a message box
*/
s32 CreateMbx() {
s32 id = mbxs.size();
mbxs.emplace_back();
return id;
}
/*!
* Set msg to thing if its there and pop it.
* Returns if it got something.
*/
s32 PollMbx(void** msg, s32 mbx) {
ASSERT(mbx < (s32)mbxs.size());
2020-08-26 01:21:33 -04:00
s32 gotSomething = mbxs[mbx].empty() ? 0 : 1;
if (gotSomething) {
2020-08-22 22:30:12 -04:00
void* thing = mbxs[mbx].front();
if (msg) {
2020-08-22 22:30:12 -04:00
*msg = thing;
}
2020-08-22 22:30:12 -04:00
mbxs[mbx].pop();
}
2022-05-19 16:54:36 -04:00
return gotSomething ? KE_OK : KE_MBOX_NOMSG;
2020-08-22 22:30:12 -04:00
}
/*!
* Push something into a mbx
*/
s32 SendMbx(s32 mbx, void* value) {
ASSERT(mbx < (s32)mbxs.size());
2020-08-22 22:30:12 -04:00
mbxs[mbx].push(value);
return 0;
}
2020-08-26 01:21:33 -04:00
s32 CreateSema() { return 1; }
2020-08-22 22:30:12 -04:00
void read_disc_sectors(u32 sector, u32 sectors, void* buffer);
bool sif_busy(u32 id);
2020-08-26 01:21:33 -04:00
void sif_rpc(s32 rpcChannel,
u32 fno,
bool async,
void* sendBuff,
s32 sendSize,
void* recvBuff,
s32 recvSize);
2020-08-22 22:30:12 -04:00
2020-08-26 01:21:33 -04:00
private:
void runThread(IopThread* thread);
void exitThread();
void updateDelay();
void processWakeups();
IopThread* schedNext();
time_stamp nextWakeup();
cothread_t kernel_thread;
2020-08-22 22:30:12 -04:00
s32 _nextThID = 0;
IopThread* _currentThread = nullptr;
std::vector<IopThread> threads;
2020-08-22 22:30:12 -04:00
std::vector<std::queue<void*>> mbxs;
std::vector<SifRecord> sif_records;
std::vector<Semaphore> semas;
std::queue<int> wakeup_queue;
2020-08-22 22:30:12 -04:00
bool mainThreadSleep = false;
FILE* iso_disc_file = nullptr;
std::mutex sif_mtx, wakeup_mtx;
2020-08-22 22:30:12 -04:00
};
2020-08-26 01:21:33 -04:00
#endif // JAK_IOP_KERNEL_H