📄 serlock.c
字号:
tqi->rb.r13svc = Angel_StackBase + Angel_SVCStackOffset; tqi->rb.r13usr = tqi->stack->stackBase; /* copy the state of the non-Angel interrupt bit to the new task */ tqi->rb.cpsr = USRmode | (cpsr & NotAngelInterruptMask); tqi->rb.r14usr = (unsigned)angel_NextTask; #ifdef R10_IS_SL /* The stack limit is not used in standard Angel: this code is here to * show where and how to set up SL. */ tqi->rb.r10usr = tqi->stack->stackLimit;#endif } cpsr = Angel_DisableInterruptsFromSVC(); switch (state) { case TS_Runnable: /* now we've set up the task, change it's state to runnable. * And insert the item into the run queue. */ tqi->state = TS_Runnable; Task_Enqueue(&angel_TQI_Run, tqi); break; case TS_Blocked: /* now we've set up the task, change it's state to runnable. * And insert the item into the wait queue. */ tqi->state = TS_Blocked; Task_AddTail(&angel_TQI_Wait, tqi); break; default: LogFatalError(LOG_SERLOCK, ("Angel_NewTask: Invalid state %d.\n", state)); }#ifdef DEBUG_TASKS angel_PrintTaskQueueShort("NT-R", &angel_TQI_Run); angel_PrintTaskQueueShort("NT-W", &angel_TQI_Wait); LogInfo(LOG_SERLOCK, ("Angel_NewTask: New task %d returning to %lx.\n", tqi->index, tqi->rb.pc));#endif LogInfo(LOG_SERLOCK, ("Angel_NewTask: func: 0x%08lx, arg %lx, type: %d => ID %d\n", fn, (int)a1, (int)type, tqi->index)); Angel_RestoreInterruptsFromSVC(cpsr); return tqi;}/* * Function: angel_DeleteTask * * Purpose: To remove the task pointed to by oldtask, freeing up * its stack and other resources and removing the TQI * from the queue. * * Arguments: oldtask - a pointer to the TQI for the task to remove * * Return: none. * * Pre-conditions: Serialiser initialised; oldtask should not point to the * idle task, and must point to a valid TQI structure. * * * Post-conditions: * */void angel_DeleteTask(angel_TaskQueueItem *tqi){#ifdef DEBUG_TASKS LogInfo(LOG_SERLOCK, ("DeleteTask: task %d (task stack HWM %d bytes, alloc %d bytes)\n", tqi->index, tqi->stack->stackBase - tqi->stack->HWM, tqi->stack->stackBase - tqi->stack->stackLimit));#endif #if DEBUG Angel_DebugLog(0, tqi, 10);#endif ASSERT((tqi->type != TP_IdleLoop), ("angel_DeleteTask: Cannot delete idle task\n")); ASSERT((tqi == angel_CurrentTask), ("angel_DeleteTask: tqi expected to be current task\n")); ASSERT(((Angel_GetCPSR() & 0xf) != 0), ("angel_DeleteTask: in USR mode\n")); ASSERT(((Angel_GetCPSR() & AngelInterruptMask) == AngelInterruptMask), ("angel_DeleteTask: interrupts must be disabled\n")); /* * SVC tasks have a "stack" value which isn't on the free list, so * don't add it onto the free list. */ if (tqi->type != TP_AngelWantLock) {#ifdef DEBUG_TASKS LogInfo(LOG_SERLOCK, ("DeleteTask: remove stack %p\n", tqi->stack ));#endif Stack_AddTail(&angel_Stack_Free, tqi->stack); }#if DEBUG tqi->stack = 0;#endif /* * remove TQI from run list, add to free list and mark deleted */ DEC_STAT(angel_NumCurrentTasks); tqi->state = TS_Undefined; /* Task_Remove(tqi); current task not in list; atm, we only delete current task */ Task_AddTail(&angel_TQI_Free, tqi); /* * tell SelectNextTask that we haven't got a current task. */ angel_CurrentTask = NULL;}/* * Function: angel_BlockAndSchedule * * Purpose: Remove task from current (run) list, put it on the waiting list * and set currenttask to NULL so Select doesn't enqueue it again on * the run list. Call SelectNextTask to schedule another task. * * Arguments: rb - the register block into which the task context was saved * tqi - the task queue referring to the task being inspected. * * Return: none. * * Pre-conditions: Must be called from the SWi return code in except.s with * currenttask pointing at the application. * * Post-conditions: * */void angel_BlockAndSchedule(angel_RegBlock *rb, angel_TaskQueueItem *tqi){ ASSERT(((Angel_GetCPSR() & 0xf) != 0), ("angel_BlockAndSchedule: in USR mode\n")); ASSERT(((Angel_GetCPSR() & AngelInterruptMask) == AngelInterruptMask), ("angel_BlockAndSchedule: interrupts must be disabled\n")); ASSERT((tqi == angel_CurrentTask), ("angel_BlockAndSchedule: code expects tqi to be current\n"));#ifdef DEBUG_TASKS LogInfo(LOG_SERLOCK, ("angel_BlockAndSchedule: task %d\n", tqi->index ));#endif tqi->state = TS_Blocked; /* copy the register context to the given TQI */ angel_QueueTask(rb, tqi); /* do this if tqi can be something other than current: * if (tqi != angel_CurrentTask) Task_Remove(tqi); */ Task_AddTail(&angel_TQI_Wait, tqi); angel_CurrentTask = NULL; /* jump to scheduler to find a new task */ angel_SelectNextTask();}/* * Function: angel_WaitCore * * Purpose: The core routine for Angel_Wait (see serlasm.s), which * overall deschedules the calling task waiting for an event * of some sort. By the time we get here, we have: * * a. entered SVC mode with interrupts disabled * * b. saved the task context in RB_Yield * * c. saved the wait parameter (the value to wait on) in * the regblock r0 value. * * Description The event value is a bitmask; each bit is significant, but * ----------- the meaning of the bits must be pre-arranged bu the tasks * (although this can happen at run-time if needed). A task * may validaly wait for a number of events by setting more than * one bit in the parameter to wait. If any one of these events * has happened, wait will return immediately with a bitmask * indicating which events out of those requested have happened. * If no events have yet happened, wait causes the task to sleep * until something Signal()s the task. Note that as Signal does * not cause a reschedule, more than one signal may occur before * wait finally returns; again, all the events signalled will be * returned to the waiting task. * * Action The core code must thus check whether the event to be waited * ------ for has already happened (by examining signalsReceived), and * if it has to return, modifying signalsReceived to remove the * events this wait was waiting for. If the event has yet to * happen, the routine records the event in the TQI for this * task and deschedule itself. * * The anomalous case when a task waits for no events results * in Angel_Wait returning a result of 0 immediately. * * Arguments: rb - the register block into which the task context was saved * tqi - the task queue referring to the task being inspected. * * Return: none (returns via StartTask on rb, or via serialiser). * * Pre-conditions: serialiser must be initialised. Only validly called via Angel_Wait * * Post-conditions: (none). * */void angel_WaitCore(angel_RegBlock *rb, angel_TaskQueueItem *tqi){ register int b; ASSERT(((Angel_GetCPSR() & AngelInterruptMask) == AngelInterruptMask), ("angel_WaitCore: interrupts must be disabled\n")); ASSERT(((Angel_GetCPSR() & 0xf) != 0), ("angel_WaitCore: in USR mode\n")); /* if we ask for no events happening, just return 0 to caller */ if (rb->r0 == 0) { LogInfo(LOG_SERLOCK, ("WaitCore: task %d returning: r0 is 0\n", Angel_TaskID() )); angel_StartTask(rb); } /* find out if (at least one of) the events has already happened */ b = rb->r0 & tqi->signalReceived; /* reset the events in received which we have now accepted */ tqi->signalReceived &= ~b; if (b) {#ifdef DEBUG_SIGNALS LogInfo(LOG_SERLOCK, ("WaitCore: task %d returning: signalReceived matched\n", Angel_TaskID()));#endif /* one of the events has happened; return which event in r0 * and return now. */ tqi->signalWaiting = 0; rb->r0 = b; angel_StartTask(rb); } else {#ifdef DEBUG_SIGNALS LogInfo(LOG_SERLOCK, ("WaitCore: task %d waiting for signal %x...\n", Angel_TaskID(), rb->r0));#endif /* no event we are interested in has happened yet. Tell the * scheduler to deschedule us until they do. */ tqi->signalWaiting = rb->r0; /* * reset the value of r0 -- this will return signals accepted. */ rb->r0 = 0; angel_BlockAndSchedule(rb, tqi); }}/* * Function: Angel_Signal * * Purpose: To cause an event to be sent to a task which is now, or will * in the future Wait() for it. In itself, Signal() does nothing * useful. * * Signal takes a task id (a small integer) identifying a current * task and marks that task as having received the passed event * bits (see the description for Angel_Wait). If the task is already * blocked, it is assumed that the task is Wait()ing and, having * subtracted the new signals from the signals the task was waiting * for it (potentially) wakes up that task. * * If the task was running, it is assumed that sometime it will call * wait(), and the signals are just marked in the task signalWaiting * member. * * Task ID's are returned by the call Angel_TaskID(), which returns * a tasks own id. It must use other means to communicate this id * to whatever needs to signal it. * * Arguments: task - the task id (NOT TQI pointer) for the task to signal. * signals - one or more bits set in a word corresponding to events. * * Return: none. * * Pre-conditions: serialiser initialised; task identified by 'task' is a current * task. * * Post-conditions: task state modified. * */int Angel_Signal(unsigned task, unsigned signals){ register int needsched = 0; register int b; Angel_EnterCriticalSection(); if (task > 0 && task < POOLSIZE) { angel_TaskQueueItem *tqi = &angel_TQ_Pool[task]; switch (tqi->state) { case TS_Blocked: /* if current task is already waiting, then signal it directly */#ifdef DEBUG_SIGNALS LogInfo(LOG_SERLOCK, ("Signal: from task %d, waiting task %d; sig %04x " "[sigRec was %04x, sigWait %04x].\n", Angel_TaskID(), task, signals, tqi->signalReceived, tqi->signalWaiting));#endif /* get the intersection of events signalled and waited on */ b = (tqi->signalWaiting & signals); /* set bits in signalReceived which were not waited for */ tqi->signalReceived |= signals & ( ~tqi->signalWaiting); /* clear bits set in signalWaiting which are being accepted */ tqi->signalWaiting &= ~b; /* * poke r0 in task RB so when task resumes the return value * is the signals we have just changed */ tqi->rb.r0 |= b;#ifdef DEBUG_SIGNALS LogInfo(LOG_SERLOCK, ("Signal: R0 |= %04x -> %04x [sigRec %04x, sigWait %04x.]\n", b, tqi->rb.r0, tqi->signalReceived, tqi->signalWaiting));#endif /* if b != 0, we can make the task runnable. */ if (b != 0) { /* remove task from wait list and make task runnable again */ tqi->state = TS_Runnable; Task_Remove(tqi); Task_Enqueue(&angel_TQI_Run, tqi); /* if in interrupt, we need to get into the scheduler before the * ISR returns */ needsched = 1; } break; case TS_Runnable: case TS_Running:#ifdef DEBUG_SIGNALS LogInfo(LOG_SERLOCK, ("Signal: from task %d, running task %d; signal %04x, " "old signalReceived %04x.\n", Angel_TaskID(), task, signals, tqi->signalReceived));#endif /* current task is not waiting for us. Assume that it will * sometime in the future... */ tqi->signalReceived |= signals; break; default: LogError(LOG_SERLOCK, ("Signal: task in strange state %d\n", tqi->state)); } } else LogError(LOG_SERLOCK, ("Signal: invalid task id %d\n", task)); Angel_LeaveCriticalSection(); return needsched;}/* * Function: Angel_DeferredBlockCore * * Purpose: Called to complete the blocking of the application task * when it was deferred because Angel was processing a SWI * on behalf of the application at the time of the original * request. * * Resetting the blocked flag is done by the assembler in * except.s, as it's address has already been loaded. * * Arguments: none. * * Return: none. * * Pre-conditions: Must be called from the SWi return code in except.s with * currenttask pointing at the application. * * Post-conditions: * */void Angel_DeferredBlockCore(void){ ASSERT((angel_CurrentTask->type == TP_Application), ("Angel_DeferredBlockCore: not appl task")); angel_BlockAndSchedule(&Angel_GlobalRegBlock[RB_SWI], angel_CurrentTask);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -