URL
https://opencores.org/ocsvn/mlite/mlite/trunk
Subversion Repositories mlite
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 166 to Rev 167
- ↔ Reverse comparison
Rev 166 → Rev 167
/trunk/kernel/rtos.c
12,6 → 12,7
* Heaps, Threads, Semaphores, Mutexes, Message Queues, and Timers. |
* This file tries to be hardware independent except for calls to: |
* MemoryRead() and MemoryWrite() for interrupts. |
* Partial support for multiple CPUs using symmetric multiprocessing. |
*--------------------------------------------------------------------*/ |
#include "plasma.h" |
#include "rtos.h" |
21,6 → 22,7
#define SEM_RESERVED_COUNT 2 |
#define HEAP_COUNT 8 |
|
|
/*************** Structures ***************/ |
#ifdef WIN32 |
#define setjmp _setjmp |
60,6 → 62,7
void *info; |
OS_Semaphore_t *semaphorePending; |
int returnCode; |
uint32 spinLocks; |
struct OS_Thread_s *next, *prev; |
struct OS_Thread_s *nextTimeout, *prevTimeout; |
uint32 magic[1]; |
104,12 → 107,12
static OS_Semaphore_t *SemaphoreSleep; |
static OS_Semaphore_t *SemaphoreLock; |
static int ThreadSwapEnabled; |
static int ThreadCurrentActive; |
static int ThreadCurrentActive[OS_CPU_COUNT]; |
static int ThreadNeedReschedule; |
static uint32 ThreadTime; |
static OS_Thread_t *ThreadHead; //Linked list of threads sorted by priority |
static OS_Thread_t *TimeoutHead; //Linked list of threads sorted by timeout |
static OS_Thread_t *ThreadCurrent; |
static OS_Thread_t *ThreadCurrent[OS_CPU_COUNT]; |
static void *NeedToFree; |
static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT]; |
static OS_Timer_t *TimerHead; //Linked list of timers sorted by timeout |
284,6 → 287,7
//Must be called with interrupts disabled |
static void OS_ThreadPriorityRemove(OS_Thread_t **head, OS_Thread_t *thread) |
{ |
uint32 cpuIndex = OS_CpuIndex(); |
//printf("r(%d) ", thread->priority); |
assert(thread->magic[0] == THREAD_MAGIC); //check stack overflow |
if(thread->prev == NULL) |
294,8 → 298,8
thread->next->prev = thread->prev; |
thread->next = NULL; |
thread->prev = NULL; |
if(head == &ThreadHead && ThreadCurrent == thread) |
ThreadCurrentActive = 0; |
if(head == &ThreadHead && ThreadCurrent[cpuIndex] == thread) |
ThreadCurrentActive[cpuIndex] = 0; |
} |
|
|
357,7 → 361,8
//Must be called with interrupts disabled |
static void OS_ThreadReschedule(int RoundRobin) |
{ |
OS_Thread_t *threadNext, *threadPrev; |
OS_Thread_t *threadNext, *threadPrev, *threadCurrent; |
uint32 cpuIndex = OS_CpuIndex(); |
int rc; |
|
if(ThreadSwapEnabled == 0 || InterruptInside) |
367,32 → 372,34
} |
|
//Determine which thread should run |
threadNext = ThreadCurrent; |
threadCurrent = ThreadCurrent[cpuIndex]; |
threadNext = threadCurrent; |
assert(ThreadHead); |
if(ThreadCurrentActive == 0 || ThreadCurrent == NULL) |
if(ThreadCurrentActive[cpuIndex] == 0 || threadCurrent == NULL) |
threadNext = ThreadHead; |
else if(ThreadCurrent->priority < ThreadHead->priority) |
else if(threadCurrent->priority < ThreadHead->priority) |
threadNext = ThreadHead; |
else if(RoundRobin) |
{ |
if(ThreadCurrent->next && |
ThreadCurrent->next->priority == ThreadHead->priority) |
threadNext = ThreadCurrent->next; |
if(threadCurrent->next && |
threadCurrent->next->priority == ThreadHead->priority) |
threadNext = threadCurrent->next; |
else |
threadNext = ThreadHead; |
} |
|
if(threadNext != ThreadCurrent) |
if(threadNext != threadCurrent) |
{ |
//Swap threads |
threadPrev = ThreadCurrent; |
ThreadCurrent = threadNext; |
assert(ThreadCurrent); |
threadPrev = threadCurrent; |
ThreadCurrent[cpuIndex] = threadNext; |
assert(threadNext); |
if(threadPrev) |
{ |
assert(threadPrev->magic[0] == THREAD_MAGIC); //check stack overflow |
threadPrev->spinLocks = OS_SpinLockGet(); |
//printf("OS_ThreadRescheduleSave(%s)\n", threadPrev->name); |
rc = setjmp(threadPrev->env); //ANSI C call to save registers |
rc = setjmp(threadPrev->env); //ANSI C call to save registers |
if(rc) |
{ |
//Returned from longjmp() |
399,9 → 406,12
return; |
} |
} |
ThreadCurrentActive = 1; |
//printf("OS_ThreadRescheduleRestore(%s)\n", ThreadCurrent->name); |
longjmp(ThreadCurrent->env, 1); //ANSI C call to restore registers |
cpuIndex = OS_CpuIndex(); //removed warning |
threadNext = ThreadCurrent[cpuIndex]; //removed warning |
ThreadCurrentActive[cpuIndex] = 1; |
//printf("OS_ThreadRescheduleRestore(%s)\n", threadNext->name); |
OS_SpinLockSet(threadNext->spinLocks); |
longjmp(threadNext->env, 1); //ANSI C call to restore registers |
} |
} |
|
409,10 → 419,11
/******************************************/ |
static void OS_ThreadInit(void *Arg) |
{ |
uint32 cpuIndex = OS_CpuIndex(); |
(void)Arg; |
|
OS_AsmInterruptEnable(1); |
ThreadCurrent->funcPtr(ThreadCurrent->arg); |
ThreadCurrent[cpuIndex]->funcPtr(ThreadCurrent[cpuIndex]->arg); |
OS_ThreadExit(); |
} |
|
461,6 → 472,7
thread->info = NULL; |
thread->semaphorePending = NULL; |
thread->returnCode = 0; |
thread->spinLocks = 1; |
thread->next = NULL; |
thread->prev = NULL; |
thread->nextTimeout = NULL; |
483,7 → 495,7
/******************************************/ |
void OS_ThreadExit(void) |
{ |
uint32 state; |
uint32 state, cpuIndex = OS_CpuIndex(); |
OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
if(NeedToFree) |
OS_HeapFree(NeedToFree); |
491,8 → 503,8
OS_SemaphorePost(SemaphoreLock); |
|
state = OS_CriticalBegin(); |
OS_ThreadPriorityRemove(&ThreadHead, ThreadCurrent); |
NeedToFree = ThreadCurrent; |
OS_ThreadPriorityRemove(&ThreadHead, ThreadCurrent[cpuIndex]); |
NeedToFree = ThreadCurrent[cpuIndex]; |
OS_ThreadReschedule(0); |
assert(ThreadHead == NULL); |
OS_CriticalEnd(state); |
502,7 → 514,7
/******************************************/ |
OS_Thread_t *OS_ThreadSelf(void) |
{ |
return ThreadCurrent; |
return ThreadCurrent[OS_CpuIndex()]; |
} |
|
|
617,7 → 629,7
/******************************************/ |
int OS_SemaphorePend(OS_Semaphore_t *Semaphore, int Ticks) |
{ |
uint32 state; |
uint32 state, cpuIndex; |
OS_Thread_t *thread; |
int returnCode=0; |
|
626,7 → 638,8
state = OS_CriticalBegin(); |
if(--Semaphore->count < 0) |
{ |
assert(ThreadCurrent); |
cpuIndex = OS_CpuIndex(); |
assert(ThreadCurrent[cpuIndex]); |
if(Ticks == 0) |
{ |
++Semaphore->count; |
633,7 → 646,7
OS_CriticalEnd(state); |
return -1; |
} |
thread = ThreadCurrent; |
thread = ThreadCurrent[cpuIndex]; |
thread->semaphorePending = Semaphore; |
thread->ticksTimeout = Ticks + OS_ThreadTime(); |
OS_ThreadPriorityRemove(&ThreadHead, thread); |
640,7 → 653,7
OS_ThreadPriorityInsert(&Semaphore->threadHead, thread); |
if(Ticks != OS_WAIT_FOREVER) |
OS_ThreadTimeoutInsert(thread); |
ThreadCurrentActive = 0; |
ThreadCurrentActive[cpuIndex] = 0; |
assert(ThreadHead); |
OS_ThreadReschedule(0); |
returnCode = thread->returnCode; |
917,6 → 930,7
int diff, check=0; |
|
assert(Timer); |
assert(InterruptInside == 0); |
Ticks += OS_ThreadTime(); |
if(Timer->active) |
OS_TimerStop(Timer); |
954,6 → 968,7
void OS_TimerStop(OS_Timer_t *Timer) |
{ |
assert(Timer); |
assert(InterruptInside == 0); |
OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
if(Timer->active) |
{ |
974,6 → 989,7
void OS_InterruptServiceRoutine(uint32 Status) |
{ |
int i; |
uint32 state; |
|
//MemoryWrite(GPIO0_OUT, Status); //Change LEDs |
InterruptInside = 1; |
993,8 → 1009,10
InterruptInside = 0; |
//MemoryWrite(GPIO0_OUT, 0); |
|
state = OS_SpinLock(); |
if(ThreadNeedReschedule) |
OS_ThreadReschedule(ThreadNeedReschedule & 1); |
OS_SpinUnlock(state); |
} |
|
|
1086,13 → 1104,15
//Plasma hardware dependent |
void OS_ThreadTick2(void *Arg) |
{ |
uint32 status, mask; |
uint32 status, mask, state; |
|
state = OS_SpinLock(); |
status = MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT); |
mask = MemoryRead(IRQ_MASK) | IRQ_COUNTER18 | IRQ_COUNTER18_NOT; |
mask &= ~status; |
MemoryWrite(IRQ_MASK, mask); |
OS_ThreadTick(Arg); |
OS_SpinUnlock(state); |
} |
|
|
1124,6 → 1144,7
void OS_Start(void) |
{ |
ThreadSwapEnabled = 1; |
(void)OS_SpinLock(); |
OS_ThreadReschedule(1); |
} |
|
1135,6 → 1156,77
} |
|
|
#if OS_CPU_COUNT > 1 |
static uint8 SpinLockArray[OS_CPU_COUNT]; |
/******************************************/ |
uint32 OS_CpuIndex(void) |
{ |
return 0; //0 to OS_CPU_COUNT-1 |
} |
|
|
/******************************************/ |
//Symmetric Multiprocessing Spin Lock Mutex |
uint32 OS_SpinLock(void) |
{ |
uint32 state, cpu, i, j, ok; |
|
cpu = OS_CpuIndex(); |
state = OS_AsmInterruptEnable(0); |
do |
{ |
ok = 1; |
if(++SpinLockArray[cpu] == 1) |
{ |
for(i = 0; i < OS_CPU_COUNT; ++i) |
{ |
if(i != cpu && SpinLockArray[i]) |
ok = 0; |
} |
if(ok == 0) |
{ |
SpinLockArray[cpu] = 0; |
for(j = 0; j < 100*cpu; ++j) //wait a bit |
++i; |
} |
} |
} while(ok == 0); |
return state; |
} |
|
|
/******************************************/ |
void OS_SpinUnlock(uint32 state) |
{ |
uint32 cpu; |
cpu = OS_CpuIndex(); |
if(--SpinLockArray[cpu] == 0) |
OS_AsmInterruptEnable(state); |
} |
|
|
/******************************************/ |
//Must be called with interrupts disabled and spin locked |
uint32 OS_SpinLockGet(void) |
{ |
uint32 cpu, count; |
cpu = OS_CpuIndex(); |
count = SpinLockArray[cpu]; |
return count; |
} |
|
|
/******************************************/ |
//Must be called with interrupts disabled and spin locked |
void OS_SpinLockSet(uint32 count) |
{ |
uint32 cpu; |
cpu = OS_CpuIndex(); |
SpinLockArray[cpu] = (uint8)count; |
} |
#endif |
|
|
/************** WIN32 Support *************/ |
#ifdef WIN32 |
//Support RTOS inside Windows |