/******************************************************************************* *Function: delay *Description: delays program execution by a certain number of miliseconds *Parameters: * DWORD time Number of miliseconds to pause *Returns: * none *******************************************************************************/ void delay(unsigned int time) /* exported! */ { #ifndef WIN32 unsigned long int startTime= GetTickCount(); while (calcTimeout(startTime) < time); #else Sleep(time); #endif }
/* * ss_entry() - Thread entry point for all state sets. * Provides the main loop for state set processing. */ static void ss_entry(void *arg) { SSCB *ss = (SSCB *)arg; SPROG *sp = ss->sprog; USER_VAR *var; if (sp->options & OPT_SAFE) var = ss->var; else var = sp->var; /* Attach to PV system; was already done for the first state set */ if (ss != sp->ss) { ss->threadId = epicsThreadGetIdSelf(); pvSysAttach(sp->pvSys); } /* Register this thread with the EPICS watchdog (no callback func) */ taskwdInsert(ss->threadId, 0, 0); /* In safe mode, update local var buffer with global one before entering the event loop. Must do this using ss_read_all_buffer since CA and other state sets could already post events resp. pvPut. */ if (sp->options & OPT_SAFE) ss_read_all_buffer(sp, ss); /* Initial state is the first one */ ss->currentState = 0; ss->nextState = -1; ss->prevState = -1; DEBUG("ss %s: entering main loop\n", ss->ssName); /* * ============= Main loop ============== */ while (TRUE) { boolean ev_trig; int transNum = 0; /* highest prio trans. # triggered */ STATE *st = ss->states + ss->currentState; /* Set state to current state */ assert(ss->currentState >= 0); /* Set state set event mask to this state's event mask */ ss->mask = st->eventMask; /* If we've changed state, do any entry actions. Also do these * even if it's the same state if option to do so is enabled. */ if (st->entryFunc && (ss->prevState != ss->currentState || (st->options & OPT_DOENTRYFROMSELF))) { st->entryFunc(ss, var); } /* Flush any outstanding DB requests */ pvSysFlush(sp->pvSys); clearDelays(ss, st); /* Clear delay list */ st->delayFunc(ss, var); /* Set up new delay list */ /* Setting this semaphore here guarantees that a when() is * always executed at least once when a state is first * entered. */ epicsEventSignal(ss->syncSemId); /* Loop until an event is triggered, i.e. when() returns TRUE */ do { double delay = 0.0; /* Wake up on PV event, event flag, or expired delay */ if (calcTimeout(ss, &delay)) { DEBUG("before epicsEventWaitWithTimeout(ss=%d,delay=%f)\n", ss - sp->ss, delay); epicsEventWaitWithTimeout(ss->syncSemId, delay); DEBUG("after epicsEventWaitWithTimeout()\n"); } else { DEBUG("before epicsEventWait\n"); epicsEventWait(ss->syncSemId); DEBUG("after epicsEventWait\n"); } /* Check whether we have been asked to exit */ if (sp->die) goto exit; /* Copy dirty variable values from CA buffer * to user (safe mode only). */ if (sp->options & OPT_SAFE) ss_read_all_buffer(sp, ss); /* Check state change conditions */ ev_trig = st->eventFunc(ss, var, &transNum, &ss->nextState); /* Clear all event flags (old ef mode only) */ if (ev_trig && !(sp->options & OPT_NEWEF)) { unsigned i; for (i = 0; i < NWORDS(sp->numEvFlags); i++) { sp->evFlags[i] &= ~ss->mask[i]; } } } while (!ev_trig); /* Execute the state change action */ st->actionFunc(ss, var, transNum, &ss->nextState); /* Check whether we have been asked to exit */ if (sp->die) goto exit; /* If changing state, do exit actions */ if (st->exitFunc && (ss->currentState != ss->nextState || (st->options & OPT_DOEXITTOSELF))) { st->exitFunc(ss, var); } /* Change to next state */ ss->prevState = ss->currentState; ss->currentState = ss->nextState; } /* Thread exit has been requested */ exit: taskwdRemove(ss->threadId); /* Declare ourselves dead */ if (ss != sp->ss) epicsEventSignal(ss->dead); }