Ejemplo n.º 1
0
static void callbackTask(void *arg)
{
    int prio = *(int*)arg;
    cbQueueSet *mySet = &callbackQueue[prio];

    taskwdInsert(0, NULL, NULL);
    epicsEventSignal(startStopEvent);

    while(!mySet->shutdown) {
        void *ptr;
        if (epicsRingPointerIsEmpty(mySet->queue))
            epicsEventMustWait(mySet->semWakeUp);

        while ((ptr = epicsRingPointerPop(mySet->queue))) {
            CALLBACK *pcallback = (CALLBACK *)ptr;
            if(!epicsRingPointerIsEmpty(mySet->queue))
                epicsEventMustTrigger(mySet->semWakeUp);
            mySet->queueOverflow = FALSE;
            (*pcallback->callback)(pcallback);
        }
    }

    if(!epicsAtomicDecrIntT(&mySet->threadsRunning))
        epicsEventSignal(startStopEvent);
    taskwdRemove(0);
}
Ejemplo n.º 2
0
void casAttachThreadToClient ( struct client *pClient )
{
    epicsSignalInstallSigAlarmIgnore ();
    epicsSignalInstallSigPipeIgnore ();
    pClient->tid = epicsThreadGetIdSelf ();
    epicsThreadPrivateSet ( rsrvCurrentClient, pClient );
    taskwdInsert ( pClient->tid, NULL, NULL );
}
Ejemplo n.º 3
0
void testTask2(void *arg)
{
    taskwdInsert(0, taskNotify, NULL);
    testDiag("Task suspending");
    epicsThreadSuspendSelf();
    epicsThreadSleep(1.0);
    testDiag("Alive again");
    epicsThreadSleep(10.0);
    taskwdRemove(0);
}
Ejemplo n.º 4
0
static void asInitTask(ASDBCALLBACK *pcallback)
{
    long status;

    taskwdInsert(epicsThreadGetIdSelf(), wdCallback, (void *)pcallback);
    status = asInitCommon();
    taskwdRemove(epicsThreadGetIdSelf());
    asInitTheadId = 0;
    if(pcallback) {
	pcallback->status = status;
	callbackRequest(&pcallback->callback);
    }
}
Ejemplo n.º 5
0
static void onceTask(void *arg)
{
    taskwdInsert(0, NULL, NULL);
    epicsEventSignal(startStopEvent);

    while (TRUE) {
        void *precord;

        epicsEventMustWait(onceSem);
        while ((precord = epicsRingPointerPop(onceQ))) {
            if (precord == &exitOnce) goto shutdown;
            dbScanLock(precord);
            dbProcess(precord);
            dbScanUnlock(precord);
        }
    }

shutdown:
    taskwdRemove(0);
    epicsEventSignal(startStopEvent);
}
Ejemplo n.º 6
0
static void ClockTimeSync(void *dummy)
{
    taskwdInsert(0, NULL, NULL);

    for (epicsEventWaitWithTimeout(ClockTimePvt.loopEvent,
             ClockTimeSyncInterval);
         ClockTimePvt.synchronize == CLOCKTIME_SYNC;
         epicsEventWaitWithTimeout(ClockTimePvt.loopEvent,
             ClockTimeSyncInterval)) {
        epicsTimeStamp timeNow;
        int priority;

        if (generalTimeGetExceptPriority(&timeNow, &priority,
                LAST_RESORT_PRIORITY) == epicsTimeOK) {
            struct timespec clockNow;

            epicsTimeToTimespec(&clockNow, &timeNow);
            if (clock_settime(CLOCK_REALTIME, &clockNow)) {
                errlogPrintf("ClockTimeSync: clock_settime failed\n");
                continue;
            }

            epicsMutexMustLock(ClockTimePvt.lock);
            if (!ClockTimePvt.synchronized) {
                ClockTimePvt.startTime    = timeNow;
                ClockTimePvt.synchronized = 1;
            }
            ClockTimePvt.syncFromPriority = priority;
            ClockTimePvt.syncTime         = timeNow;
            epicsMutexUnlock(ClockTimePvt.lock);
        }
    }

    ClockTimePvt.synchronized = 0;
    taskwdRemove(0);
}
Ejemplo n.º 7
0
/*
 * caRepeaterThread ()
 */
extern "C" void caRepeaterThread ( void * /* pDummy */ )
{
    taskwdInsert ( epicsThreadGetIdSelf(), NULL, NULL );
    ca_repeater ();
}
Ejemplo n.º 8
0
/*
 *
 *  req_server()
 *
 *  CA server task
 *
 *  Waits for connections at the CA port and spawns a task to
 *  handle each of them
 *
 */
static void req_server (void *pParm)
{
    unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
    unsigned priorityOfBeacons;
    epicsThreadBooleanStatus tbs;
    struct sockaddr_in serverAddr;  /* server's address */
    osiSocklen_t addrSize;
    int status;
    SOCKET clientSock;
    epicsThreadId tid;
    int portChange;

    epicsSignalInstallSigPipeIgnore ();

    taskwdInsert ( epicsThreadGetIdSelf (), NULL, NULL );
    
    rsrvCurrentClient = epicsThreadPrivateCreate ();

    if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) {
        ca_server_port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT, 
            (unsigned short) CA_SERVER_PORT );
    }
    else {
        ca_server_port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, 
            (unsigned short) CA_SERVER_PORT );
    }

    if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) {
        epicsSocketDestroy ( IOC_sock );
    }
    
    /*
     * Open the socket. Use ARPA Internet address format and stream
     * sockets. Format described in <sys/socket.h>.
     */
    if ( ( IOC_sock = epicsSocketCreate (AF_INET, SOCK_STREAM, 0) ) == INVALID_SOCKET ) {
        errlogPrintf ("CAS: Socket creation error\n");
        epicsThreadSuspendSelf ();
    }

    epicsSocketEnableAddressReuseDuringTimeWaitState ( IOC_sock );

    /* Zero the sock_addr structure */
    memset ( (void *) &serverAddr, 0, sizeof ( serverAddr ) );
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl (INADDR_ANY); 
    serverAddr.sin_port = htons ( ca_server_port );

    /* get server's Internet address */
    status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
	if ( status < 0 ) {
		if ( SOCKERRNO == SOCK_EADDRINUSE ) {
			/*
			 * enable assignment of a default port
			 * (so the getsockname() call below will
			 * work correctly)
			 */
			serverAddr.sin_port = ntohs (0);
			status = bind ( IOC_sock, 
                (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
		}
		if ( status < 0 ) {
            char sockErrBuf[64];
            epicsSocketConvertErrnoToString ( 
                sockErrBuf, sizeof ( sockErrBuf ) );
            errlogPrintf ( "CAS: Socket bind error was \"%s\"\n",
                sockErrBuf );
            epicsThreadSuspendSelf ();
		}
        portChange = 1;
	}
    else {
        portChange = 0;
    }

	addrSize = ( osiSocklen_t ) sizeof ( serverAddr );
	status = getsockname ( IOC_sock, 
			(struct sockaddr *)&serverAddr, &addrSize);
	if ( status ) {
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( 
            sockErrBuf, sizeof ( sockErrBuf ) );
		errlogPrintf ( "CAS: getsockname() error %s\n", 
			sockErrBuf );
        epicsThreadSuspendSelf ();
	}

    ca_server_port = ntohs (serverAddr.sin_port);

    if ( portChange ) {
        errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
        errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n", 
            ca_server_port );
        errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
        errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
        errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
    }

    /* listen and accept new connections */
    if ( listen ( IOC_sock, 20 ) < 0 ) {
        errlogPrintf ("CAS: Listen error\n");
        epicsSocketDestroy (IOC_sock);
        epicsThreadSuspendSelf ();
    }

    tbs  = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfBeacons );
    if ( tbs != epicsThreadBooleanStatusSuccess ) {
        priorityOfBeacons = priorityOfSelf;
    }

    beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
    beacon_ctl = ctlPause;

    tid = epicsThreadCreate ( "CAS-beacon", priorityOfBeacons,
        epicsThreadGetStackSize (epicsThreadStackSmall),
        rsrv_online_notify_task, 0 );
    if ( tid == 0 ) {
        epicsPrintf ( "CAS: unable to start beacon thread\n" );
    }

    epicsEventMustWait(beacon_startStopEvent);
    epicsEventSignal(castcp_startStopEvent);

    while (TRUE) {
        struct sockaddr     sockAddr;
        osiSocklen_t        addLen = sizeof(sockAddr);

        while (castcp_ctl == ctlPause) {
            epicsThreadSleep(0.1);
        }

        clientSock = epicsSocketAccept ( IOC_sock, &sockAddr, &addLen );
        if ( clientSock == INVALID_SOCKET ) {
            char sockErrBuf[64];
            epicsSocketConvertErrnoToString ( 
                sockErrBuf, sizeof ( sockErrBuf ) );
            errlogPrintf("CAS: Client accept error was \"%s\"\n",
                sockErrBuf );
            epicsThreadSleep(15.0);
            continue;
        } 
        else {
            epicsThreadId id;
            struct client *pClient;

            /* socket passed in is closed if unsuccessful here */
            pClient = create_tcp_client ( clientSock );
            if ( ! pClient ) {
                epicsThreadSleep ( 15.0 );
                continue;
            }

            LOCK_CLIENTQ;
            ellAdd ( &clientQ, &pClient->node );
            UNLOCK_CLIENTQ;

            id = epicsThreadCreate ( "CAS-client", epicsThreadPriorityCAServerLow,
                    epicsThreadGetStackSize ( epicsThreadStackBig ),
                    camsgtask, pClient );
            if ( id == 0 ) {
                LOCK_CLIENTQ;
                ellDelete ( &clientQ, &pClient->node );
                UNLOCK_CLIENTQ;
                destroy_tcp_client ( pClient );
                errlogPrintf ( "CAS: task creation for new client failed\n" );
                epicsThreadSleep ( 15.0 );
                continue;
            }
        }
    }
}
Ejemplo n.º 9
0
void testTask1(void *arg)
{
    taskwdInsert(0, taskNotify, NULL);
    epicsThreadSleep(10.0);
    taskwdRemove(0);
}
Ejemplo n.º 10
0
static void NTPTimeSync(void *dummy)
{
    taskwdInsert(0, NULL, NULL);

    for (epicsEventWaitWithTimeout(NTPTimePvt.loopEvent, NTPTimeSyncInterval);
         NTPTimePvt.synchronize;
         epicsEventWaitWithTimeout(NTPTimePvt.loopEvent, NTPTimeSyncInterval)) {
        int             status;
        struct timespec timespecNow;
        epicsTimeStamp  timeNow;
        epicsUInt32     tickNow;
        double          diff;
        double          ntpDelta;

        status = osdNTPGet(&timespecNow);
        tickNow = osdTickGet();

        if (status) {
            if (++NTPTimePvt.syncsFailed > NTPTimeSyncRetries &&
                NTPTimePvt.synchronized) {
                errlogPrintf("NTPTimeSync: NTP requests failing - %s\n",
                    strerror(errno));
                NTPTimePvt.synchronized = 0;
            }
            continue;
        }

        if (timespecNow.tv_sec <= POSIX_TIME_AT_EPICS_EPOCH ||
            epicsTimeFromTimespec(&timeNow, &timespecNow) == epicsTimeERROR) {
            errlogPrintf("NTPTimeSync: Bad time received from NTP server\n");
            NTPTimePvt.synchronized = 0;
            continue;
        }

        ntpDelta = epicsTimeDiffInSeconds(&timeNow, &NTPTimePvt.syncTime);
        if (ntpDelta <= 0.0 && NTPTimePvt.synchronized) {
            errlogPrintf("NTPTimeSync: NTP time not increasing, delta = %g\n",
                ntpDelta);
            NTPTimePvt.synchronized = 0;
            continue;
        }

        NTPTimePvt.syncsFailed = 0;
        if (!NTPTimePvt.synchronized) {
            errlogPrintf("NTPTimeSync: Sync recovered.\n");
        }

        epicsMutexMustLock(NTPTimePvt.lock);
        diff = epicsTimeDiffInSeconds(&timeNow, &NTPTimePvt.clockTime);
        if (diff >= 0.0) {
            NTPTimePvt.ticksToSkip = 0;
        } else { /* dont go back in time */
            NTPTimePvt.ticksToSkip = -diff * osdTickRateGet();
        }
        NTPTimePvt.clockTick = tickNow;
        NTPTimePvt.clockTime = timeNow;
        NTPTimePvt.synchronized = 1;
        epicsMutexUnlock(NTPTimePvt.lock);

        NTPTimePvt.tickRate = (tickNow - NTPTimePvt.syncTick) / ntpDelta;
        NTPTimePvt.syncTick = tickNow;
        NTPTimePvt.syncTime = timeNow;
    }

    NTPTimePvt.synchronized = 0;
    taskwdRemove(0);
}
Ejemplo n.º 11
0
/*
 *  RSRV_ONLINE_NOTIFY_TASK
 */
void rsrv_online_notify_task(void *pParm)
{
    unsigned                    priorityOfSelf = epicsThreadGetPrioritySelf ();
    osiSockAddrNode             *pNode;
    double                      delay;
    double                      maxdelay;
    long                        longStatus;
    double                      maxPeriod;
    caHdr                       msg;
    int                         status;
    SOCKET                      sock;
    int                         intTrue = TRUE;
    unsigned short              port;
    ca_uint32_t                 beaconCounter = 0;
    char                        * pStr;
    int                         autoBeaconAddr;
    ELLLIST                     autoAddrList;
    char                        buf[16];
    unsigned                    priorityOfUDP;
    epicsThreadBooleanStatus    tbs;
    epicsThreadId               tid;
    
    taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL);
    
    if ( envGetConfigParamPtr ( & EPICS_CAS_BEACON_PERIOD ) ) {
        longStatus = envGetDoubleConfigParam ( & EPICS_CAS_BEACON_PERIOD, & maxPeriod );
    }
    else {
        longStatus = envGetDoubleConfigParam ( & EPICS_CA_BEACON_PERIOD, & maxPeriod );
    }
    if (longStatus || maxPeriod<=0.0) {
        maxPeriod = 15.0;
        epicsPrintf ("EPICS \"%s\" float fetch failed\n",
                        EPICS_CAS_BEACON_PERIOD.name);
        epicsPrintf ("Setting \"%s\" = %f\n",
            EPICS_CAS_BEACON_PERIOD.name, maxPeriod);
    }
    
    delay = 0.02; /* initial beacon period in sec */
    maxdelay = maxPeriod;
    
    /* 
     *  Open the socket.
     *  Use ARPA Internet address format and datagram socket.
     *  Format described in <sys/socket.h>.
     */
    if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
        errlogPrintf ("CAS: online socket creation error\n");
        epicsThreadSuspendSelf ();
    }
    
    status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, 
                (char *)&intTrue, sizeof(intTrue));
    if (status<0) {
        errlogPrintf ("CAS: online socket set up error\n");
        epicsThreadSuspendSelf ();
    }

    {
        /*
         * this connect is to supress a warning message on Linux
         * when we shutdown the read side of the socket. If it
         * fails (and it will on old ip kernels) we just ignore 
         * the failure.
         */
        osiSockAddr sockAddr;
        sockAddr.ia.sin_family = AF_UNSPEC;
        sockAddr.ia.sin_port = htons ( 0 );
        sockAddr.ia.sin_addr.s_addr = htonl (0);
        connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) );
        shutdown ( sock, SHUT_RD );
    }
    
    memset((char *)&msg, 0, sizeof msg);
    msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP);
    msg.m_count = htons (ca_server_port);
    msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION);
    
    ellInit ( & beaconAddrList );
    ellInit ( & autoAddrList );

    pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf);
    if ( ! pStr ) {
	    pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf);
    }
	if (pStr) {
		if (strstr(pStr,"no")||strstr(pStr,"NO")) {
			autoBeaconAddr = FALSE;
		}
		else if (strstr(pStr,"yes")||strstr(pStr,"YES")) {
			autoBeaconAddr = TRUE;
		}
		else {
			fprintf(stderr, 
		"CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr);
			autoBeaconAddr = TRUE;
		}
	}
	else {
		autoBeaconAddr = TRUE;
	}

    /*
     * load user and auto configured
     * broadcast address list
     */
    if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) {
        port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT, 
            (unsigned short) CA_REPEATER_PORT );
    }
    else {
        port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, 
            (unsigned short) CA_REPEATER_PORT );
    }

    /*
     * discover beacon addresses associated with this interface
     */
    if ( autoBeaconAddr ) {
        osiSockAddr addr;
		ELLLIST tmpList;

		ellInit ( &tmpList );
        addr.ia.sin_family = AF_UNSPEC;
        osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr); 
        forcePort ( &tmpList, port );
		removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 );
    }
            
    /*
     * by default use EPICS_CA_ADDR_LIST for the
     * beacon address list
     */
    {
        const ENV_PARAM *pParam;
        
        if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) || 
            envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) {
            pParam = &EPICS_CAS_BEACON_ADDR_LIST;
        }
        else {
            pParam = &EPICS_CA_ADDR_LIST;
        }
    
        /* 
         * add in the configured addresses
         */
        addAddrToChannelAccessAddressList (
            &autoAddrList, pParam, port,  pParam == &EPICS_CA_ADDR_LIST );
    }
 
    removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 );

    if ( ellCount ( &beaconAddrList ) == 0 ) {
        errlogPrintf ("The CA server's beacon address list was empty after initialization?\n");
    }
  
#   ifdef DEBUG
        printChannelAccessAddressList (&beaconAddrList);
#   endif

    tbs  = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP );
    if ( tbs != epicsThreadBooleanStatusSuccess ) {
        priorityOfUDP = priorityOfSelf;
    }

    casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
    casudp_ctl = ctlPause;

    tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP,
        epicsThreadGetStackSize (epicsThreadStackMedium),
        cast_server, 0 );
    if ( tid == 0 ) {
        epicsPrintf ( "CAS: unable to start UDP daemon thread\n" );
    }

    epicsEventMustWait(casudp_startStopEvent);
    epicsEventSignal(beacon_startStopEvent);

    while (TRUE) {
        pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList);
        while (pNode) {
            char buf[64];

            status = connect (sock, &pNode->addr.sa, 
                sizeof(pNode->addr.sa));
            if (status<0) {
                char sockErrBuf[64];
                epicsSocketConvertErrnoToString ( 
                    sockErrBuf, sizeof ( sockErrBuf ) );
                ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
                errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n",
                    __FILE__, buf, sockErrBuf);
            }
            else {
                struct sockaddr_in if_addr;

                osiSocklen_t size = sizeof (if_addr);
                status = getsockname (sock, (struct sockaddr *) &if_addr, &size);
                if (status<0) {
                    char sockErrBuf[64];
                    epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
                    errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n",
                        __FILE__, sockErrBuf);
                }
                else if (if_addr.sin_family==AF_INET) {
                    msg.m_available = if_addr.sin_addr.s_addr;
                    msg.m_cid = htonl ( beaconCounter );

                    status = send (sock, (char *)&msg, sizeof(msg), 0);
                    if (status < 0) {
                        char sockErrBuf[64];
                        epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
                        ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
                        errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
                            __FILE__, buf, sockErrBuf);
                    }
                    else {
                        assert (status == sizeof(msg));
                    }
                }
            }
            pNode = (osiSockAddrNode *) pNode->node.next;
        }

        epicsThreadSleep(delay);
        if (delay<maxdelay) {
            delay *= 2.0;
            if (delay>maxdelay) {
                delay = maxdelay;
            }
        }

        beaconCounter++; /* expected to overflow */

        while (beacon_ctl == ctlPause) {
            epicsThreadSleep(0.1);
            delay = 0.02; /* Restart beacon timing if paused */
        }
    }
}
Ejemplo n.º 12
0
/*
 * 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;
	PROG		*sp = ss->prog;

	/* Attach to PV system; was already done for the first state set */
	if (ss != sp->ss)
	{
		ss->threadId = epicsThreadGetIdSelf();
		createOrAttachPvSystem(sp);
	}

	/* 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 (optTest(sp, 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;
		double	now;

		/* 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
			|| optTest(st, OPT_DOENTRYFROMSELF)))
		{
			st->entryFunc(ss);
		}

		/* Flush any outstanding DB requests */
		pvSysFlush(sp->pvSys);

		/* Setting this semaphore here guarantees that a when() is
		 * always executed at least once when a state is first entered.
		 */
		epicsEventSignal(ss->syncSem);

		pvTimeGetCurrentDouble(&now);

		/* Set time we entered this state if transition from a different
		 * state or else if option not to do so is off for this state.
		 */
		if ((ss->currentState != ss->prevState) ||
			!optTest(st, OPT_NORESETTIMERS))
		{
			ss->timeEntered = now;
		}
		ss->wakeupTime = epicsINF;

		/* Loop until an event is triggered, i.e. when() returns TRUE
		 */
		do {
			/* Wake up on PV event, event flag, or expired delay */
			DEBUG("before epicsEventWaitWithTimeout(ss=%d,timeout=%f)\n",
				ss - sp->ss, ss->wakeupTime - now);
			epicsEventWaitWithTimeout(ss->syncSem, ss->wakeupTime - now);
			DEBUG("after epicsEventWaitWithTimeout()\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 (optTest(sp, OPT_SAFE))
				ss_read_all_buffer(sp, ss);

			ss->wakeupTime = epicsINF;

			/* Check state change conditions */
			ev_trig = st->eventFunc(ss,
				&transNum, &ss->nextState);

			/* Clear all event flags (old ef mode only) */
			if (ev_trig && !optTest(sp, OPT_NEWEF))
			{
				unsigned i;
				for (i = 0; i < NWORDS(sp->numEvFlags); i++)
				{
					sp->evFlags[i] &= ~ss->mask[i];
				}
			}
			if (!ev_trig)
				pvTimeGetCurrentDouble(&now);
		} while (!ev_trig);

		/* Execute the state change action */
		st->actionFunc(ss, 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
			|| optTest(st, OPT_DOEXITTOSELF)))
		{
			st->exitFunc(ss);
		}

		/* 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);
}
Ejemplo n.º 13
0
static void periodicTask(void *arg)
{
    periodic_scan_list *ppsl = (periodic_scan_list *)arg;
    epicsTimeStamp next, reported;
    unsigned int overruns = 0;
    double report_delay = OVERRUN_REPORT_DELAY;
    double overtime = 0.0;
    double over_min = 0.0;
    double over_max = 0.0;
    const double penalty = (ppsl->period >= 2) ? 1 : (ppsl->period / 2);

    taskwdInsert(0, NULL, NULL);
    epicsEventSignal(startStopEvent);

    epicsTimeGetCurrent(&next);
    reported = next;

    while (ppsl->scanCtl != ctlExit) {
        double delay;
        epicsTimeStamp now;

        if (ppsl->scanCtl == ctlRun)
            scanList(&ppsl->scan_list);

        epicsTimeAddSeconds(&next, ppsl->period);
        epicsTimeGetCurrent(&now);
        delay = epicsTimeDiffInSeconds(&next, &now);
        if (delay <= 0.0) {
            if (overtime == 0.0) {
                overtime = over_min = over_max = -delay;
            }
            else {
                overtime -= delay;
                if (over_min + delay > 0)
                    over_min = -delay;
                if (over_max + delay < 0)
                    over_max = -delay;
            }
            delay = penalty;
            ppsl->overruns++;
            next = now;
            epicsTimeAddSeconds(&next, delay);
            if (++overruns >= 10 &&
                epicsTimeDiffInSeconds(&now, &reported) > report_delay) {
                errlogPrintf("\ndbScan warning from '%s' scan thread:\n"
                    "\tScan processing averages %.2f seconds (%.2f .. %.2f).\n"
                    "\tOver-runs have now happened %u times in a row.\n"
                    "\tTo fix this, move some records to a slower scan rate.\n",
                    ppsl->name, ppsl->period + overtime / overruns,
                    ppsl->period + over_min, ppsl->period + over_max, overruns);

                reported = now;
                if (report_delay < (OVERRUN_REPORT_MAX / 2))
                    report_delay *= 2;
                else
                    report_delay = OVERRUN_REPORT_MAX;
            }
        }
        else {
            overruns = 0;
            report_delay = OVERRUN_REPORT_DELAY;
            overtime = 0.0;
        }

        epicsEventWaitWithTimeout(ppsl->loopEvent, delay);
    }

    taskwdRemove(0);
    epicsEventSignal(startStopEvent);
}
Ejemplo n.º 14
0
static void dbCaTask(void *arg)
{
    taskwdInsert(0, NULL, NULL);
    SEVCHK(ca_context_create(ca_enable_preemptive_callback),
        "dbCaTask calling ca_context_create");
    dbCaClientContext = ca_current_context ();
    SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
        "ca_add_exception_event");
    epicsEventSignal(startStopEvent);

    /* channel access event loop */
    while (TRUE){
        do {
            epicsEventMustWait(workListEvent);
        } while (dbCaCtl == ctlPause);
        while (TRUE) { /* process all requests in workList*/
            caLink *pca;
            short  link_action;
            int    status;

            epicsMutexMustLock(workListLock);
            if (!(pca = (caLink *)ellGet(&workList))){  /* Take off list head */
                epicsMutexUnlock(workListLock);
                if (dbCaCtl == ctlExit) goto shutdown;
                break; /* workList is empty */
            }
            link_action = pca->link_action;
            pca->link_action = 0;
            if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
            epicsMutexUnlock(workListLock);         /* Give back immediately */
            if (link_action & CA_CLEAR_CHANNEL) {   /* This must be first */
                dbCaLinkFree(pca);
                /* No alarm is raised. Since link is changing so what? */
                continue; /* No other link_action makes sense */
            }
            if (link_action & CA_CONNECT) {
                status = ca_create_channel(
                      pca->pvname,connectionCallback,(void *)pca,
                      CA_PRIORITY_DB_LINKS, &(pca->chid));
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_create_channel %s\n",
                        ca_message(status));
                    printLinks(pca);
                    continue;
                }
                dbca_chan_count++;
                status = ca_replace_access_rights_event(pca->chid,
                    accessRightsCallback);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask replace_access_rights_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                continue; /*Other options must wait until connect*/
            }
            if (ca_state(pca->chid) != cs_conn) continue;
            if (link_action & CA_WRITE_NATIVE) {
                assert(pca->pputNative);
                if (pca->putType == CA_PUT) {
                    status = ca_array_put(
                        pca->dbrType, pca->nelements,
                        pca->chid, pca->pputNative);
                } else if (pca->putType==CA_PUT_CALLBACK) {
                    status = ca_array_put_callback(
                        pca->dbrType, pca->nelements,
                        pca->chid, pca->pputNative,
                        putCallback, pca);
                } else {
                    status = ECA_PUTFAIL;
                }
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_array_put %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                epicsMutexMustLock(pca->lock);
                if (status == ECA_NORMAL) pca->newOutNative = FALSE;
                epicsMutexUnlock(pca->lock);
            }
            if (link_action & CA_WRITE_STRING) {
                assert(pca->pputString);
                if (pca->putType == CA_PUT) {
                    status = ca_array_put(
                        DBR_STRING, 1,
                        pca->chid, pca->pputString);
                } else if (pca->putType==CA_PUT_CALLBACK) {
                    status = ca_array_put_callback(
                        DBR_STRING, 1,
                        pca->chid, pca->pputString,
                        putCallback, pca);
                } else {
                    status = ECA_PUTFAIL;
                }
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_array_put %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                epicsMutexMustLock(pca->lock);
                if (status == ECA_NORMAL) pca->newOutString = FALSE;
                epicsMutexUnlock(pca->lock);
            }
            /*CA_GET_ATTRIBUTES before CA_MONITOR so that attributes available
             * before the first monitor callback                              */
            if (link_action & CA_GET_ATTRIBUTES) {
                status = ca_get_callback(DBR_CTRL_DOUBLE,
                    pca->chid, getAttribEventCallback, pca);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_get_callback %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
            if (link_action & CA_MONITOR_NATIVE) {
                size_t element_size;
    
                element_size = dbr_value_size[ca_field_type(pca->chid)];
                epicsMutexMustLock(pca->lock);
                pca->pgetNative = dbCalloc(pca->nelements, element_size);
                epicsMutexUnlock(pca->lock);
                status = ca_add_array_event(
                    ca_field_type(pca->chid)+DBR_TIME_STRING,
                    ca_element_count(pca->chid),
                    pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_add_array_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
            if (link_action & CA_MONITOR_STRING) {
                epicsMutexMustLock(pca->lock);
                pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
                epicsMutexUnlock(pca->lock);
                status = ca_add_array_event(DBR_TIME_STRING, 1,
                    pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_add_array_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
        }
        SEVCHK(ca_flush_io(), "dbCaTask");
    }
shutdown:
    taskwdRemove(0);
    if (dbca_chan_count == 0)
        ca_context_destroy();
    else
        fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", dbca_chan_count);
    epicsEventSignal(startStopEvent);
}