📄 trglib.c
字号:
default: intUnlock(level); return(FALSE); } case TRIGGER_LEQ: switch (pTrg->condType) { case TRIGGER_COND_VAR: retval = ((* ((BOOL *)pTrg->condEx1) <= pTrg->condEx2)); intUnlock(level); return(retval); case TRIGGER_COND_FUNC: retval = (((* ((FUNCPTR)pTrg->condEx1)) () <= pTrg->condEx2)); intUnlock(level); return(retval); default: intUnlock(level); return(FALSE); } case TRIGGER_OR: switch (pTrg->condType) { case TRIGGER_COND_VAR: retval = ((* ((BOOL *)pTrg->condEx1) || pTrg->condEx2)); intUnlock(level); return(retval); case TRIGGER_COND_FUNC: retval = (((* ((FUNCPTR)pTrg->condEx1)) () || pTrg->condEx2)); intUnlock(level); return(retval); default: intUnlock(level); return(FALSE); } case TRIGGER_AND: switch (pTrg->condType) { case TRIGGER_COND_VAR: retval = ((* ((BOOL *)pTrg->condEx1) && pTrg->condEx2)); intUnlock(level); return(retval); case TRIGGER_COND_FUNC: retval = (((* ((FUNCPTR)pTrg->condEx1)) () && pTrg->condEx2)); intUnlock(level); return(retval); default: intUnlock(level); return(FALSE); } default: intUnlock(level); return (FALSE); } intUnlock(level); }/********************************************************************************* trgActionPerform - perform the action associated to a trigger ** INTERNAL* FIXME** RETURNS: * SEE ALSO: FIXME()* NOMANUAL*/void trgActionPerform ( TRIGGER_ID pTrg ) { switch (pTrg->actionType) { case TRG_ACT_WV_START: case TRG_ACT_WV_STOP: case TRG_ACT_FUNC: if ( pTrg->actionFunc != NULL) { (* (pTrg->actionFunc)) (pTrg->actionArg); } } }/********************************************************************************* trgActionDefPerform - perform the trigger action in deferred mode** INTERNAL* FIXME** RETURNS: * SEE ALSO: FIXME()* NOMANUAL*/STATUS trgActionDefPerform () { /* loop, executing actions and pending on the next request */ if ((trgDefSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY)) == NULL) { return (ERROR); } while (TRUE) { semTake (trgDefSem, WAIT_FOREVER); /* pend on event semaphore */ if ( trgWorkQFullNotify ) { logMsg ("Error: Triggering Work Queue overflow! \n", 0,0,0,0,0,0); trgWorkQFullNotify = FALSE; } while (TRUE) { if (trgWorkQ[trgWorkQReader] != NULL) { /* there is an entry here on the queue. Process it */ trgActionPerform ((TRIGGER_ID)trgWorkQ[trgWorkQReader]); trgWorkQ[trgWorkQReader] = NULL; } else { if (trgWorkQReader == trgWorkQWriter) { /* * this entry is marked as unused and the read pointer * has caught up the write pointer. The queue is now * empty */ break; /* exit the inner loop */ } } /* increment the read pointer so it remains valid at all times */ if (trgWorkQReader >= (TRG_MAX_REQUESTS - 1)) trgWorkQReader = 0; else trgWorkQReader++; } } /* never returns */ return (OK); } /********************************************************************************* trgCheck - check if there is a trigger associated to the event** INTERNAL** This routine is the core of the triggering mechanism. It is called whenever* an event point is hit. It determines if a trigger exists for this event and* performs the action associated to the trigger. In order to verify a trigger* has been set for the event point, the routine performs the following steps:* - selects the trigger list the event belongs to, so not to look for all* triggers. Triggers are divided in different lists, depending on the class* they belong to. Classes are similar but not identical to the Windview ones.* - verifies the trigger is a valid object* - verifies the type of event matches the trigger event id* - verifies the object ID of the event point (if any) matches the one defined* in the trigger (if any)* - check the contect we are in is the same as the one specified in the trigger.* Contexts can be of the following type: ANY, ANY_TASK, TASK, SYSTEM, ANY_ISR.* - if a condition is also defined for the trigger, it checks it is verified.* Conditions, can be a function, a var or a library function. They can use* different operands (==, !=, >, <, ...) and are matched against a value* - if we ever get here, well, we have hit a trigger! At this point 3 things,* not necessarily mutually exclusive can happen:* . disable the current trigger (we want the action performed only once)* . perform an action* . enable a chained trigger (similar to a state machine)** The action can be either a user/system defined routine or a library (such* as WV_START/STOP). Action axecution represent the most complex part of the* triggering mechanism. Event points are often set in critical regions of the* kernel where the number of actions that can be performed is limited. In order* to avoid conflicts and still allow the user full range of action, we have * provided a deferred execution mode. In this way, when an action should be * performed a request is sent to a task. Therefore the action itself will not be* executed in the context where the event happens, but in a safer one. If a user* really needs the action to be performed on the spot, this mode can be switched* off. The way the deferred mode is implemented represent the critical part of* the code, and it is still a work in progress.* The first approach we followed was to use message queues. It logically satisfies* the need we had to send information to a task pending waiting for it.* The implementation of this approach raised a few issues:* - recursion: msgQSend/Receive (directly and indirectly) refer to several event* points. Things get worse if a trigger is set on one of them. First of all,* we are introducing a form of intrusion, since the triggers will be fired on* events generated by the trigger itself. More than that, if triggers are not* disabled, it will go into a loop.* - context switch: msgQSend can generate a context switch, which is not the most* desirable thing.* - queue does not work well with interrupts: if we are in an interrupt we can not* use the WAITFOREVER option. This will generate potential inconsistency in the* queue.* * A second approach was to put a task on the workQueue, using workQAdd, but this will * cause the execution of the action when we are doing windExit.* A solution to this problem would be to add some "harmless" action in the workQueue, * that does not cause context switch, and eventually will wake up the task. Therefore,* the idea of semBGiveDefer. The problem now is to tell the pending task what to do.* This is solved by putting the request into a triggering work queue.* This is the current implementation. The work queue mechanism needs definitely to be* revised. Atthe moment it could cause starvation. The requests are executed from the* top of the list down, but a new request will be put at the top of the list, even if* the list is not empty. This could be solved by using a rotation mechanism, so that * request are alway put at the end of the queue. This part has not been implemented yet.** It requires two arguments and a few optional ones.** RETURNS:* SEE ALSO: FIXME()* NOMANUAL*/void trgCheck ( event_t event, int index, int obj, int arg1, int arg2, int arg3, int arg4, int arg5 ) { TRIGGER_ID pTrg = NULL; int level; int any = 0; pTrg = trgList[index];restart: if (index == TRG_CLASS_3_ON) trgNone = 20; while (pTrg != NULL) { if (OBJ_VERIFY (pTrg, trgClassId) != OK) pTrg = pTrg->next; else if ( pTrg->status != TRG_ENABLE ) pTrg = pTrg->next; else if ((pTrg->eventId != EVENT_ANY_EVENT) && (pTrg->eventId != event) ) pTrg = pTrg->next; else if ((pTrg->objId != NULL) && (((OBJ_ID)obj != NULL) && ((OBJ_ID)obj != pTrg->objId)) ) pTrg = pTrg->next; else { switch ( pTrg->contextType ) { case TRG_CTX_ANY: break; case TRG_CTX_SYSTEM: if (kernelState) break; else goto end; case TRG_CTX_TASK: if ((!kernelState) && (!INT_CONTEXT ()) && ((WIND_TCB *)(pTrg->contextId) == taskIdCurrent) ) break; else goto end; case TRG_CTX_ANY_TASK: if ((!kernelState) && (!INT_CONTEXT ())) break; else goto end; case TRG_CTX_ISR: case TRG_CTX_ANY_ISR: if (INT_CONTEXT ()) break; else goto end; default: goto end; } /* check if it is a conditional trigger and in case * test the condition */ if ((pTrg->conditional == TRIGGER_COND_YES) && (pTrg->condEx1 != NULL) && (trgCondTest(pTrg,obj) == FALSE)) goto end; level = intLock(); /* disable the current trigger, if requested */ if ((pTrg->disable == TRUE) && (trgDisable(pTrg) == ERROR)) { intUnlock(level); goto end; } intUnlock(level); pTrg->hitCnt++; /* perform the action associated with the trigger, if any */ if ( pTrg->actionType != TRG_ACT_NONE ) { if ( pTrg->actionDef == FALSE ) trgActionPerform(pTrg); else /* defer the action */ { /* * This will put a request in the triggering work queue * and release a semaphore so that the task trgActDef * can execute the request once we are out of this * code. We might be in Kernel state and we do not want * to perform action here, if possible. */ level = intLock(); if ( trgWorkQ[trgWorkQWriter] == NULL ) { trgWorkQ[trgWorkQWriter] = pTrg; /* * Increment the writer index. * Ensure that trgWorkQWriter NEVER goes to an invalid * value when wrapping round. This assurance is needed * in the trgActDef task */ if (trgWorkQWriter >= (TRG_MAX_REQUESTS - 1)) trgWorkQWriter = 0; else trgWorkQWriter++; } else { /* If the workQ is full need to stop triggering */ trgWorkQFullNotify = TRUE; trgOff(); intUnlock(level); return ; } #if (CPU_FAMILY == I80X86) portWorkQAdd1((FUNCPTR)semBGiveDefer, (int)trgDefSem);#else workQAdd1((FUNCPTR)semBGiveDefer, (int)trgDefSem);#endif /* CPU_FAMILY == I80X86 */ intUnlock(level); } } /* check if there is any trigger chained to the current * one, and if any, enable it if (OBJ_VERIFY (&(pTrg->chain), trgClassId) == OK) */ if ( pTrg->chain != NULL ) { trgEnable(pTrg->chain); if (!TRG_ACTION_IS_SET) trgOn(); } /* * let's loop for the next one! */end: pTrg = pTrg->next; } } if ((any == 0) && (trgList[TRG_ANY_EVENT_INDEX] != NULL)) { any = 1; pTrg = trgList[TRG_ANY_EVENT_INDEX]; goto restart; } }/* Conditional library fn */int isTaskNew(int taskId, int arg){ REG_SET regs; /* Load the regs of the task being resumed */ taskRegsGet (taskId,®s); /* Compare the current PC with the initial entry point */#if 0logMsg("entry = %p, pc = %p\n",((WIND_TCB *) taskId)->entry,regs.pc,0,0,0,0);#endif if ((FUNCPTR) regs.pc == (FUNCPTR) vxTaskEntry) { /* * Task is at entry point, we can therefore deduce it has * just been created. */ /* now match actual user entry point */ if((int) ((WIND_TCB *) taskId)->entry != 0 && (int) ((WIND_TCB *) taskId)->entry == arg) { /* Suspend the task! */#if 0logMsg ("Suspending task %p\n",taskId);#endif#if 1#if (CPU_FAMILY == I80X86) portWorkQAdd1 ((FUNCPTR)taskSuspend, taskId);#else workQAdd1 ((FUNCPTR)taskSuspend, taskId);#endif /* CPU_FAMILY == I80X86 */#else excJobAdd ((VOIDFUNCPTR)taskSuspend, taskId,0,0,0,0,0);#endif return (TRUE); } else { /* This is not the entry point of interest */ return (FALSE); } } else { /* * Task is been resumed after running on from entry point. */ return (FALSE); }}/********************************************************************************* trgEvent - trigger a user-defined event ** This routine triggers a user event. A trigger must exist and triggering must * have been started with trgOn() or from the triggering GUI to use this routine. * The <evtId> should be in the range 40000-65535. * * RETURNS: N/A** SEE ALSO: dbgLib, e()** INTERNAL**/void trgEvent ( event_t evtId /* event */ ) { trgCheck (evtId, TRG_USER_INDEX, 0, 0, 0, 0, 0, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -