246 lines
5.9 KiB
C
246 lines
5.9 KiB
C
/**************************************************************************
|
||
GTA PROJECT AT division
|
||
Copyright, 1990, The Regents of the University of California.
|
||
Los Alamos National Laboratory
|
||
|
||
@(#)seq_task.c 1.4 2/1/91
|
||
DESCRIPTION: Seq_tasks.c: Task creation and control for sequencer
|
||
state sets.
|
||
|
||
ENVIRONMENT: VxWorks
|
||
***************************************************************************/
|
||
|
||
#include "seq.h"
|
||
#include "vxWorks.h"
|
||
#include "taskLib.h"
|
||
|
||
|
||
LOCAL ss_task_init();
|
||
LOCAL ULONG get_timeout();
|
||
LOCAL VOID semTake();
|
||
|
||
|
||
extern TASK *task_area_ptr;
|
||
|
||
/* Create state set tasks. Set task variable for each task */
|
||
#define TASK_NAME_SIZE 25
|
||
create_ss_tasks(sp_ptr, stack_size)
|
||
SPROG *sp_ptr;
|
||
int stack_size;
|
||
{
|
||
SSCB *ss_ptr;
|
||
int nss;
|
||
char task_name[2*TASK_NAME_SIZE+2];
|
||
extern TASK *task_area_ptr;
|
||
extern ss_entry();
|
||
|
||
ss_ptr = sp_ptr->sscb;
|
||
task_name[0] = 0;
|
||
strncat(task_name, sp_ptr->name, TASK_NAME_SIZE);
|
||
strcat(task_name, "_");
|
||
|
||
for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++)
|
||
{
|
||
if (nss != 0)
|
||
{ /* Spawn the ss task */
|
||
/* Form task name from program name + state set name */
|
||
strncat(task_name, ss_ptr->name, TASK_NAME_SIZE);
|
||
|
||
ss_ptr->task_id = taskSpawn(task_name,
|
||
SPAWN_PRIORITY+ss_ptr->task_priority,
|
||
SPAWN_OPTIONS, stack_size, ss_entry, sp_ptr, ss_ptr);
|
||
#ifdef DEBUG
|
||
printf("task %d: %s\n", ss_ptr->task_id, task_name);
|
||
#endif DEBUG
|
||
}
|
||
}
|
||
/* Main task handles first state set */
|
||
ss_ptr = sp_ptr->sscb;
|
||
ss_ptr->task_id = sp_ptr->task_id;
|
||
ss_entry(sp_ptr, ss_ptr);
|
||
}
|
||
/* Task entry point for state sets */
|
||
/* Provides main loop for state set processing (common, re-entrant code) */
|
||
ss_entry(sp_ptr, ss_ptr)
|
||
SPROG *sp_ptr;
|
||
SSCB *ss_ptr;
|
||
{
|
||
BOOL ev_trig;
|
||
STATE *st_ptr;
|
||
ULONG delay, get_timeout();
|
||
|
||
/* Initialize all tasks except the main task */
|
||
if (ss_ptr->task_id != sp_ptr->task_id)
|
||
ss_task_init(sp_ptr, ss_ptr);
|
||
|
||
/* Start in first state */
|
||
st_ptr = ss_ptr->current_state;
|
||
|
||
/* Initialize for event flag processing */
|
||
ss_ptr->ev_flag_mask = st_ptr->event_flag_mask;
|
||
ss_ptr->ev_flag = 0;
|
||
|
||
/* Main loop */
|
||
while (1)
|
||
{
|
||
#ifdef DEBUG
|
||
printf("State set %s, state %s\n", ss_ptr->name, st_ptr->name);
|
||
#endif DEBUG
|
||
ss_ptr->time = tickGet(); /* record time we entered this state */
|
||
|
||
/* Call delay function to set up delays */
|
||
ss_ptr->ndelay = 0;
|
||
st_ptr->delay_func(sp_ptr, ss_ptr);
|
||
|
||
/* On 1-st pass fall thru w/o wake up */
|
||
semGive(ss_ptr->sem_id);
|
||
|
||
/* Loop until an event is triggered */
|
||
do {
|
||
/* Wake up on CA event, event flag, or expired time delay */
|
||
semTake(ss_ptr->sem_id, get_timeout(ss_ptr, st_ptr));
|
||
#ifdef DEBUG
|
||
printf("%s: semTake returned\n", ss_ptr->name);
|
||
#endif DEBUG
|
||
ss_ptr->time = tickGet();
|
||
/* Call event function to check for event trigger */
|
||
ev_trig = st_ptr->event_func(sp_ptr, ss_ptr);
|
||
} while (!ev_trig);
|
||
|
||
/* Event triggered, execute the corresponding action */
|
||
ss_ptr->action_complete = FALSE;
|
||
st_ptr->action_func(sp_ptr, ss_ptr);
|
||
|
||
/* Change to next state */
|
||
ss_ptr->current_state = ss_ptr->next_state;
|
||
ss_ptr->next_state = NULL;
|
||
st_ptr = ss_ptr->current_state;
|
||
ss_ptr->ev_flag_mask = st_ptr->event_flag_mask;
|
||
ss_ptr->ev_flag = 0;
|
||
ss_ptr->action_complete = TRUE;
|
||
}
|
||
}
|
||
/* Initialize state-set tasks */
|
||
LOCAL ss_task_init(sp_ptr, ss_ptr)
|
||
SPROG *sp_ptr;
|
||
SSCB *ss_ptr;
|
||
{
|
||
/* Import task variable context from main task */
|
||
taskVarAdd(ss_ptr->task_id, &task_area_ptr);
|
||
taskVarGet(sp_ptr->task_id, &task_area_ptr); /* main task's id */
|
||
|
||
/* Import Channel Access context from main task */
|
||
ca_import(sp_ptr->task_id);
|
||
|
||
return;
|
||
}
|
||
/* Return time-out for semTake() */
|
||
LOCAL ULONG get_timeout(ss_ptr)
|
||
SSCB *ss_ptr;
|
||
{
|
||
int ndelay;
|
||
ULONG time, timeout, tmin;
|
||
|
||
if (ss_ptr->ndelay == 0)
|
||
return 0;
|
||
|
||
time = tickGet();
|
||
tmin = 0;
|
||
/* find lowest timeout that's not expired */
|
||
for (ndelay = 0; ndelay < ss_ptr->ndelay; ndelay++)
|
||
{
|
||
timeout = ss_ptr->timeout[ndelay];
|
||
if (time < timeout)
|
||
{
|
||
if (tmin == 0 || timeout < tmin)
|
||
tmin = timeout;
|
||
}
|
||
}
|
||
if (tmin != 0)
|
||
tmin -= time; /* convert timeout to delay */
|
||
return tmin;
|
||
}
|
||
/* Set-up for delay() on entering a state. This routine is called
|
||
by the state program for each delay in the "when" statement */
|
||
VOID seq_start_delay(sp_ptr, ss_ptr, delay_id, delay)
|
||
SPROG *sp_ptr;
|
||
SSCB *ss_ptr;
|
||
int delay_id; /* delay id */
|
||
float delay;
|
||
{
|
||
ss_ptr->timeout[delay_id] = ss_ptr->time + delay*60.0;
|
||
delay_id += 1;
|
||
if (delay_id > ss_ptr->ndelay)
|
||
ss_ptr->ndelay = delay_id;
|
||
return;
|
||
}
|
||
|
||
/* Test for time-out expired */
|
||
BOOL seq_test_delay(sp_ptr, ss_ptr, delay_id)
|
||
SPROG *sp_ptr;
|
||
SSCB *ss_ptr;
|
||
int delay_id;
|
||
{
|
||
return (ss_ptr->time >= ss_ptr->timeout[delay_id]);
|
||
}
|
||
/* This task is run whenever ANY task in the system is deleted */
|
||
sprog_delete(pTcbX)
|
||
TCBX *pTcbX; /* ptr to TCB of task to be deleted */
|
||
{
|
||
int tid, nss, val, tid_ss;
|
||
SPROG *sp_ptr;
|
||
SSCB *ss_ptr;
|
||
extern TASK *task_area_ptr;
|
||
TASK *ta_ptr;
|
||
|
||
tid = pTcbX->taskId;
|
||
/* Note: task_area_ptr is a task variable */
|
||
val = taskVarGet(tid, &task_area_ptr);
|
||
if (val == ERROR)
|
||
return 0; /* not one of our tasks */
|
||
ta_ptr = (TASK *)val;
|
||
printf(" ta_ptr=0x%x, tid=%d=0x%x\n", ta_ptr, tid, tid);
|
||
sp_ptr = ta_ptr->sp_ptr;
|
||
|
||
/* Is this a real sequencer task? */
|
||
if (sp_ptr->magic != MAGIC)
|
||
{
|
||
printf(" Not main state program task\n");
|
||
return -1;
|
||
}
|
||
|
||
/* Delete state set tasks */
|
||
ss_ptr = sp_ptr->sscb;
|
||
for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++)
|
||
{
|
||
tid_ss = ss_ptr->task_id;
|
||
if ( tid_ss > 0)
|
||
{
|
||
/* Don't delete self yet */
|
||
if (tid != tid_ss)
|
||
{
|
||
printf(" delete ss task: tid=%d=0x%x\n",
|
||
tid_ss, tid_ss);
|
||
taskVarSet(tid_ss, &task_area_ptr, ERROR);
|
||
taskDelete(tid_ss);
|
||
}
|
||
}
|
||
}
|
||
|
||
printf("free ta_ptr=0x%x\n", ta_ptr);
|
||
taskDelay(60);
|
||
free(ta_ptr);
|
||
|
||
return 0;
|
||
}
|
||
/* semTake - take semaphore:
|
||
VxWorks semTake with timeout added. */
|
||
LOCAL VOID semTake (semId, timeout)
|
||
SEM_ID semId; /* semaphore id to take */
|
||
UINT timeout; /* timeout in tics */
|
||
{
|
||
int dummy;
|
||
|
||
vrtxPend(&semId->count, timeout, &dummy);
|
||
}
|