Integrate MultiFeOS into the kernel

This commit is contained in:
fincs 2013-08-10 20:24:29 +02:00
parent a53ba81701
commit f52d938521
20 changed files with 266 additions and 282 deletions

1
.gitignore vendored
View File

@ -31,7 +31,6 @@ build/
!/sdk/userlib/README.txt !/sdk/userlib/README.txt
!/sdk/userlib/feoswifi/ !/sdk/userlib/feoswifi/
!/sdk/userlib/feos3d/ !/sdk/userlib/feos3d/
!/sdk/userlib/multifeos/
!/sdk/userlib/libfar/ !/sdk/userlib/libfar/
!/sdk/userlib/libitcm/ !/sdk/userlib/libitcm/
!/sdk/userlib/md5/ !/sdk/userlib/md5/

View File

@ -285,6 +285,14 @@ __isEmulator: @ Only to be called once!
.Lmov_r0_1: .Lmov_r0_1:
mov r0, #1 mov r0, #1
.align 2
.global __enterThread
.type __enterThread, %function
__enterThread: @ r0 - param, r1 - entrypoint, r2 - stack pointer
mov sp, r2
ldr lr, =ThrExit
bx r1
.macro swiimp name num .macro swiimp name num
.align 2 .align 2
.global \name .global \name

View File

@ -159,13 +159,12 @@ BEGIN_TABLE(FEOSDSHW)
ADD_FUNC_(DSLoadARM7), ADD_FUNC_(DSLoadARM7),
ADD_FUNC_(DSModeShim), ADD_FUNC_(DSModeShim),
ADD_FUNC_(DSProcessIRQs), ADD_FUNC_(DSProcessIRQs),
ADD_FUNC_(DSSetIRQWaitFunc),
ADD_FUNC_(DSSetSuspendMode), ADD_FUNC_(DSSetSuspendMode),
ADD_FUNC_(DSTimerTick), ADD_FUNC_(DSTimerTick),
ADD_FUNC_(DSTimerWrite), ADD_FUNC_(DSTimerWrite),
ADD_FUNC_(DSVideoReset), ADD_FUNC_(DSVideoReset),
ADD_FUNC_(DSWaitForIRQ), ADD_FUNC_(DSWaitForIRQ),
ADD_ALIAS(DSWaitForNextIRQ, DSWaitForNextIRQRaw), ADD_FUNC_(DSWaitForNextIRQ),
ADD_FUNC_(bgClearControlBits), ADD_FUNC_(bgClearControlBits),
ADD_FUNC_(bgExtPaletteDisable), ADD_FUNC_(bgExtPaletteDisable),
ADD_FUNC_(bgExtPaletteDisableSub), ADD_FUNC_(bgExtPaletteDisableSub),

View File

@ -64,8 +64,6 @@ static inline bool AddressCheckMainRAM(const void* addr)
#define E_INVALIDARG (-11) #define E_INVALIDARG (-11)
#define E_APPKILLED (-12) #define E_APPKILLED (-12)
typedef void (*irqWaitFunc_t)(word_t);
void DSRunFifoQueue(); void DSRunFifoQueue();
void DSFifoSetDatamsgHandler(int channel, FifoDatamsgHandlerFunc handler, void* userdata); void DSFifoSetDatamsgHandler(int channel, FifoDatamsgHandlerFunc handler, void* userdata);
void DSFifoSetValue32Handler(int channel, FifoValue32HandlerFunc handler, void* userdata); void DSFifoSetValue32Handler(int channel, FifoValue32HandlerFunc handler, void* userdata);
@ -76,6 +74,7 @@ word_t DSProcessIRQs();
void DSWaitForIRQ(word_t mask); void DSWaitForIRQ(word_t mask);
void DSWaitForIRQRaw(word_t mask); void DSWaitForIRQRaw(word_t mask);
word_t DSWaitForNextIRQRaw(); word_t DSWaitForNextIRQRaw();
word_t DSWaitForNextIRQ();
static inline void DSWaitForVBlank() static inline void DSWaitForVBlank()
{ {
@ -87,9 +86,6 @@ static inline void DSWaitForVBlankRaw()
DSWaitForIRQRaw(IRQ_VBLANK); DSWaitForIRQRaw(IRQ_VBLANK);
} }
#define GET_IRQFUNC ((irqWaitFunc_t)0xFFFFFFFF)
irqWaitFunc_t DSSetIRQWaitFunc(irqWaitFunc_t newFunc);
int __getMode(); int __getMode();
#define isUserMode() (__getMode() == 0x10) #define isUserMode() (__getMode() == 0x10)
@ -130,6 +126,13 @@ typedef struct
} executeStatus_t; } executeStatus_t;
extern executeStatus_t* curExecStatus; extern executeStatus_t* curExecStatus;
typedef executeStatus_t* execstat_t;
execstat_t KeExecStatusCreate();
void KeExecStatusAddRef(execstat_t hSt);
void KeExecStatusRelease(execstat_t hSt);
void KeSetCurExecStatus(execstat_t hSt);
execstat_t KeGetCurExecStatus();
#ifdef LIBFAT_FEOS_MULTICWD #ifdef LIBFAT_FEOS_MULTICWD
char* _getCwdBuf(); char* _getCwdBuf();

View File

@ -375,23 +375,6 @@ void coop_swiIntrWaitCompat(word_t how, word_t what)
} }
#endif #endif
#ifdef ARM9
static irqWaitFunc_t irqWaitFunc = NULL;
void DSWaitForIRQ(word_t mask)
{
irqWaitFunc ? irqWaitFunc(mask) : DSWaitForIRQRaw(mask);
}
irqWaitFunc_t DSSetIRQWaitFunc(irqWaitFunc_t newFunc)
{
irqWaitFunc_t oldFunc = irqWaitFunc;
if (newFunc != GET_IRQFUNC)
irqWaitFunc = newFunc;
return oldFunc;
}
#endif
word_t DSWaitForNextIRQRaw() word_t DSWaitForNextIRQRaw()
{ {
word_t flags = 0; word_t flags = 0;

View File

@ -1,6 +1,7 @@
#include "feos.h" #include "feos.h"
#include "loader.h" #include "loader.h"
#include "feosfifo.h" #include "feosfifo.h"
#include "thread.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -38,14 +39,6 @@ void KeSetExcptHandler(void*);
// Execution status functions // Execution status functions
typedef void* execstat_t;
execstat_t KeExecStatusCreate();
void KeExecStatusAddRef(execstat_t hSt);
void KeExecStatusRelease(execstat_t hSt);
void KeSetCurExecStatus(execstat_t hSt);
execstat_t KeGetCurExecStatus();
typedef int (* systemfunc_t)(const char* command); typedef int (* systemfunc_t)(const char* command);
systemfunc_t __system; systemfunc_t __system;
@ -404,10 +397,6 @@ BEGIN_TABLE(FEOSKRNL)
ADD_FUNC_(KeDiv3232), ADD_FUNC_(KeDiv3232),
ADD_FUNC_(KeDiv6432), ADD_FUNC_(KeDiv6432),
ADD_FUNC_(KeDiv6464), ADD_FUNC_(KeDiv6464),
ADD_FUNC_(KeExecStatusAddRef),
ADD_FUNC_(KeExecStatusCreate),
ADD_FUNC_(KeExecStatusRelease),
ADD_FUNC_(KeGetCurExecStatus),
ADD_FUNC_(KeGetDiskStats), ADD_FUNC_(KeGetDiskStats),
ADD_ALIAS(KeGetErrnoPtr, __errno), ADD_ALIAS(KeGetErrnoPtr, __errno),
ADD_FUNC_(KeGetMemStats), ADD_FUNC_(KeGetMemStats),
@ -417,7 +406,6 @@ BEGIN_TABLE(FEOSKRNL)
ADD_FUNC_(KeMod3232), ADD_FUNC_(KeMod3232),
ADD_FUNC_(KeMod6432), ADD_FUNC_(KeMod6432),
ADD_FUNC_(KeMod6464), ADD_FUNC_(KeMod6464),
ADD_FUNC_(KeSetCurExecStatus),
ADD_FUNC_(KeSetExcptHandler), ADD_FUNC_(KeSetExcptHandler),
ADD_FUNC_(KeSqrt32), ADD_FUNC_(KeSqrt32),
ADD_FUNC_(KeSqrt64), ADD_FUNC_(KeSqrt64),
@ -432,11 +420,24 @@ BEGIN_TABLE(FEOSKRNL)
ADD_FUNC_(LdrLoadModule), ADD_FUNC_(LdrLoadModule),
ADD_FUNC_(LdrLockModule), ADD_FUNC_(LdrLockModule),
ADD_FUNC_(LdrResGetSize), ADD_FUNC_(LdrResGetSize),
ADD_FUNC_(LdrResolveAddr),
ADD_FUNC_(LdrResRead), ADD_FUNC_(LdrResRead),
ADD_FUNC_(LdrResSeek), ADD_FUNC_(LdrResSeek),
ADD_FUNC_(LdrResTell), ADD_FUNC_(LdrResTell),
ADD_FUNC_(LdrResolveAddr),
ADD_FUNC_(LdrUnlockModule), ADD_FUNC_(LdrUnlockModule),
ADD_FUNC_(PsCreateFromArgv),
ADD_FUNC_(PsCreateFromCmdLine),
ADD_FUNC_(ThrCreate),
ADD_FUNC_(ThrDetach),
ADD_FUNC_(ThrGetSelf),
ADD_FUNC_(ThrExit),
ADD_FUNC_(ThrFree),
ADD_FUNC_(ThrGetExitCode),
ADD_FUNC_(ThrIsActive),
ADD_FUNC_(ThrJoin),
ADD_FUNC_(ThrRunInContext),
ADD_FUNC_(ThrSetPriority),
ADD_FUNC_(ThrYield),
ADD_FUNC_(__aeabi_idiv), ADD_FUNC_(__aeabi_idiv),
ADD_FUNC_(__aeabi_idivmod), ADD_FUNC_(__aeabi_idivmod),
ADD_FUNC_(__aeabi_ldivmod), ADD_FUNC_(__aeabi_ldivmod),
@ -605,14 +606,14 @@ execstat_t KeExecStatusCreate()
void KeExecStatusAddRef(execstat_t hSt) void KeExecStatusAddRef(execstat_t hSt)
{ {
if (hSt == (execstat_t) &defaultExecStatus) return; if (hSt == &defaultExecStatus) return;
((executeStatus_t*)hSt)->refcount ++; hSt->refcount ++;
} }
void KeExecStatusRelease(execstat_t hSt) void KeExecStatusRelease(execstat_t hSt)
{ {
if (hSt == (execstat_t) &defaultExecStatus) return; if (hSt == &defaultExecStatus) return;
word_t r = --((executeStatus_t*)hSt)->refcount; word_t r = --hSt->refcount;
if (r == 0) if (r == 0)
free(hSt); free(hSt);
} }
@ -622,7 +623,7 @@ void KeSetCurExecStatus(execstat_t hSt)
#ifdef LIBFAT_FEOS_MULTICWD #ifdef LIBFAT_FEOS_MULTICWD
curExecStatus->cwdCluster = g_fatCwdCluster; curExecStatus->cwdCluster = g_fatCwdCluster;
#endif #endif
curExecStatus = (executeStatus_t*) hSt; curExecStatus = hSt;
#ifdef LIBFAT_FEOS_MULTICWD #ifdef LIBFAT_FEOS_MULTICWD
g_fatCwdCluster = curExecStatus->cwdCluster; g_fatCwdCluster = curExecStatus->cwdCluster;
_setCwdBuf(curExecStatus->cwdBuffer); _setCwdBuf(curExecStatus->cwdBuffer);
@ -631,7 +632,7 @@ void KeSetCurExecStatus(execstat_t hSt)
execstat_t KeGetCurExecStatus() execstat_t KeGetCurExecStatus()
{ {
return (execstat_t) curExecStatus; return curExecStatus;
} }
#define LdrCurModule curExecStatus->curModule #define LdrCurModule curExecStatus->curModule

View File

@ -527,6 +527,10 @@ void* LdrFindInTbl(const fxe_inmem_exports* exphdr, const char* name)
return exphdr->table[mid].addr; return exphdr->table[mid].addr;
} }
#ifdef DEBUG
iprintf("{DBG} Cannot resolve %s\n", name);
#endif
return NULL; return NULL;
} }

View File

@ -1,4 +1,5 @@
#include "feos.h" #include "feos.h"
#include "thread.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
@ -378,6 +379,7 @@ int main()
#ifdef LIBFAT_FEOS_MULTICWD #ifdef LIBFAT_FEOS_MULTICWD
g_fatCwdClusterPtr = (vu32*) _FAT_getCwdClusterPtr("/"); g_fatCwdClusterPtr = (vu32*) _FAT_getCwdClusterPtr("/");
KeInitDefaultExecStatus(); KeInitDefaultExecStatus();
ThrInit();
#endif #endif
InstallThunks(); InstallThunks();
#ifdef LIBFAT_FEOS_MULTICWD #ifdef LIBFAT_FEOS_MULTICWD

View File

@ -1,20 +1,4 @@
#include <multifeos.h> #include "thread.h"
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
enum { THREAD_EXIT = BIT(0), THREAD_IRQWAIT = BIT(1), THREAD_EXECBITS = 3, THREAD_HIGHPRIO = BIT(2), THREAD_DETACHED = BIT(3) };
typedef struct tag_threadSt
{
jmp_buf ctx;
word_t* stack;
struct tag_threadSt* prev;
struct tag_threadSt* next;
execstat_t execStat;
word_t flags;
union { int rc; word_t irqMask; };
} threadSt;
threadSt _firstThread; threadSt _firstThread;
@ -25,22 +9,18 @@ int threadsFinished = 0;
#define inactiveThreadCount() (threadsWaiting + threadsFinished) #define inactiveThreadCount() (threadsWaiting + threadsFinished)
void __attribute__((noreturn)) __newThread(void* param, threadEP_t entryPoint, word_t* stackPtr); void __attribute__((noreturn)) __enterThread(void* param, threadEP_t entryPoint, word_t* stackPtr);
static irqWaitFunc_t oldIrqWaitFunc;
static void _irqWaitYield(word_t mask);
static threadSt* _irqWaitCheck(); static threadSt* _irqWaitCheck();
FEOSINIT void initFirstThread() void ThrInit()
{ {
curThread->execStat = FeOS_GetCurExecStatus(); curThread->execStat = KeGetCurExecStatus();
curThread->prev = curThread; curThread->prev = curThread;
curThread->next = curThread; curThread->next = curThread;
oldIrqWaitFunc = FeOS_SetIRQWaitFunc(_irqWaitYield);
FeOS_StayResident();
} }
thread_t FeOS_CreateThread(word_t stackSize, threadEP_t entryPoint, void* param) thread_t ThrCreate(word_t stackSize, threadEP_t entryPoint, void* param)
{ {
// 32-bit align the stack size // 32-bit align the stack size
stackSize += 3; stackSize += 3;
@ -51,8 +31,8 @@ thread_t FeOS_CreateThread(word_t stackSize, threadEP_t entryPoint, void* param)
threadSt* t = (threadSt*) (mem + stackSize); threadSt* t = (threadSt*) (mem + stackSize);
t->stack = (word_t*) mem; t->stack = (word_t*) mem;
t->execStat = FeOS_GetCurExecStatus(); t->execStat = KeGetCurExecStatus();
FeOS_ExecStatusAddRef(t->execStat); KeExecStatusAddRef(t->execStat);
t->flags = curThread->flags & THREAD_HIGHPRIO; t->flags = curThread->flags & THREAD_HIGHPRIO;
threadSt* insPoint; threadSt* insPoint;
@ -75,20 +55,20 @@ thread_t FeOS_CreateThread(word_t stackSize, threadEP_t entryPoint, void* param)
nThreads ++; nThreads ++;
if (!setjmp(thisThread->ctx)) if (!setjmp(thisThread->ctx))
__newThread(param, entryPoint, (word_t*) t); __enterThread(param, entryPoint, (word_t*) t);
return (thread_t) t; return t;
} }
void _doYield(threadSt* t) void _doYield(threadSt* t)
{ {
curThread = t; curThread = t;
FeOS_SetCurExecStatus(curThread->execStat); KeSetCurExecStatus(curThread->execStat);
longjmp(curThread->ctx, 1); longjmp(curThread->ctx, 1);
} }
void FeOS_Yield() void ThrYield()
{ {
threadSt* t = curThread; threadSt* t = curThread;
@ -113,7 +93,7 @@ void FeOS_Yield()
while ((t->flags & THREAD_DETACHED) && (t->flags & THREAD_EXIT)) while ((t->flags & THREAD_DETACHED) && (t->flags & THREAD_EXIT))
{ {
threadSt* next = t->next; threadSt* next = t->next;
FeOS_FreeThread(t); ThrFree(t);
t = next; t = next;
} }
} while (t->flags & THREAD_EXECBITS); } while (t->flags & THREAD_EXECBITS);
@ -121,31 +101,30 @@ void FeOS_Yield()
_doYield(t); _doYield(t);
} }
thread_t FeOS_GetCurrentThread() thread_t ThrGetSelf()
{ {
return (thread_t) curThread; return curThread;
} }
void FeOS_ExitThread(int rc) void ThrExit(int rc)
{ {
if (curThread == &_firstThread) return; if (curThread == &_firstThread) return;
curThread->flags |= THREAD_EXIT; curThread->flags |= THREAD_EXIT;
curThread->rc = rc; curThread->rc = rc;
threadsFinished ++; threadsFinished ++;
FeOS_Yield(); ThrYield();
} }
bool FeOS_IsThreadActive(thread_t hThread) bool ThrIsActive(thread_t hThread)
{ {
return (((threadSt*)hThread)->flags & THREAD_EXIT) == 0; return (hThread->flags & THREAD_EXIT) == 0;
} }
void FeOS_FreeThread(thread_t hThread) void ThrFree(thread_t t)
{ {
if (hThread == (thread_t) &_firstThread) return; if (t == &_firstThread) return;
if (hThread == (thread_t) curThread) return; if (t == curThread) return;
threadSt* t = (threadSt*) hThread;
if (t->flags & THREAD_IRQWAIT) if (t->flags & THREAD_IRQWAIT)
threadsWaiting --; threadsWaiting --;
if (t->flags & THREAD_EXIT) if (t->flags & THREAD_EXIT)
@ -153,29 +132,28 @@ void FeOS_FreeThread(thread_t hThread)
t->prev->next = t->next; t->prev->next = t->next;
t->next->prev = t->prev; t->next->prev = t->prev;
free(t->stack); free(t->stack);
FeOS_ExecStatusRelease(t->execStat); KeExecStatusRelease(t->execStat);
nThreads --; nThreads --;
} }
int FeOS_ThreadJoin(thread_t hThread) int ThrJoin(thread_t hThread)
{ {
int rc; int rc;
while (FeOS_IsThreadActive(hThread)) FeOS_Idle(); while (ThrIsActive(hThread)) DSWaitForIRQ(~0);
rc = FeOS_GetThreadRC(hThread); rc = ThrGetExitCode(hThread);
FeOS_FreeThread(hThread); ThrFree(hThread);
return rc; return rc;
} }
void FeOS_SetThreadPrio(thread_t hThread, int prio) void ThrSetPriority(thread_t t, int prio)
{ {
threadSt* t = (threadSt*) hThread;
word_t flag = (prio == PRIORITY_HIGH) ? THREAD_HIGHPRIO : 0; word_t flag = (prio == PRIORITY_HIGH) ? THREAD_HIGHPRIO : 0;
if ((t->flags & flag) == flag) return; if ((t->flags & flag) == flag) return;
t->flags &= ~THREAD_HIGHPRIO; t->flags &= ~THREAD_HIGHPRIO;
t->flags |= flag; t->flags |= flag;
// Can't change position of the first thread // Can't change position of the first thread
if (hThread == (thread_t) &_firstThread) return; if (t == &_firstThread) return;
// Pull the thread out of the list // Pull the thread out of the list
t->prev->next = t->next; t->prev->next = t->next;
@ -189,9 +167,9 @@ void FeOS_SetThreadPrio(thread_t hThread, int prio)
t->prev->next = t; t->prev->next = t;
} }
int FeOS_GetThreadRC(thread_t hThread) int ThrGetExitCode(thread_t hThread)
{ {
return ((threadSt*)hThread)->rc; return hThread->rc;
} }
typedef struct typedef struct
@ -203,16 +181,17 @@ typedef struct
static int _execAsyncEP(void* _param) static int _execAsyncEP(void* _param)
{ {
execParams* params = (void*) _param; execParams* params = (void*) _param;
FeOS_ExecStatusRelease(curThread->execStat); execstat_t es = KeExecStatusCreate();
curThread->execStat = FeOS_ExecStatusCreate(); if (!es) return -4;
if (!curThread->execStat) return -1; KeExecStatusRelease(curThread->execStat);
FeOS_SetCurExecStatus(curThread->execStat); curThread->execStat = es;
int rc = FeOS_Execute(params->argc, params->argv); KeSetCurExecStatus(curThread->execStat);
int rc = LdrExecuteArgv(params->argc, params->argv);
free(_param); free(_param);
return rc; return rc;
} }
thread_t FeOS_CreateProcess(int argc, const char* argv[]) thread_t PsCreateFromArgv(int argc, const char* argv[])
{ {
execParams* params = (execParams*) malloc(sizeof(execParams)); execParams* params = (execParams*) malloc(sizeof(execParams));
if (!params) return NULL; if (!params) return NULL;
@ -220,7 +199,7 @@ thread_t FeOS_CreateProcess(int argc, const char* argv[])
params->argc = argc; params->argc = argc;
params->argv = argv; params->argv = argv;
thread_t t = FeOS_CreateThread(16*1024, _execAsyncEP, params); thread_t t = ThrCreate(16*1024, _execAsyncEP, params);
if (!t) if (!t)
{ {
free(params); free(params);
@ -232,52 +211,54 @@ thread_t FeOS_CreateProcess(int argc, const char* argv[])
static int _runAsyncEP(void* _param) static int _runAsyncEP(void* _param)
{ {
FeOS_ExecStatusRelease(curThread->execStat); execstat_t es = KeExecStatusCreate();
curThread->execStat = FeOS_ExecStatusCreate(); if (!es) return -4;
KeExecStatusRelease(curThread->execStat);
curThread->execStat = es;
if (!curThread->execStat) return -1; if (!curThread->execStat) return -1;
FeOS_SetCurExecStatus(curThread->execStat); KeSetCurExecStatus(curThread->execStat);
return system((const char*)_param); return system((const char*)_param);
} }
thread_t FeOS_RunAsync(const char* command) thread_t PsCreateFromCmdLine(const char* command)
{ {
return FeOS_CreateThread(16*1024, _runAsyncEP, (void*)command); return ThrCreate(16*1024, _runAsyncEP, (void*)command);
} }
void FeOS_DetachThread(thread_t hThread) void ThrDetach(thread_t t)
{ {
if (hThread == &_firstThread || hThread == curThread) if (t == &_firstThread || t == curThread)
return; return;
threadSt* t = (threadSt*) hThread;
t->flags |= THREAD_DETACHED; t->flags |= THREAD_DETACHED;
} }
int FeOS_RunInContext(thread_t hThread, threadEP_t func, void* param) int ThrRunInContext(thread_t t, threadEP_t func, void* param)
{ {
threadSt* t = (threadSt*) hThread;
execstat_t oldSt = curThread->execStat; execstat_t oldSt = curThread->execStat;
curThread->execStat = t->execStat; curThread->execStat = t->execStat;
FeOS_SetCurExecStatus(curThread->execStat); KeExecStatusAddRef(curThread->execStat);
KeSetCurExecStatus(curThread->execStat);
int rc = func(param); int rc = func(param);
curThread->execStat = oldSt; curThread->execStat = oldSt;
FeOS_SetCurExecStatus(curThread->execStat); KeSetCurExecStatus(curThread->execStat);
KeExecStatusRelease(curThread->execStat);
return rc; return rc;
} }
void _irqWaitYield(word_t mask) void DSWaitForIRQ(word_t mask)
{ {
threadsWaiting ++; threadsWaiting ++;
curThread->irqMask = mask; curThread->irqMask = mask;
curThread->flags |= THREAD_IRQWAIT; curThread->flags |= THREAD_IRQWAIT;
FeOS_Yield(); ThrYield();
} }
word_t FeOS_NextIRQYield() word_t DSWaitForNextIRQ()
{ {
threadsWaiting ++; threadsWaiting ++;
curThread->irqMask = 0; curThread->irqMask = 0;
curThread->flags |= THREAD_IRQWAIT; curThread->flags |= THREAD_IRQWAIT;
FeOS_Yield(); ThrYield();
return curThread->irqMask; return curThread->irqMask;
} }
@ -299,7 +280,7 @@ threadSt* _irqWaitCheck()
// Get the interrupt mask. If all other threads are inactive (such as waiting for IRQs), // Get the interrupt mask. If all other threads are inactive (such as waiting for IRQs),
// we can then perform the wait for IRQ. // we can then perform the wait for IRQ.
word_t mask = (inactiveThreadCount() == nThreads) ? FeOS_NextIRQ() : FeOS_CheckPendingIRQs(); word_t mask = (inactiveThreadCount() == nThreads) ? DSWaitForNextIRQRaw() : DSProcessIRQs();
if (!mask) // implies inactiveThreadCount() != nThreads if (!mask) // implies inactiveThreadCount() != nThreads
return NULL; return NULL;

39
kernel/source/thread.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include "feos.h"
#include "loader.h"
#define PRIORITY_HIGH 0x7FFFFFFF
#define PRIORITY_NORMAL 0
enum { THREAD_EXIT = BIT(0), THREAD_IRQWAIT = BIT(1), THREAD_EXECBITS = 3, THREAD_HIGHPRIO = BIT(2), THREAD_DETACHED = BIT(3) };
typedef struct tag_threadSt
{
jmp_buf ctx;
word_t* stack;
struct tag_threadSt* prev;
struct tag_threadSt* next;
execstat_t execStat;
word_t flags;
union { int rc; word_t irqMask; };
} threadSt;
typedef threadSt* thread_t;
typedef int (*threadEP_t)(void* param);
void ThrInit();
thread_t ThrCreate(word_t stackSize, threadEP_t entryPoint, void* param);
void ThrYield();
thread_t ThrGetSelf();
void ThrExit(int rc);
bool ThrIsActive(thread_t hThread);
void ThrFree(thread_t hThread);
void ThrSetPriority(thread_t hThread, int prio);
int ThrGetExitCode(thread_t hThread);
int ThrJoin();
void ThrDetach(thread_t hThread);
int ThrRunInContext(thread_t hThread, threadEP_t func, void* param);
thread_t PsCreateFromArgv(int argc, const char* argv[]);
thread_t PsCreateFromCmdLine(const char* command);

View File

@ -42,6 +42,7 @@ extern "C"
\subsection api FeOS API \subsection api FeOS API
- \ref api_base "Core FeOS API" - \ref api_base "Core FeOS API"
- \ref api_thr "FeOS Threading API"
- **FeOS libnds-compatible DS hardware access API** - **FeOS libnds-compatible DS hardware access API**
- \ref api_ds "Basic functions" - \ref api_ds "Basic functions"
- \ref api_math "Math functions" - \ref api_math "Math functions"
@ -49,7 +50,6 @@ extern "C"
- \ref api_dsspr "Sprite functions" - \ref api_dsspr "Sprite functions"
\subsection userlibs System Libraries \subsection userlibs System Libraries
- \ref multifeos.h "MultiFeOS (cooperative multitasking)"
- \ref feoswifi "FeOSWifi (dswifi for FeOS)" - \ref feoswifi "FeOSWifi (dswifi for FeOS)"
- \ref feos3d.h "FeOS3D (libnds videoGL for FeOS)" - \ref feos3d.h "FeOS3D (libnds videoGL for FeOS)"
- \ref far.h "libfar (FeOS ARchives)" - \ref far.h "libfar (FeOS ARchives)"
@ -67,6 +67,7 @@ extern "C"
#include <feosuser.h> #include <feosuser.h>
#include <feosmath.h> #include <feosmath.h>
#include <feosdsapi.h> #include <feosdsapi.h>
#include <feosthr.h>
#include <feosdsspr.h> #include <feosdsspr.h>
#include <feosdsbg.h> #include <feosdsbg.h>
#else #else

View File

@ -401,13 +401,6 @@ static inline void swiWaitForVBlank()
DSWaitForIRQ(IRQ_VBLANK); DSWaitForIRQ(IRQ_VBLANK);
} }
#define DEFAULT_IRQFUNC ((irqWaitFunc_t)0) //!< Internal macro not for public consumption.
#define GET_IRQFUNC ((irqWaitFunc_t)0xFFFFFFFF) //!< Internal macro not for public consumption.
typedef void (*irqWaitFunc_t)(word_t); //!< Internal data type not for public consumption.
//! \brief Internal function not for public consumption.
irqWaitFunc_t DSSetIRQWaitFunc(irqWaitFunc_t newFunc);
//! \brief Writes a value into a timer register. //! \brief Writes a value into a timer register.
void DSTimerWrite(int, word_t); void DSTimerWrite(int, word_t);
//! \brief Reads a timer's counting value. //! \brief Reads a timer's counting value.

79
sdk/include/feosthr.h Normal file
View File

@ -0,0 +1,79 @@
//
// FeOS Standard Library
// feosthr.h
// FeOS Threading API
//
#pragma once
#include <feos.h>
/** @file feosthr.h
* \brief FeOS Threading API
*/
/** @addtogroup api_thr FeOS Threading API
* @{
*/
#define DEFAULT_STACK_SIZE (8*1024) //!< Default thread stack size.
// Ersatz future-proof binary priority system
#define PRIORITY_HIGH 0x7FFFFFFF //!< High priority.
#define PRIORITY_NORMAL 0 //!< Low priority
typedef void* thread_t; //!< Thread handle datatype.
typedef int (*threadEP_t)(void* param); //!< Thread entry point callback datatype.
//! \brief Creates a thread.
thread_t ThrCreate(word_t stackSize, threadEP_t entryPoint, void* param);
//! \brief Yields thread execution. Normally an IRQ wait function should be used instead.
void ThrYield();
//! \brief Gets the currently executing thread.
thread_t ThrGetSelf();
//! \brief Exits the current thread.
void ThrExit(int rc);
//! \brief Determines whether a certain thread has not finished.
bool ThrIsActive(thread_t hThread);
//! \brief Frees/deletes a thread.
void ThrFree(thread_t hThread);
//! \brief Sets the priority of a thread.
void ThrSetPriority(thread_t hThread, int prio);
//! \brief Gets the exit code of a thread.
int ThrGetExitCode(thread_t hThread);
//! \brief Waits for a thread to finish executing. The thread is additionally freed.
int ThrJoin();
//! \brief Makes the thread be automatically free when it exits.
void ThrDetach(thread_t hThread);
//! \brief Runs a piece of code in the context of another thread.
int ThrRunInContext(thread_t hThread, threadEP_t func, void* param);
//! \brief Recommended way to idle.
static inline void ThrIdle()
{
DSWaitForIRQ(~0);
}
//! \brief Creates a process using an argv array.
thread_t PsCreateFromArgv(int argc, const char* argv[]);
//! \brief Creates a process using a command line.
thread_t PsCreateFromCmdLine(const char* command);
// Simple lock API
typedef volatile word_t lock_t; //!< Simple lock datatype
//! \brief Acquires a lock.
//! \param bIrqIdling Determines if IRQ-waiting is to be used as an idling method.
static inline void ThrAcquireLock(lock_t* pLock, bool bIrqIdling)
{
while (*pLock) bIrqIdling ? ThrIdle() : ThrYield();
*pLock = 1;
}
//! \brief Releases a lock.
static inline void ThrReleaseLock(lock_t* pLock)
{
*pLock = 0;
}
/** @} */

View File

@ -70,12 +70,6 @@ void LdrEnumModules(ModuleEnumCallback, void*);
//! \brief Decreases the reference count of the callers' module. //! \brief Decreases the reference count of the callers' module.
#define LdrEndResidency() LdrUnlockModule(LdrGetSelf()) #define LdrEndResidency() LdrUnlockModule(LdrGetSelf())
execstat_t KeExecStatusCreate(); //!< (Low-level) Creates a new execution status object.
void KeExecStatusAddRef(execstat_t); //!< (Low-level) Increases the reference count of an execstat object.
void KeExecStatusRelease(execstat_t); //!< (Low-level) Decreases the reference count of an execstat object.
void KeSetCurExecStatus(execstat_t); //!< (Low-level) Sets the current execution status.
execstat_t KeGetCurExecStatus(); //!< (Low-level) Gets the current execution status.
//! \brief Executes the specified argc and argv. //! \brief Executes the specified argc and argv.
int LdrExecuteArgv(int, const char*[]); int LdrExecuteArgv(int, const char*[]);

31
sdk/include/multifeos.h Normal file
View File

@ -0,0 +1,31 @@
//
// FeOS Standard Library
// multifeos.h
// MultiFeOS compatibility defines
//
#pragma once
#include <feos.h>
#define FeOS_CancelThread ThrFree
#define FeOS_CreateThread ThrCreate
#define FeOS_Yield ThrYield
#define FeOS_GetCurrentThread ThrGetSelf
#define FeOS_ExitThread ThrExit
#define FeOS_IsThreadActive ThrIsActive
#define FeOS_FreeThread ThrFree
#define FeOS_SetThreadPrio ThrSetPriority
#define FeOS_GetThreadRC ThrGetExitCode
#define FeOS_ThreadJoin ThrJoin
#define FeOS_DetachThread ThrDetach
#define FeOS_RunInContext ThrRunInContext
#define FeOS_Idle ThrIdle
#define FeOS_CreateProcess PsCreateFromArgv
#define FeOS_RunAsync PsCreateFromCmdLine
#define FeOS_NextIRQYield DSWaitForNextIRQ
#define FeOS_AcquireLock ThrAcquireLock
#define FeOS_ReleaseLock ThrReleaseLock

View File

@ -13,7 +13,6 @@ DSGetSubOAM \
DSLoadARM7 \ DSLoadARM7 \
DSModeShim \ DSModeShim \
DSProcessIRQs \ DSProcessIRQs \
DSSetIRQWaitFunc \
DSSetSuspendMode \ DSSetSuspendMode \
DSTimerTick \ DSTimerTick \
DSTimerWrite \ DSTimerWrite \

View File

@ -20,10 +20,6 @@ IoSetStdout \
KeDiv3232 \ KeDiv3232 \
KeDiv6432 \ KeDiv6432 \
KeDiv6464 \ KeDiv6464 \
KeExecStatusAddRef \
KeExecStatusCreate \
KeExecStatusRelease \
KeGetCurExecStatus \
KeGetDiskStats \ KeGetDiskStats \
KeGetErrnoPtr \ KeGetErrnoPtr \
KeGetMemStats \ KeGetMemStats \
@ -33,7 +29,6 @@ KeGetTickCount \
KeMod3232 \ KeMod3232 \
KeMod6432 \ KeMod6432 \
KeMod6464 \ KeMod6464 \
KeSetCurExecStatus \
KeSetExcptHandler \ KeSetExcptHandler \
KeSqrt32 \ KeSqrt32 \
KeSqrt64 \ KeSqrt64 \
@ -48,11 +43,24 @@ LdrGetModuleName \
LdrLoadModule \ LdrLoadModule \
LdrLockModule \ LdrLockModule \
LdrResGetSize \ LdrResGetSize \
LdrResolveAddr \
LdrResRead \ LdrResRead \
LdrResSeek \ LdrResSeek \
LdrResTell \ LdrResTell \
LdrResolveAddr \
LdrUnlockModule \ LdrUnlockModule \
PsCreateFromArgv \
PsCreateFromCmdLine \
ThrCreate \
ThrDetach \
ThrGetSelf \
ThrExit \
ThrFree \
ThrGetExitCode \
ThrIsActive \
ThrJoin \
ThrRunInContext \
ThrSetPriority \
ThrYield \
__aeabi_idiv \ __aeabi_idiv \
__aeabi_idivmod \ __aeabi_idivmod \
__aeabi_ldivmod \ __aeabi_ldivmod \

View File

@ -1,37 +0,0 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro")
endif
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
ifeq ($(strip $(FEOSSDK)),)
$(error "Please set FEOSSDK in your environment. export FEOSSDK=<path to>FeOS/sdk")
endif
FEOSMK = $(FEOSSDK)/mk
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
CONF_DEFINES = -DMULTIFEOS_BUILD
include $(FEOSMK)/dynlib.mk
install: all
@cp $(TARGET).fx2 $(FEOSDEST)/data/FeOS/lib/$(TARGET).fx2

View File

@ -1,92 +0,0 @@
//
// MultiFeOS
// multifeos.h
// FeOS user-mode cooperative multithreading library
//
#pragma once
#include <feos.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MULTIFEOS_BUILD
#define MULTIFEOS_API FEOS_EXPORT
#else
#define MULTIFEOS_API
#endif
/*! \file multifeos.h
\brief FeOS user-mode cooperative multithreading library
*/
#define DEFAULT_STACK_SIZE (8*1024) //!< Default thread stack size.
// Ersatz future-proof binary priority system
#define PRIORITY_HIGH 0x7FFFFFFF //!< High priority.
#define PRIORITY_NORMAL 0 //!< Low priority
typedef void* thread_t; //!< Thread handle datatype.
typedef int (*threadEP_t)(void* param); //!< Thread entry point callback datatype.
#define FeOS_CancelThread FeOS_FreeThread //!< Alternative name for FeOS_FreeThread().
//! \brief Creates a thread.
MULTIFEOS_API thread_t FeOS_CreateThread(word_t stackSize, threadEP_t entryPoint, void* param);
//! \brief Yields thread execution. Normally an IRQ wait function should be used instead.
MULTIFEOS_API void FeOS_Yield();
//! \brief Gets the currently executing thread.
MULTIFEOS_API thread_t FeOS_GetCurrentThread();
//! \brief Exits the current thread.
MULTIFEOS_API void FeOS_ExitThread(int rc);
//! \brief Determines whether a certain thread has not finished.
MULTIFEOS_API bool FeOS_IsThreadActive(thread_t hThread);
//! \brief Frees/deletes a thread.
MULTIFEOS_API void FeOS_FreeThread(thread_t hThread);
//! \brief Sets the priority of a thread.
MULTIFEOS_API void FeOS_SetThreadPrio(thread_t hThread, int prio);
//! \brief Gets the exit code of a thread.
MULTIFEOS_API int FeOS_GetThreadRC(thread_t hThread);
//! \brief Waits for a thread to finish executing. The thread is additionally freed.
MULTIFEOS_API int FeOS_ThreadJoin();
//! \brief Asynchronously runs a command.
MULTIFEOS_API thread_t FeOS_CreateProcess(int argc, const char* argv[]);
//! \brief Asynchronously runs a shell command.
MULTIFEOS_API thread_t FeOS_RunAsync(const char* command);
//! \brief Makes the thread be automatically free when it exits.
MULTIFEOS_API void FeOS_DetachThread(thread_t hThread);
//! \brief Runs a piece of code in the context of another thread.
MULTIFEOS_API int FeOS_RunInContext(thread_t hThread, threadEP_t func, void* param);
//! \brief MultiFeOS-safe version of FeOS_NextIRQ().
MULTIFEOS_API word_t FeOS_NextIRQYield();
//! \brief MultiFeOS-safe way of idling.
static inline void FeOS_Idle()
{
FeOS_WaitForIRQ(~0);
}
// Simple lock API
typedef volatile word_t lock_t; //!< Simple lock datatype
//! \brief Acquires a lock.
//! \param bIrqIdling Determines if IRQ-waiting is to be used as an idling method.
static inline void FeOS_AcquireLock(lock_t* pLock, bool bIrqIdling)
{
while (*pLock) (bIrqIdling ? FeOS_Idle : FeOS_Yield)();
*pLock = 1;
}
//! \brief Releases a lock.
static inline void FeOS_ReleaseLock(lock_t* pLock)
{
*pLock = 0;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +0,0 @@
.arch armv5te
.text
.global __newThread
.hidden __newThread
.type __newThread STT_FUNC
.align 2
__newThread: @ r0 - param, r1 - entrypoint, r2 - stack pointer
mov sp, r2
ldr lr, =FeOS_ExitThread
bx r1