Esempio n. 1
0
/*
 * Ensure func() is run only once.
 */
void epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
{
    #define EPICS_THREAD_ONCE_DONE (epicsThreadId) 1

    if (!initialized) epicsThreadInit();
    epicsMutexMustLock(onceMutex);
    if (*id != EPICS_THREAD_ONCE_DONE) {
        if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
            *id = epicsThreadGetIdSelf();    /* mark active */
            epicsMutexUnlock(onceMutex);
            func(arg);
            epicsMutexMustLock(onceMutex);
            *id = EPICS_THREAD_ONCE_DONE;    /* mark done */
        } else if (*id == epicsThreadGetIdSelf()) {
            epicsMutexUnlock(onceMutex);
            cantProceed("Recursive epicsThreadOnce() initialization\n");
        } else
            while (*id != EPICS_THREAD_ONCE_DONE) {
                /* Another thread is in the above func(arg) call. */
                epicsMutexUnlock(onceMutex);
                epicsThreadSleep(epicsThreadSleepQuantum());
                epicsMutexMustLock(onceMutex);
            }
    }
    epicsMutexUnlock(onceMutex);
}
Esempio n. 2
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);
    }
}
Esempio n. 3
0
// extern "C"
int epicsShareAPI ca_clear_channel ( chid pChan )
{
    ca_client_context & cac = pChan->getClientCtx ();
    {
        epicsGuard < epicsMutex > guard ( cac.mutex );
        try {
            pChan->eliminateExcessiveSendBacklog ( guard );
        }
        catch ( cacChannel::notConnected & ) {
            // intentionally ignored
        }
    }
    if ( cac.pCallbackGuard.get() &&
            cac.createdByThread == epicsThreadGetIdSelf () ) {
        epicsGuard < epicsMutex > guard ( cac.mutex );
        pChan->destructor ( *cac.pCallbackGuard.get(), guard );
    cac.oldChannelNotifyFreeList.release ( pChan );
    }
    else {
        //
        // we will definately stall out here if all of the
        // following are true
        //
        // o user creates non-preemtive mode client library context
        // o user doesnt periodically call a ca function
        // o user calls this function from an auxiillary thread
        //
        CallbackGuard cbGuard ( cac.cbMutex );
        epicsGuard < epicsMutex > guard ( cac.mutex );
        pChan->destructor ( *cac.pCallbackGuard.get(), guard );
        cac.oldChannelNotifyFreeList.release ( pChan );
    }
    return ECA_NORMAL;
}
void OrderedMutex::lock(const char *file, size_t line)
{
#ifdef DETECT_DEADLOCK
    LockMonitor::getInstance()->add(file, line, epicsThreadGetIdSelf(), *this);
#endif
    if (epicsMutexLock(mutex) != epicsMutexLockOK)
    {
        if (getenv("ABORT_ON_ERRORS"))
        {
            LOG_MSG("%s (%zu): mutex lock '%s' failed\n",
                file, line, name.c_str());
            abort();
        }
        // else
        throw GenericException(file, line, "mutex lock '%s' failed",
                               name.c_str());
    }
#ifdef DETECT_DEADLOCK
    if (getenv("TRACE_MUTEX"))
    {
        fprintf(stderr, "%25s:%4zu Lock   : ", file, line);
        LockMonitor::getInstance()->dump();
    }
#endif
}
Esempio n. 5
0
/*
 * ca_sg_delete()
 */
extern "C" int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid )
{
    ca_client_context * pcac;
    int caStatus = fetchClientContext ( & pcac );
    if ( caStatus == ECA_NORMAL ) {
        if ( pcac->pCallbackGuard.get() &&
            pcac->createdByThread == epicsThreadGetIdSelf () ) {
          epicsGuard < epicsMutex > guard ( pcac->mutex );
          caStatus = ca_sync_group_destroy ( *pcac->pCallbackGuard.get(),
                                          guard, *pcac, gid );
        }
        else {
          //
          // we will definately stall out here if all of the
          // following are true
          //
          // o user creates non-preemtive mode client library context
          // o user doesnt periodically call a ca function
          // o user calls this function from an auxiillary thread
          //
          CallbackGuard cbGuard ( pcac->cbMutex );
          epicsGuard < epicsMutex > guard ( pcac->mutex );
          caStatus = ca_sync_group_destroy ( cbGuard, guard, *pcac, gid );
        }
    }
    return caStatus;
}
Esempio n. 6
0
File: taskwd.c Progetto: ukaea/epics
void taskwdInsert(epicsThreadId tid, TASKWDFUNC callback, void *usr)
{
    struct tNode *pt;
    struct mNode *pm;

    taskwdInit();
    if (tid == 0)
       tid = epicsThreadGetIdSelf();

    pt = &allocNode()->t;
    pt->tid = tid;
    pt->callback = callback;
    pt->usr = usr;
    pt->suspended = FALSE;

    epicsMutexMustLock(mLock);
    pm = (struct mNode *)ellFirst(&mList);
    while (pm) {
        if (pm->funcs->insert) {
            pm->funcs->insert(pm->usr, tid);
        }
        pm = (struct mNode *)ellNext(&pm->node);
    }
    epicsMutexUnlock(mLock);

    epicsMutexMustLock(tLock);
    ellAdd(&tList, (void *)pt);
    epicsMutexUnlock(tLock);
}
Esempio n. 7
0
void threadFunc_RTcore_DivideB(void *param)
{
	ST_RTcore *pRTcore = (ST_RTcore*) param;;
	epicsThreadId pthreadInfo;

#if USE_CPU_AFFINITY_RT	
	pthreadInfo = epicsThreadGetIdSelf();
/*	printf("%s: EPICS ID %p, pthreadID %lu\n", pthreadInfo->name, (void *)pthreadInfo, (unsigned long)pthreadInfo->tid); */
	epicsThreadSetCPUAffinity( pthreadInfo, AFFINITY_RTCORE_DivB);
	epicsThreadSetPosixPriority(pthreadInfo, PRIOTY_RTCORE_DivB, "SCHED_FIFO");
#endif

	epicsThreadSleep(1.0);


	while(TRUE) {
		epicsEventWait( pRTcore->ST_DivThreadB.threadEventId);

#if USE_RTCORE_DivB_HIGH
		WRITE32(pRTcore->base0 + 0x4, 0x1);
#endif
#if USE_RTCORE_DivB_LOW
		WRITE32(pRTcore->base0 + 0x4, 0x0);
#endif

	}
}
Esempio n. 8
0
void casAttachThreadToClient ( struct client *pClient )
{
    epicsSignalInstallSigAlarmIgnore ();
    epicsSignalInstallSigPipeIgnore ();
    pClient->tid = epicsThreadGetIdSelf ();
    epicsThreadPrivateSet ( rsrvCurrentClient, pClient );
    taskwdInsert ( pClient->tid, NULL, NULL );
}
void OrderedMutex::unlock()
{
    epicsMutexUnlock(mutex);
#ifdef DETECT_DEADLOCK
    LockMonitor::getInstance()->remove(epicsThreadGetIdSelf(), *this);
    if (getenv("TRACE_MUTEX"))
    {
        fprintf(stderr, "                               Unlock : ");
        LockMonitor::getInstance()->dump();
    }
#endif
}
Esempio n. 10
0
epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
{
    static struct epicsThreadOSD threadOnceComplete;
    #define EPICS_THREAD_ONCE_DONE &threadOnceComplete
    int status;

    epicsThreadInit();
    status = mutexLock(&onceLock);
    if(status) {
        fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
            strerror(status));
        exit(-1);
    }

    if (*id != EPICS_THREAD_ONCE_DONE) {
        if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
            *id = epicsThreadGetIdSelf();    /* mark active */
            status = pthread_mutex_unlock(&onceLock);
            checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
            func(arg);
            status = mutexLock(&onceLock);
            checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
            *id = EPICS_THREAD_ONCE_DONE;    /* mark done */
        } else if (*id == epicsThreadGetIdSelf()) {
            status = pthread_mutex_unlock(&onceLock);
            checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
            cantProceed("Recursive epicsThreadOnce() initialization\n");
        } else
            while (*id != EPICS_THREAD_ONCE_DONE) {
                /* Another thread is in the above func(arg) call. */
                status = pthread_mutex_unlock(&onceLock);
                checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
                epicsThreadSleep(epicsThreadSleepQuantum());
                status = mutexLock(&onceLock);
                checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
            }
    }
    status = pthread_mutex_unlock(&onceLock);
    checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
}
Esempio n. 11
0
epicsShareFunc void * mallocMustSucceed(size_t size, const char *msg)
{
    void * mem = NULL;
    if (size > 0) {
        while ((mem = malloc(size)) == NULL) {
            errlogPrintf("%s: mallocMustSucceed(%lu) - malloc failed\n",
                msg, (unsigned long)size);
            errlogPrintf("Thread %s (%p) suspending.\n",
                    epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf());
            errlogFlush();
            epicsThreadSuspendSelf();
        }
    }
    return mem;
}
Esempio n. 12
0
epicsShareFunc void cantProceed(const char *msg, ...)
{
    va_list pvar;
    va_start(pvar, msg);
    if (msg)
        errlogVprintf(msg, pvar);
    va_end(pvar);
    
    errlogPrintf("Thread %s (%p) can't proceed, suspending.\n",
            epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf());
    errlogFlush();
    
    epicsThreadSleep(1.0);
    while (1)
        epicsThreadSuspendSelf();
}
Esempio n. 13
0
static long doCalc(acalcoutRecord *pcalc) {
	calcMessage msg;
	int doAsync = 0;

	if (aCalcoutRecordDebug >= 10)
		printf("acalcoutRecord(%s):doCalc\n", pcalc->name);

	if ( acalcGetNumElements(pcalc) > aCalcAsyncThreshold )
		doAsync = 1;

	/* if required infrastructure doesn't yet exist, create it */
	if (doAsync && acalcMsgQueue == NULL) {
		acalcMsgQueue = epicsMessageQueueCreate(MAX_MSG, MSG_SIZE);
		if (acalcMsgQueue==NULL) {
			printf("aCalcoutRecord: Unable to create message queue\n");
			return(-1);
		}

		acalcThreadId = epicsThreadCreate("acalcPerformTask", PRIORITY,
			epicsThreadGetStackSize(epicsThreadStackBig),
			(EPICSTHREADFUNC)acalcPerformTask, (void *)epicsThreadGetIdSelf());

		if (acalcThreadId == NULL) {
			printf("aCalcoutRecord: Unable to create acalcPerformTask\n");
			epicsMessageQueueDestroy(acalcMsgQueue);
			acalcMsgQueue = NULL;
			return(-1);
		}
	}
	
	/* Ideally, we should do short calculations in this thread, and queue long calculations.
	 * But aCalcPerform is not reentrant (global value stack), so for now we queue everything.
	 */
	if (doAsync) {
		if (aCalcoutRecordDebug >= 2) printf("acalcoutRecord(%s):doCalc async\n", pcalc->name);
		pcalc->cact = 1; /* Tell caller that we went asynchronous */
		msg.pcalc = pcalc;
		epicsMessageQueueSend(acalcMsgQueue, (void *)&msg, MSG_SIZE);
		return(0);
	} else {
		if (aCalcoutRecordDebug >= 2) printf("acalcoutRecord(%s):doCalc sync\n", pcalc->name);
		call_aCalcPerform(pcalc);
	}
	return(0);
}
Esempio n. 14
0
/* Action function for state "wait_z_pv2" in state set "reassign" */
static void A_reassign_0_wait_z_pv2(SS_ID ssId, struct UserVar *pVar, int transNum, int *pNextState)
{
    switch(transNum)
    {
    case 0:
    {
# line 81 "../reassign.st"
        testDiag("wait_z_pv2");
# line 82 "../reassign.st"
        testOk1(seq_pvChannelCount(ssId) == 3);
# line 83 "../reassign.st"
        testOk1(seq_pvConnectCount(ssId) == 3);
# line 84 "../reassign.st"
        testOk1(seq_pvAssignCount(ssId) == 3);
# line 85 "../reassign.st"
        seqShow(epicsThreadGetIdSelf());
    }
    return;
    }
}
Esempio n. 15
0
void sync_group_reset ( ca_client_context & client, CASG & sg )
{
    if ( client.pCallbackGuard.get() &&
        client.createdByThread == epicsThreadGetIdSelf () ) {
        epicsGuard < epicsMutex > guard ( client.mutex );
        sg.reset ( *client.pCallbackGuard.get(), guard );
    }
    else {  
        //
        // we will definately stall out here if all of the
        // following are true
        //
        // o user creates non-preemtive mode client library context
        // o user doesnt periodically call a ca function
        // o user calls this function from an auxiillary thread
        //
        CallbackGuard cbGuard ( client.cbMutex );
        epicsGuard < epicsMutex > guard ( client.mutex );
        sg.reset ( cbGuard, guard );
    }
}
Esempio n. 16
0
/*
 * ca_sg_test
 */
extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid )
{
    ca_client_context * pcac;
    int caStatus = fetchClientContext ( &pcac );
    if ( caStatus == ECA_NORMAL ) {
        epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
        CASG * pcasg = pcac->lookupCASG ( guard, gid );
        if ( pcasg ) {
            bool isComplete;
            if ( pcac->pCallbackGuard.get() &&
                pcac->createdByThread == epicsThreadGetIdSelf () ) {
              epicsGuard < epicsMutex > guard ( pcac->mutex );
              isComplete = pcasg->ioComplete ( *pcac->pCallbackGuard.get(), guard );
            }
            else {
              //
              // we will definately stall out here if all of the
              // following are true
              //
              // o user creates non-preemtive mode client library context
              // o user doesnt periodically call a ca function
              // o user calls this function from an auxiillary thread
              //
              CallbackGuard cbGuard ( pcac->cbMutex );
              epicsGuard < epicsMutex > guard ( pcac->mutex );
              isComplete = pcasg->ioComplete ( cbGuard, guard );
            }
            if ( isComplete ) {
                caStatus = ECA_IODONE;
            }
            else{
                caStatus = ECA_IOINPROGRESS;
            }
        }
        else {
            caStatus = ECA_BADSYNCGRP;
        }
    }
    return caStatus;
}
Esempio n. 17
0
File: taskwd.c Progetto: ukaea/epics
void taskwdRemove(epicsThreadId tid)
{
    struct tNode *pt;
    struct mNode *pm;
    char tName[40];

    taskwdInit();

    if (tid == 0)
       tid = epicsThreadGetIdSelf();

    epicsMutexMustLock(tLock);
    pt = (struct tNode *)ellFirst(&tList);
    while (pt != NULL) {
        if (tid == pt->tid) {
            ellDelete(&tList, (void *)pt);
            epicsMutexUnlock(tLock);
            freeNode((union twdNode *)pt);

            epicsMutexMustLock(mLock);
            pm = (struct mNode *)ellFirst(&mList);
            while (pm) {
                if (pm->funcs->remove) {
                    pm->funcs->remove(pm->usr, tid);
                }
                pm = (struct mNode *)ellNext(&pm->node);
            }
            epicsMutexUnlock(mLock);
            return;
        }
        pt = (struct tNode *)ellNext(&pt->node);
    }
    epicsMutexUnlock(tLock);

    epicsThreadGetName(tid, tName, sizeof(tName));
    errlogPrintf("taskwdRemove: Thread %s (%p) not registered!\n",
        tName, (void *)tid);
}
Esempio n. 18
0
/*
 * caRepeaterThread ()
 */
extern "C" void caRepeaterThread ( void * /* pDummy */ )
{
    taskwdInsert ( epicsThreadGetIdSelf(), NULL, NULL );
    ca_repeater ();
}
Esempio n. 19
0
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void)
{
    epicsThreadInit();
    return(epicsThreadGetPriority(epicsThreadGetIdSelf()));
}
Esempio n. 20
0
/*
 * sequencer() - Sequencer main thread entry point.
 */
void sequencer (void *arg)	/* ptr to original (global) state program table */
{
	PROG		*sp = (PROG *)arg;
	unsigned	nss;
	size_t		threadLen;
	char		threadName[THREAD_NAME_SIZE+10];

	/* Get this thread's id */
	sp->ss->threadId = epicsThreadGetIdSelf();

	/* Add the program to the program list */
	seqAddProg(sp);

	createOrAttachPvSystem(sp);

	if (!pvSysIsDefined(sp->pvSys))
	{
		sp->die = TRUE;
		goto exit;
	}

	/* Call sequencer init function to initialize variables. */
	sp->initFunc(sp);

	/* Initialize state set variables. In safe mode, copy variable
	   block to state set buffers. Must do all this before connecting. */
	if (optTest(sp, OPT_SAFE))
	{
		for (nss = 0; nss < sp->numSS; nss++)
		{
			SSCB	*ss = sp->ss + nss;
			memcpy(ss->var, sp->var, sp->varSize);
		}
	}

	/* Attach to PV system */
	pvSysAttach(sp->pvSys);

	/* Initiate connect & monitor requests to database channels, waiting
	   for all connections to be established if the option is set. */
	if (seq_connect(sp, optTest(sp, OPT_CONN) != pvStatOK))
		goto exit;

	/* Emulate the 'first monitor event' for anonymous PVs */
	if (optTest(sp, OPT_SAFE))
	{
		unsigned nch;
		for (nch=0; nch<sp->numChans; nch++)
			if (sp->chan[nch].syncedTo && !sp->chan[nch].dbch)
				seq_efSet(sp->ss, sp->chan[nch].syncedTo);
	}

	/* Call program entry function if defined.
	   Treat as if called from 1st state set. */
	if (sp->entryFunc) sp->entryFunc(sp->ss);

	/* Create each additional state set task (additional state set thread
	   names are derived from the first ss) */
	epicsThreadGetName(sp->ss->threadId, threadName, sizeof(threadName));
	threadLen = strlen(threadName);
	for (nss = 1; nss < sp->numSS; nss++)
	{
		SSCB		*ss = sp->ss + nss;
		epicsThreadId	tid;

		/* Form thread name from program name + state set number */
		sprintf(threadName+threadLen, "_%d", nss);

		/* Spawn the task */
		tid = epicsThreadCreate(
			threadName,			/* thread name */
			sp->threadPriority,		/* priority */
			sp->stackSize,			/* stack size */
			ss_entry,			/* entry point */
			ss);				/* parameter */

		DEBUG("Spawning additional state set thread %p: \"%s\"\n", tid, threadName);
	}

	/* First state set jumps directly to entry point */
	ss_entry(sp->ss);

	DEBUG("   Wait for other state sets to exit\n");
	for (nss = 1; nss < sp->numSS; nss++)
	{
		SSCB *ss = sp->ss + nss;
		epicsEventMustWait(ss->dead);
	}

	/* Call program exit function if defined.
	   Treat as if called from 1st state set. */
	if (sp->exitFunc) sp->exitFunc(sp->ss);

exit:
	DEBUG("   Disconnect all channels\n");
	seq_disconnect(sp);
	DEBUG("   Remove program instance from list\n");
	seqDelProg(sp);

	errlogSevPrintf(errlogInfo,
		"Instance %d of sequencer program \"%s\" terminated\n",
		sp->instance, sp->progName);

	/* Free all allocated memory */
	seq_free(sp);
}
Esempio n. 21
0
//
// cac::cac ()
//
cac::cac ( 
    epicsMutex & mutualExclusionIn, 
    epicsMutex & callbackControlIn, 
    cacContextNotify & notifyIn ) :
    _refLocalHostName ( localHostNameCache.getReference () ),
    programBeginTime ( epicsTime::getCurrent() ),
    connTMO ( CA_CONN_VERIFY_PERIOD ),
    mutex ( mutualExclusionIn ),
    cbMutex ( callbackControlIn ),
    ipToAEngine ( ipAddrToAsciiEngine::allocate () ),
    timerQueue ( epicsTimerQueueActive::allocate ( false, 
        lowestPriorityLevelAbove(epicsThreadGetPrioritySelf()) ) ),
    pUserName ( 0 ),
    pudpiiu ( 0 ),
    tcpSmallRecvBufFreeList ( 0 ),
    tcpLargeRecvBufFreeList ( 0 ),
    notify ( notifyIn ),
    initializingThreadsId ( epicsThreadGetIdSelf() ),
    initializingThreadsPriority ( epicsThreadGetPrioritySelf() ),
    maxRecvBytesTCP ( MAX_TCP ),
    maxContigFrames ( contiguousMsgCountWhichTriggersFlowControl ),
    beaconAnomalyCount ( 0u ),
    iiuExistenceCount ( 0u ),
    cacShutdownInProgress ( false )
{
    if ( ! osiSockAttach () ) {
        throwWithLocation ( udpiiu :: noSocket () );
    }

    try {
	    long status;

        /*
         * Certain os, such as HPUX, do not unblock a socket system call 
         * when another thread asynchronously calls both shutdown() and 
         * close(). To solve this problem we need to employ OS specific
         * mechanisms.
         */
        epicsSignalInstallSigAlarmIgnore ();
        epicsSignalInstallSigPipeIgnore ();

        {
            char tmp[256];
            size_t len;
            osiGetUserNameReturn gunRet;

            gunRet = osiGetUserName ( tmp, sizeof (tmp) );
            if ( gunRet != osiGetUserNameSuccess ) {
                tmp[0] = '\0';
            }
            len = strlen ( tmp ) + 1;
            this->pUserName = new char [ len ];
            strncpy ( this->pUserName, tmp, len );
        }

        this->_serverPort = 
            envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
                                        static_cast <unsigned short> (CA_SERVER_PORT) );

        status = envGetDoubleConfigParam ( &EPICS_CA_CONN_TMO, &this->connTMO );
        if ( status ) {
            this->connTMO = CA_CONN_VERIFY_PERIOD;
            epicsGuard < epicsMutex > cbGuard ( this->cbMutex );
            errlogPrintf ( "EPICS \"%s\" double fetch failed\n", EPICS_CA_CONN_TMO.name );
            errlogPrintf ( "Defaulting \"%s\" = %f\n", EPICS_CA_CONN_TMO.name, this->connTMO );
        }

        long maxBytesAsALong;
        status =  envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong );
        if ( status || maxBytesAsALong < 0 ) {
            errlogPrintf ( "cac: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" );
        }
        else {
            /* allow room for the protocol header so that they get the array size they requested */
            static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
            ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong;
            if ( maxBytes < 0xffffffff - headerSize ) {
                maxBytes += headerSize;
            }
            else {
                maxBytes = 0xffffffff;
            }
            if ( maxBytes < MAX_TCP ) {
                errlogPrintf ( "cac: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP );
            }
            else {
                this->maxRecvBytesTCP = maxBytes;
            }
        }
        freeListInitPvt ( &this->tcpSmallRecvBufFreeList, MAX_TCP, 1 );
        if ( ! this->tcpSmallRecvBufFreeList ) {
            throw std::bad_alloc ();
        }

        freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 );
        if ( ! this->tcpLargeRecvBufFreeList ) {
            throw std::bad_alloc ();
        }
        unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes ();
        if ( bufsPerArray > 1u ) {
            maxContigFrames = bufsPerArray * 
                contiguousMsgCountWhichTriggersFlowControl;
        }
    }
    catch ( ... ) {
        osiSockRelease ();
        delete [] this->pUserName;
        if ( this->tcpSmallRecvBufFreeList ) {
            freeListCleanup ( this->tcpSmallRecvBufFreeList );
        }
        if ( this->tcpLargeRecvBufFreeList ) {
            freeListCleanup ( this->tcpLargeRecvBufFreeList );
        }
        this->timerQueue.release ();
        throw;
    }

    /*
     * load user configured tcp name server address list,
     * create virtual circuits, and add them to server table
     */
    ELLLIST dest, tmpList;

    ellInit ( & dest );
    ellInit ( & tmpList );

    addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_NAME_SERVERS, this->_serverPort, false );
    removeDuplicateAddresses ( &dest, &tmpList, 0 );

    epicsGuard < epicsMutex > guard ( this->mutex );

    while ( osiSockAddrNode *
        pNode = reinterpret_cast < osiSockAddrNode * > ( ellGet ( & dest ) ) ) {
        tcpiiu * piiu = NULL;
        SearchDestTCP * pdst = new SearchDestTCP ( *this, pNode->addr );
        this->registerSearchDest ( guard, * pdst );
        bool newIIU = findOrCreateVirtCircuit (
            guard, pNode->addr, cacChannel::priorityDefault,
            piiu, CA_UKN_MINOR_VERSION, pdst );
        free ( pNode );
        if ( newIIU ) {
            piiu->start ( guard );
        }
    }
}
Esempio n. 22
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);
}
Esempio n. 23
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;
            }
        }
    }
}
extern "C" void messageQueueTest(void *parm)
{
    unsigned int i;
    char cbuf[80];
    int len;
    int pass;
    int used;
    int want;

    epicsMessageQueue *q1 = new epicsMessageQueue(4, 20);

    testDiag("Simple single-thread tests:");
    i = 0;
    used = 0;
    testOk1(q1->pending() == 0);
    while (q1->trySend((void *)msg1, i ) == 0) {
        i++;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
    }
    testOk1(q1->pending() == 4);

    want = 0;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 3);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->trySend((void *)msg1, i++);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->trySend((void *)msg1, i++);
    testOk1(q1->pending() == 3);

    i = 3;
    while ((len = q1->receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
        --i;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
        want++;
        if (!testOk1((len == want) & (strncmp(msg1, cbuf, len) == 0)))
            testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    }
    testOk1(q1->pending() == 0);

    testDiag("Test sender timeout:");
    i = 0;
    used = 0;
    testOk1(q1->pending() == 0);
    while (q1->send((void *)msg1, i, 1.0 ) == 0) {
        i++;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
    }
    testOk1(q1->pending() == 4);

    want = 0;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 3);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->send((void *)msg1, i++, 1.0);

    want++;
    len = q1->receive(cbuf, sizeof cbuf);
    testOk1(q1->pending() == 2);
    if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
        testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    q1->send((void *)msg1, i++, 1.0);
    testOk1(q1->pending() == 3);

    i = 3;
    while ((len = q1->receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
        --i;
        testOk(q1->pending() == i, "q1->pending() == %d", i);
        want++;
        if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
            testDiag("wanted:%d '%.*s'   got:%d '%.*s'", want, want, msg1, len, len, cbuf);
    }
    testOk1(q1->pending() == 0);

    testDiag("Test receiver with timeout:");
    for (i = 0 ; i < 4 ; i++)
        testOk1 (q1->send((void *)msg1, i, 1.0) == 0);
    testOk1(q1->pending() == 4);
    for (i = 0 ; i < 4 ; i++)
        testOk(q1->receive((void *)cbuf, sizeof cbuf, 1.0) == (int)i,
            "q1->receive(...) == %d", i);
    testOk1(q1->pending() == 0);
    testOk1(q1->receive((void *)cbuf, sizeof cbuf, 1.0) < 0);
    testOk1(q1->pending() == 0);

    testDiag("Single receiver with invalid size, single sender tests:");
    epicsThreadCreate("Bad Receiver", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), badReceiver, q1);
    epicsThreadSleep(1.0);
    testOk(q1->send((void *)msg1, 10) == 0, "Send with waiting receiver");
    epicsThreadSleep(2.0);
    testOk(q1->send((void *)msg1, 10) == 0, "Send with no receiver");
    epicsThreadSleep(2.0);

    testDiag("Single receiver, single sender tests:");
    epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityHigh);
    epicsThreadCreate("Receiver one", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), receiver, q1);
    for (pass = 1 ; pass <= 3 ; pass++) {
        for (i = 0 ; i < 10 ; i++) {
            if (q1->trySend((void *)msg1, i) < 0)
                break;
            if (pass >= 3)
                epicsThreadSleep(0.5);
        }
        switch (pass) {
        case 1:
            if (i<6)
                testDiag("  priority-based scheduler, sent %d messages", i);
            epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityLow);
            break;
        case 2:
            if (i<10)
                testDiag("  scheduler not strict priority, sent %d messages", i);
            else
                testDiag("  strict priority scheduler, sent 10 messages");
            break;
        case 3:
            testOk(i == 10, "%d of 10 messages sent with sender pauses", i);
            break;
        }
        epicsThreadSleep(1.0);
    }

    /*
     * Single receiver, multiple sender tests
     */
    testDiag("Single receiver, multiple sender tests:");
    testDiag("This test takes 5 minutes...");
    epicsThreadCreate("Sender 1", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);
    epicsThreadCreate("Sender 2", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);
    epicsThreadCreate("Sender 3", epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);
    epicsThreadCreate("Sender 4", epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), sender, q1);

    epicsThreadSleep(300.0);

    testExit = 1;
}
Esempio n. 25
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 */
        }
    }
}
Esempio n. 26
0
void threadFunc_EC1_ANT_RT (void *param)
{
	ST_STD_device *pSTDmy = (ST_STD_device*) param;
	ST_EC1_ANT *pEC1_ANT;
	ST_MASTER *pMaster = NULL;

	epicsThreadId pthreadInfo;
	
	//int nFirst = 1;
	//int toggle = 1;
	
	pMaster = get_master();
	if(!pMaster)	return;

	pEC1_ANT = (ST_EC1_ANT *)pSTDmy->pUser;
	if( !pEC1_ANT ) {
		printf("ERROR! threadFunc_user_DAQ() has null pointer of pEC1_ANT.\n");
		return;
	}

#if USE_CPU_AFFINITY_RT	
	pthreadInfo = epicsThreadGetIdSelf();
	printf("%s: EPICS ID %p, pthreadID %lu\n", pthreadInfo->name, (void *)pthreadInfo, (unsigned long)pthreadInfo->tid);
	epicsThreadSetCPUAffinity( pthreadInfo, "5");
	epicsThreadSetPosixPriority(pthreadInfo, PRIOTY_EC1_ANT, "SCHED_FIFO");
#endif

	int		num_samples = 1;
	float	read_buf[num_samples];
	int		scans_read;

	while(TRUE) {
#if 0
		epicsEventWait (pSTDmy->ST_RTthread.threadEventId);

		//		pSTDmy->StatusDev |= TASK_WAIT_FOR_TRIGGER;
		//		notify_refresh_master_status();

		nFirst = 1;
		toggle = 1;
		printf("%s: Got epics RT Run event.\n", pSTDmy->taskName);
#endif

#if 0
		while(TRUE) {
			got	= read(pEC1_ANT->fd_event, &nval, 4);

			toggle = 0;

			pSTDmy->rtCnt++; 

			if( nFirst ) {
				send_master_stop_event();
				nFirst = 0;
			}
			
			if( pEC1_ANT->useScanIoRequest ) {
				scanIoRequest(pSTDmy->ioScanPvt_userCall);
			}

			if( !(pSTDmy->StatusDev & TASK_IN_PROGRESS ) )
			{
				pSTDmy->StatusDev &= ~TASK_WAIT_FOR_TRIGGER;
				printf("system stop!.. bye RT thread!\n");
				break;
			}
		}
#else
		while (TRUE) {
			// read scaled samples for synchronization with PCSRT1
			if (0 > (scans_read = pxi6259_read_ai (pEC1_ANT->channelFD, read_buf, num_samples))) {
				epicsThreadSleep (0.00001);
				continue;
			}

			kuDebug (kuDEBUG, "[EC1_ANT_RT] schedule RfmHandler ...\n");

			// schedule RfmHandler
			epicsEventSignal (pEC1_ANT->ctrlRunEventId);
		}
#endif

		if( pMaster->cUseAutoSave ) {
			//db_put("HICS_EC1_ANT_SEND_DATA", "1");
		}
	}
}
Esempio n. 27
0
/*
 * Process breakpoint
 *  Returns a zero if dbProcess() is to execute
 *  record support, a one if dbProcess() is to
 *  skip over record support.  See dbProcess().
 *
 *  1.  See if there is at least a breakpoint set somewhere
 *        in precord's lockset.  If not, return immediately.
 *  2.  Check the disable flag.
 *  3.  Add entry points to the queue for future stepping and
 *        schedule new entrypoints for the continuation task.
 *  4.  Check the pact flag.
 *  5.  Check to see if there is a breakpoint set in a record, and
 *        if so, turn on stepping mode.
 *  6.  If stepping mode is set, stop and report the breakpoint.
 */
int epicsShareAPI dbBkpt(dbCommon *precord)
{
  struct LS_LIST *pnode;
  struct EP_LIST *pqe;

 /*
  *  It is crucial that operations in dbBkpt() execute
  *    in the correct order or certain features in the
  *    breakpoint handler will not work as expected.
  */

 /*
  *  Take and give a semaphore to check for breakpoints
  *	every time a record is processed.  Slow.  Thank
  *	goodness breakpoint checking is turned off during
  *	normal operation.
  */
  epicsMutexMustLock(bkpt_stack_sem);
  FIND_LOCKSET(precord, pnode);
  epicsMutexUnlock(bkpt_stack_sem);

  if (pnode == NULL) {
    /* no breakpoints in precord's lockset */
     return(0);
  }

 /* Check disable flag */
  dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0);
  if (precord->disa == precord->disv) {
     /*
      *  Do not process breakpoints if the record is disabled,
      *    but allow disable alarms.  Alarms will be raised
      *    in dbProcess() because returning 0 allows dbProcess()
      *    to continue.  However processing will be prevented
      *    because disa and disv will be examined again in
      *    dbProcess(). Note that checking for pact will occur
      *    before checking for disa and disv in dbProcess().
      */
      return(0);
  }

 /*
  *  Queue entry points for future stepping.  The taskid comparison
  *    is used to determine if the source of processing is the
  *    continuation task or an external source. If it is an external
  *    source, queue its execution, but dump out of dbProcess without
  *    calling record support. 
  */
  if (pnode->taskid && (epicsThreadGetIdSelf() != pnode->taskid)) {
    /* CONTINUE TASK CANNOT ENTER HERE */

    /*
     *  Add an entry point to queue, if it does
     *    not already exist.
     */
     FIND_QUEUE_ENTRY(&pnode->ep_queue, pqe, precord);
 
     if (pqe == NULL) {

        pqe = (struct EP_LIST *) malloc(sizeof(struct EP_LIST));
        if (pqe == NULL)
             return(1);


        pqe->entrypoint = precord;
        pqe->count = 1;
        epicsTimeGetCurrent(&pqe->time);
        pqe->sched = 0;

#ifdef BKPT_DIAG
        printf("   BKPT> Adding entrypoint %s to queue\n", precord->name);
#endif

       /*
        *  Take semaphore, wait on continuation task
        */
        epicsMutexMustLock(bkpt_stack_sem);

       /* Add entry to queue */
        ellAdd(&pnode->ep_queue, (ELLNODE *)pqe);

        epicsMutexUnlock(bkpt_stack_sem);
     }
     else {
        if (pqe->count < MAX_EP_COUNT)
           pqe->count++;
     }

    /* check pact */
     if (! precord->pact) {
       /* schedule if pact not set */
        pqe->sched = 1;

       /*
        *  Release the semaphore, letting the continuation
        *     task begin execution of the new entrypoint.
        */ 
        epicsEventSignal(pnode->ex_sem);
     }
     return(1);
  }

 /*
  *  Don't mess with breakpoints if pact set!  Skip
  *    over rest of dbProcess() since we don't want
  *    alarms going off.  The pact flag is checked
  *    AFTER entry point queuing so that the record
  *    timing feature will work properly.
  */
  if (precord->pact)
     return(1);

 /* Turn on stepping mode if a breakpoint is found */
  if (precord->bkpt & BKPT_ON_MASK) {
     pnode->step = 1;

#ifdef BKPT_DIAG
     printf("   BKPT> Bkpt detected: %s\n", precord->name);
#endif
  }

 /*
  *  If we are currently stepping through the lockset,
  *    suspend task.
  */
  if (pnode->step) {
      printf("\n   BKPT> Stopped at:  %s  within Entrypoint:  %s\n-> ",
                 precord->name, pnode->current_ep->name);

      pnode->precord = precord;

     /* Move current lockset to top of stack */
      ellDelete(&lset_stack, (ELLNODE *)pnode);
      ellInsert(&lset_stack, NULL, (ELLNODE *)pnode);
     /*
      *  Unlock database while the task suspends itself.  This
      *   is done so that dbb() dbd() dbc() dbs() may be used
      *   when the task is suspended.  Scan tasks that also
      *   use the scan lock feature will not be hung during
      *   a breakpoint, so that records in other locksets will
      *   continue to be processed.  Cross your fingers, this
      *   might actually work !
      */
      epicsMutexUnlock(bkpt_stack_sem);
      dbScanUnlock(precord);
      epicsThreadSuspendSelf();
      dbScanLock(precord);
      epicsMutexMustLock(bkpt_stack_sem);
   }
   return(0);
}
Esempio n. 28
0
void threadFunc_RTcore_RT(void *param)
{
	ST_STD_device *pSTDdev = (ST_STD_device*) param;
	ST_RTcore *pRTcore;
//	ST_MASTER *pMaster = NULL;
	ST_STD_device *pSTDRMchk = NULL;
	ST_RMCHK *pRMCHK;	

	epicsThreadId pthreadInfo;

	
	int got;
	int nval;
	int nFirst = 1;

	
//	pMaster = get_master();
//	if(!pMaster)	return;

	pRTcore = (ST_RTcore *)pSTDdev->pUser;
	if( !pRTcore ) {
		printf("ERROR! threadFunc_user_DAQ() has null pointer of pRTcore.\n");
		return;
	}

	
/********************************************/
/* to get RFM, RMcheck device */
	pSTDRMchk = get_STDev_from_type(STR_DEVICE_TYPE_2);
	if( !pSTDRMchk ) {
		printf("ERROR! threadFunc_RTcore_RT() has null pointer of Target device.\n");
		return;
	} else {
		printf("target RMchk: %p, eventID:%d\n", pSTDRMchk, pSTDRMchk->ST_DAQThread.threadEventId );
	}
	pRMCHK = (ST_RMCHK *)pSTDRMchk->pUser;
	if( !pRMCHK ) {
		printf("ERROR! threadFunc_RTcore_RT() has null pointer of pRMCHK.\n");
		return;
	}
/*********************/

#if USE_CPU_AFFINITY_RT	
	pthreadInfo = epicsThreadGetIdSelf();
	printf("%s: EPICS ID %p, pthreadID %lu\n", pthreadInfo->name, (void *)pthreadInfo, (unsigned long)pthreadInfo->tid);
	epicsThreadSetCPUAffinity( pthreadInfo, AFFINITY_RTCORE_RT);
	epicsThreadSetPosixPriority(pthreadInfo, PRIOTY_RTCORE_RT, "SCHED_FIFO");
#endif

	while(TRUE) {
		epicsEventWait( pSTDdev->ST_RTthread.threadEventId);
		nFirst = 1;
		rt_toggle = 1;
		printf("%s: Got epics RT Run event.\n", pSTDdev->taskName);
		
		while(TRUE) {
			got	= read(pRTcore->fd_event, &nval, 4);
#if USE_KERNEL_ACK_HIGH
			WRITE32(pRTcore->base0 + 0x4, 0x1);
#endif
#if USE_KERNEL_ACK_LOW
			WRITE32(pRTcore->base0 + 0x4, 0x0);
#endif

			if( rt_toggle ) { /* Half clock,   10Khz, when 20Khz */
				rt_toggle = 0;
				epicsEventSignal( pSTDdev->ST_DAQThread.threadEventId );
				epicsEventSignal( pSTDRMchk->ST_DAQThread.threadEventId );
			} 
			else rt_toggle = 1;

#if USE_DIVIDER_A
			if( (pSTDdev->stdCoreCnt % DIVIDER_A) == 0) { // value is 4, 5KHz if Mclk is 20Khz 
				epicsEventSignal( pRTcore->ST_DivThreadA.threadEventId );

			}
#endif
#if USE_DIVIDER_B
			if( (pSTDdev->stdCoreCnt % DIVIDER_B) == 0) { // value is 20, 1KHz if Mclk is 20Khz 
				epicsEventSignal( pRTcore->ST_DivThreadB.threadEventId );
			}
#endif
			pSTDdev->stdCoreCnt++; 
		/* not use scanIoRequest() */

			if( nFirst ) {
				send_master_stop_event();
				nFirst = 0;
			}

			if( !(pSTDdev->StatusDev & TASK_IN_PROGRESS ) )
			{
				pSTDdev->StatusDev &= ~TASK_WAIT_FOR_TRIGGER;
				printf("system stop!.. bye RT thread!\n");
				break;
			}
		}
	}
}
Esempio n. 29
0
void threadFunc_RTcore_DAQ(void *param)
{
	ST_STD_device *pSTDdev = (ST_STD_device*) param;
	ST_RTcore *pRTcore;
	ST_MASTER *pMaster = NULL;

	ST_STD_device *pSTDRMchk = NULL;
	ST_RMCHK *pRMCHK;	
	
	epicsThreadId pthreadInfo;
	ST_User_Buf_node queueData;
	ST_buf_node *pbufferNode = NULL;

	
	pMaster = get_master();
	if(!pMaster)	return;

	if( !pSTDdev ) {
		printf("ERROR! threadFunc_user_DAQ() has null pointer of STD device.\n");
		return;
	}

	pRTcore = (ST_RTcore *)pSTDdev->pUser;
	if( !pRTcore ) {
		printf("ERROR! threadFunc_user_DAQ() has null pointer of pRTcore.\n");
		return;
	}
/* get RFM device ******************************************* */
	pSTDRMchk = get_STDev_from_type(STR_DEVICE_TYPE_2);
	if( !pSTDRMchk ) {
		printf("ERROR! threadFunc_RTcore_DAQ() has null pointer of Dev2.\n");
		return;
	} else {
		printf("target RMchk: %p, eventID:%d\n", pSTDRMchk, pSTDRMchk->ST_DAQThread.threadEventId );
	}
	pRMCHK = (ST_RMCHK *)pSTDRMchk->pUser;
	if( !pRMCHK ) {
		printf("ERROR! threadFunc_RTcore_RT() has null pointer of pRMCHK.\n");
		return;
	}
/*********************************************************** */

#if USE_CPU_AFFINITY_RT	
	pthreadInfo = epicsThreadGetIdSelf();
/*	printf("%s: EPICS ID %p, pthreadID %lu\n", pthreadInfo->name, (void *)pthreadInfo, (unsigned long)pthreadInfo->tid); */
	epicsThreadSetCPUAffinity( pthreadInfo, AFFINITY_RTCORE_DAQ);
	epicsThreadSetPosixPriority(pthreadInfo, PRIOTY_RTCORE_DAQ, "SCHED_FIFO");
#endif

#if USE_RTCORE_DAQRING
	epicsThreadSleep(1.0);
	pbufferNode = (ST_buf_node *)ellFirst(pSTDdev->pList_BufferNode);
	ellDelete(pSTDdev->pList_BufferNode, &pbufferNode->node);
#endif

	while(TRUE) {
		epicsEventWait( pSTDdev->ST_DAQThread.threadEventId);

#if USE_RTCORE_DAQ_HIGH
		WRITE32(pRTcore->base0 + 0x4, 0x1);
#endif
#if USE_RTCORE_DAQ_LOW
		WRITE32(pRTcore->base0 + 0x4, 0x0);
#endif

#if USE_RTCORE_DAQRING
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 0] = pRMCHK->mapBuf[RM_PCS_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 1] = pRMCHK->mapBuf[RM_PF1_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 2] = pRMCHK->mapBuf[RM_PF2_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 3] = pRMCHK->mapBuf[RM_PF3U_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 4] = pRMCHK->mapBuf[RM_PF3L_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 5] = pRMCHK->mapBuf[RM_PF4U_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 6] = pRMCHK->mapBuf[RM_PF4L_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 7] = pRMCHK->mapBuf[RM_PF5U_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 8] = pRMCHK->mapBuf[RM_PF5L_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 9] = pRMCHK->mapBuf[RM_PF6U_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 10] = pRMCHK->mapBuf[RM_PF6L_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 11] = pRMCHK->mapBuf[RM_PF7_CNT/4];
		pbufferNode->data[pRTcore->cntDAQ_loop * LOOP_ELM + 12] = pRMCHK->mapBuf[RM_IVC_CNT/4];

		
//		pRTcore->cntDAQ++;

		pRTcore->cntDAQ_loop++;
		pRTcore->cntAccum += LOOP_ELM;


		if( pRTcore->cntDAQ_loop >= LOOP_CNT ) {
			queueData.pNode		= pbufferNode;
			queueData.timeStamp	= 0x0;
			epicsMessageQueueSend(pSTDdev->ST_RingBufThread.threadQueueId, (void*) &queueData, sizeof(ST_User_Buf_node));

			pbufferNode = (ST_buf_node *)ellFirst(pSTDdev->pList_BufferNode);
			ellDelete(pSTDdev->pList_BufferNode, &pbufferNode->node);

			pRTcore->cntDAQ_loop = 0;

		}
#endif	
		pSTDdev->stdDAQCnt++;

		if( pRTcore->useScanIoRequest )
			scanIoRequest(pSTDdev->ioScanPvt_userCall);
	}
}
Esempio n. 30
0
void threadFunc_RTcore_RingBuf(void *param)
{
	int i, ellCnt;
	epicsThreadId pthreadInfo;

	ST_STD_device *pSTDdev = (ST_STD_device*) param;

	ST_User_Buf_node queueData;
	ST_buf_node *pbufferNode;	
	ST_RTcore *pRTcore;


	pRTcore = (ST_RTcore *)pSTDdev->pUser;

#if 0
	epicsPrintf("\n %s: pSTDdev: %p, p16aiss8ao4: %p , pST_BuffThread: %p\n",pSTDdev->taskName, pSTDdev, p16aiss8ao4, pST_BufThread );
#endif

	for(i = 0; i< MAX_RING_BUF_NUM; i++)
	{
		ST_buf_node *pbufferNode1 = NULL;
		pbufferNode1 = (ST_buf_node*) malloc(sizeof(ST_buf_node));
		if(!pbufferNode1) {
			epicsPrintf("\n>>> threadFunc_user_RingBuf: malloc(sizeof(ST_buf_node))... fail\n");
			return;
		}
		ellAdd(pSTDdev->pList_BufferNode, &pbufferNode1->node);
	}
	epicsPrintf(" %s: create %d node (size:%dKB)\n", pSTDdev->ST_RingBufThread.threadName, 
																		MAX_RING_BUF_NUM,
																		sizeof(ST_buf_node)/1024 );
#if 0
	epicsPrintf(">>> %s, ellCnt:%d\n", pringThreadConfig->threadName, 
												ellCount(p16aiss8ao4->pdrvBufferConfig->pbufferList));
#endif

#if USE_CPU_AFFINITY_RT	
	pthreadInfo = epicsThreadGetIdSelf();
/*	printf("%s: EPICS ID %p, pthreadID %lu\n", pthreadInfo->name, (void *)pthreadInfo, (unsigned long)pthreadInfo->tid); */
	epicsThreadSetCPUAffinity( pthreadInfo, AFFINITY_RTCORE_RING);
	epicsThreadSetPosixPriority(pthreadInfo, PRIOTY_RTCORE_RING, "SCHED_FIFO");
#endif

	
	while(TRUE) 
	{
		epicsMessageQueueReceive(pSTDdev->ST_RingBufThread.threadQueueId, (void*) &queueData, sizeof(ST_User_Buf_node));

		pbufferNode = queueData.pNode;


/*		fwrite( pbufferNode->data,  sizeof(unsigned int), LOOP_CNT*LOOP_ELM, pRTcore->fp_raw); */
		
		
		ellAdd(pSTDdev->pList_BufferNode, &pbufferNode->node);
		ellCnt = ellCount(pSTDdev->pList_BufferNode);
/*		printf("RTcore_RingBuf, ellCnt: %d\n", ellCnt); */


	} /* while(TRUE)  */

	return;
}