epicsTime roundTimeDown(const epicsTime &time, double secs)
{
    if (secs <= 0.0)
        return time;
    struct local_tm_nano_sec tm;
    unsigned long round, full_secs;
    if (secs < 1.0)
    {
        epicsTimeStamp stamp = (epicsTimeStamp)time;
        round =(unsigned long)(secs * NSEC);
        stamp.nsec = (stamp.nsec / round)*round;
        return epicsTime(stamp);
    }
    else if (secs < secsPerDay)
    {
    full_secs = (unsigned long)secs;
        epicsTimeStamp stamp = (epicsTimeStamp)time;
        // secs >= 1.0, so nanosecs are 0
        round = stamp.secPastEpoch / full_secs;
        stamp.secPastEpoch = (epicsUInt32) (round*secs);
        stamp.nsec = 0;
        return epicsTime(stamp);
    }
    else if (secs < secsPerMonth)
    {
    full_secs = (unsigned long)secs;
        tm = (local_tm_nano_sec) time;
        round = full_secs/secsPerDay;
        tm.nSec = 0;
        tm.ansi_tm.tm_sec = 0;
        tm.ansi_tm.tm_min = 0;
        tm.ansi_tm.tm_hour = 0;
        tm.ansi_tm.tm_mday = (tm.ansi_tm.tm_mday / round) * round;
    }
    else if (secs < secsPerYear)
    {
    full_secs = (unsigned long)secs;
        tm = (local_tm_nano_sec) time;
        round = full_secs/secsPerMonth;
        tm.nSec = 0;
        tm.ansi_tm.tm_sec = 0;
        tm.ansi_tm.tm_min = 0;
        tm.ansi_tm.tm_hour = 0;
        tm.ansi_tm.tm_mday = 1;
        tm.ansi_tm.tm_mon = (tm.ansi_tm.tm_mon / round) * round;
    }
    else
    {
        tm = (local_tm_nano_sec) time;
        tm.nSec = 0;
        tm.ansi_tm.tm_sec = 0;
        tm.ansi_tm.tm_min = 0;
        tm.ansi_tm.tm_hour = 0;
        tm.ansi_tm.tm_mday = 1;
        tm.ansi_tm.tm_mon = 0;
    }
    // TODO: round weeks, fortnights?
    return epicsTime(tm);
}
Exemple #2
0
 epicsShareFunc void epicsShareAPI epicsTimeAddSeconds (epicsTimeStamp *pDest, double seconds)
 {
     try {
         *pDest = epicsTime (*pDest) + seconds;
     }
     catch ( ... ) {
         *pDest = epicsTime ();
     }
 }
Exemple #3
0
 epicsShareFunc int epicsShareAPI epicsTimeNotEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
 {
     try {
         return epicsTime (*pLeft) != epicsTime (*pRight);
     }
     catch ( ... ) {
         return 1;
     }
 }
Exemple #4
0
 epicsShareFunc int epicsShareAPI epicsTimeLessThanEqual (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
 {
     try {
         return epicsTime (*pLeft) <= epicsTime (*pRight);
     }
     catch ( ... ) {
         return 0;
     }
 }
Exemple #5
0
 epicsShareFunc int epicsShareAPI epicsTimeGreaterThan (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
 {
     try {
         return epicsTime (*pLeft) > epicsTime (*pRight);
     }
     catch ( ... ) {
         return 0;
     }
 }
Exemple #6
0
 epicsShareFunc double epicsShareAPI epicsTimeDiffInSeconds (const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
 {
     try {
         return epicsTime (*pLeft) - epicsTime (*pRight);
     }
     catch (...) {
         return - DBL_MAX;
     }
 }
epicsTime::epicsTime (const gm_tm_nano_sec &tm)
{
    int year = tm.ansi_tm.tm_year + 1900;
    int month = tm.ansi_tm.tm_mon;
    if (month > 11) {
        year += month / 12;
        month %= 12;
    } else if (month < 0) {
        int years_diff = (-month + 11) / 12;
        year  -= years_diff;
        month += 12 * years_diff;
    }
    month++;

    int day = tm.ansi_tm.tm_mday;
    int day_of_year = days_from_1jan(year, month, day);
    int days_since_epoch = days_from_1970(year) + day_of_year;

    time_t_wrapper ansiTimeTicks;
    ansiTimeTicks.ts = ((days_since_epoch
        * 24 + tm.ansi_tm.tm_hour)
        * 60 + tm.ansi_tm.tm_min)
        * 60 + tm.ansi_tm.tm_sec;

    *this = epicsTime(ansiTimeTicks);
    this->addNanoSec(tm.nSec);
}
Exemple #8
0
//
// epicsTime::operator + (const double &rhs)
//
// rhs has units seconds
//
epicsTime epicsTime::operator + (const double &rhs) const
{
    unsigned long newSec, newNSec, secOffset, nSecOffset;
    double fnsec;

    if (rhs >= 0) {
        secOffset = static_cast <unsigned long> (rhs);
        fnsec = rhs - secOffset;
        nSecOffset = static_cast <unsigned long> ( (fnsec * nSecPerSec) + 0.5 );

        newSec = this->secPastEpoch + secOffset; // overflow expected
        newNSec = this->nSec + nSecOffset;
        if (newNSec >= nSecPerSec) {
            newSec++; // overflow expected
            newNSec -= nSecPerSec;
        }
    }
    else {
        secOffset = static_cast <unsigned long> (-rhs);
        fnsec = rhs + secOffset;
        nSecOffset = static_cast <unsigned long> ( (-fnsec * nSecPerSec) + 0.5 );

        newSec = this->secPastEpoch - secOffset; // underflow expected
        if (this->nSec>=nSecOffset) {
            newNSec = this->nSec - nSecOffset;
        }
        else {
            // borrow
            newSec--; // underflow expected
            newNSec = this->nSec + (nSecPerSec - nSecOffset);
        }
    }
    return epicsTime (newSec, newNSec);
}
Exemple #9
0
//
// epicsTime (const struct timespec &ts)
//
epicsTime::epicsTime (const struct timespec &ts)
{
    time_t_wrapper ansiTimeTicks;

    ansiTimeTicks.ts = ts.tv_sec;
    *this = epicsTime (ansiTimeTicks);
    this->addNanoSec (ts.tv_nsec);
}
Exemple #10
0
//
// epicsTime (const local_tm_nano_sec &tm)
//
epicsTime::epicsTime (const local_tm_nano_sec &tm)
{
    static const time_t mktimeFailure = static_cast <time_t> (-1);
    time_t_wrapper ansiTimeTicks;
    struct tm tmp = tm.ansi_tm;

    ansiTimeTicks.ts = mktime (&tmp);
    if (ansiTimeTicks.ts ==  mktimeFailure) {
        throwWithLocation ( formatProblemWithStructTM () );
    }

    *this = epicsTime (ansiTimeTicks);

    unsigned long nSecAdj = tm.nSec % nSecPerSec;
    unsigned long secAdj = tm.nSec / nSecPerSec;
    *this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj );
}
Exemple #11
0
epicsTime epicsTime::getEvent (const epicsTimeEvent &event)
{
    epicsTimeStamp current;
    int status = epicsTimeGetEvent (&current, event);
    if (status) {
        throwWithLocation ( unableToFetchCurrentTime () );
    }
    return epicsTime ( current );
}
Exemple #12
0
 epicsShareFunc void epicsShareAPI epicsTimeShow (const epicsTimeStamp *pTS, unsigned interestLevel)
 {
     try {
         epicsTime(*pTS).show (interestLevel);
     }
     catch ( ... ) {
         printf ( "Invalid epicsTimeStamp\n" );
     }
 }
Exemple #13
0
 epicsShareFunc size_t epicsShareAPI epicsTimeToStrftime (char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
 {
     try {
         return epicsTime(*pTS).strftime (pBuff, bufLength, pFormat);
     }
     catch ( ... ) {
         return 0;
     }
 }
Exemple #14
0
 epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc)
 {
     try {
         *pDest = epicsTime (*pSrc);
     }
     catch (...) {
         return epicsTimeERROR;
     }
     return epicsTimeOK;
 }
Exemple #15
0
 epicsShareFunc int epicsShareAPI epicsTimeFromTimeval (epicsTimeStamp *pDest, const struct timeval *pSrc)
 {
     try {
         *pDest = epicsTime (*pSrc);
     }
     catch (...) {
         return epicsTimeERROR;
     }
     return epicsTimeOK;
 }
Exemple #16
0
 //
 // ANSI C interface
 //
 // its too bad that these cant be implemented with inline functions 
 // at least when running the GNU compiler
 //
 epicsShareFunc int epicsShareAPI epicsTimeToTime_t (time_t *pDest, const epicsTimeStamp *pSrc)
 {
     try {
         time_t_wrapper dst = epicsTime (*pSrc);
         *pDest = dst.ts;
     }
     catch (...) {
         return epicsTimeERROR;
     }
     return epicsTimeOK;
 }
Exemple #17
0
void bhe::unregisterIIU ( 
    epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
{
    guard.assertIdenticalMutex ( this->mutex );
    if ( this->pIIU == & iiu ) {
        this->pIIU = 0;
        this->timeStamp = epicsTime();
        this->averagePeriod = - DBL_MAX;
        logBeacon ( "ui", this->averagePeriod, epicsTime::getCurrent () );
    }
}
    static int osdTimeGetCurrent (epicsTimeStamp *pDest)
    {
        struct timeval tv;
        struct timezone tz;

        if (gettimeofday (&tv, &tz))
            return epicsTimeERROR;

        *pDest = epicsTime(tv);
        return epicsTimeOK;
    }
Exemple #19
0
static void format_time(const epicsTime &time, stdString &text)
{
    if (only_millisecs)
    {
        epicsTimeStamp stamp = time;
        stamp.nsec = ((stamp.nsec + 500000) / 1000000) * 1000000;
        epicsTime2string(epicsTime(stamp), text);
        text = text.substr(0, 23);
        return;
    }
    epicsTime2string(time, text);
}
Exemple #20
0
 epicsShareFunc int epicsShareAPI epicsTimeFromTime_t (epicsTimeStamp *pDest, time_t src)
 {
     try {
         time_t_wrapper dst;
         dst.ts = src;
         *pDest = epicsTime ( dst );
     }
     catch (...) {
         return epicsTimeERROR;
     }
     return epicsTimeOK;
 }
Exemple #21
0
 epicsShareFunc int epicsShareAPI epicsTimeToGMTM (struct tm *pDest, unsigned long *pNSecDest, const epicsTimeStamp *pSrc)
 {
     try {
         gm_tm_nano_sec gmtmns = epicsTime (*pSrc);
         *pDest = gmtmns.ansi_tm;
         *pNSecDest = gmtmns.nSec;
     }
     catch (...) {
         return epicsTimeERROR;
     }
     return epicsTimeOK;
 }
Exemple #22
0
 epicsShareFunc int epicsShareAPI epicsTimeFromTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
 {
     try {
         local_tm_nano_sec tmns;
         tmns.ansi_tm = *pSrc;
         tmns.nSec = nSecSrc;
         *pDest = epicsTime (tmns);
     }
     catch (...) {
         return epicsTimeERROR;
     }
     return epicsTimeOK;
 }
//
// epicsTime (const local_tm_nano_sec &tm)
//
epicsTime::epicsTime (const local_tm_nano_sec &tm)
{
    struct tm tmp = tm.ansi_tm;
    time_t_wrapper ansiTimeTicks = { mktime (&tmp) };

    static const time_t mktimeError = static_cast <time_t> (-1);
    if (ansiTimeTicks.ts == mktimeError) {
        throwWithLocation ( formatProblemWithStructTM () );
    }

    *this = epicsTime(ansiTimeTicks);
    this->addNanoSec(tm.nSec);
}
Exemple #24
0
bool cac::findOrCreateVirtCircuit ( 
    epicsGuard < epicsMutex > & guard, const osiSockAddr & addr,
    unsigned priority, tcpiiu *& piiu, unsigned minorVersionNumber,
    SearchDestTCP * pSearchDest )
{
    guard.assertIdenticalMutex ( this->mutex );
    bool newIIU = false;

    if ( piiu ) {
        if ( ! piiu->alive ( guard ) ) {
            return newIIU;
        }
    }
    else {
        try {
            autoPtrFreeList < tcpiiu, 32, epicsMutexNOOP > pnewiiu (
                    this->freeListVirtualCircuit,
                    new ( this->freeListVirtualCircuit ) tcpiiu ( 
                        *this, this->mutex, this->cbMutex, this->notify, this->connTMO, 
                        this->timerQueue, addr, this->comBufMemMgr, minorVersionNumber, 
                        this->ipToAEngine, priority, pSearchDest ) );

            bhe * pBHE = this->beaconTable.lookup ( addr.ia );
            if ( ! pBHE ) {
                pBHE = new ( this->bheFreeList ) 
                                    bhe ( this->mutex, epicsTime (), 0u, addr.ia );
                if ( this->beaconTable.add ( *pBHE ) < 0 ) {
                    return newIIU;
                }
            }
            this->serverTable.add ( *pnewiiu );
            this->circuitList.add ( *pnewiiu );
            this->iiuExistenceCount++;
            pBHE->registerIIU ( guard, *pnewiiu );
            piiu = pnewiiu.release ();
            newIIU = true;
        }
        catch ( std :: exception & except ) {
            errlogPrintf ( 
                "CAC: exception during virtual circuit creation \"%s\"\n",
                except.what () );
            return newIIU;
        }
        catch ( ... ) {
            errlogPrintf ( 
                "CAC: Nonstandard exception during virtual circuit creation\n" );
            return newIIU;
        }
    }
    return newIIU;
}
Exemple #25
0
//
// epicsTime (const struct timeval &ts)
//
epicsTime::epicsTime (const struct timeval &ts)
{
    time_t_wrapper ansiTimeTicks;
    // On Posix systems timeval :: tv_sec is a time_t so this can be 
    // a direct assignement. On other systems I dont know that we can
    // guarantee that time_t and timeval :: tv_sec will have the
    // same epoch or have the same scaling factor to discrete seconds.
    // For example, on windows time_t changed recently to a 64 bit 
    // quantity but timeval is still a long. That can cause problems
    // on 32 bit systems. So technically, we should have an os 
    // dependent conversion between time_t and timeval :: tv_sec?
    ansiTimeTicks.ts = ts.tv_sec;
    *this = epicsTime (ansiTimeTicks);
    this->addNanoSec (ts.tv_usec * nSecPerUSec);
}
Exemple #26
0
/*
 * update beacon period
 *
 * updates beacon period, and looks for beacon anomalies
 */
bool bhe::updatePeriod ( 
    epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime, 
    const epicsTime & currentTime, ca_uint32_t beaconNumber, 
    unsigned protocolRevision )
{
    guard.assertIdenticalMutex ( this->mutex );

    //
    // this block is enetered if the beacon was created as a side effect of
    // creating a connection and so we dont yet know the first beacon time 
    // and  sequence number
    //
    if ( this->timeStamp == epicsTime () ) {
        if ( CA_V410 ( protocolRevision ) ) {
            this->lastBeaconNumber = beaconNumber;
        }

        this->beaconAnomalyNotify ( guard );

        /* 
         * this is the 1st beacon seen - the beacon time stamp
         * was not initialized during BHE create because
         * a TCP/IP connection created the beacon.
         * (nothing to do but set the beacon time stamp and return)
         */
        this->timeStamp = currentTime;

        logBeacon ( "fb", - DBL_MAX, currentTime );

        return false;
    }

    // 1) detect beacon duplications due to redundant routes
    // 2) detect lost beacons due to input queue overrun or damage
    if ( CA_V410 ( protocolRevision ) ) {
        unsigned beaconSeqAdvance;
        if ( beaconNumber >= this->lastBeaconNumber ) {
            beaconSeqAdvance = beaconNumber - this->lastBeaconNumber;
        }
        else {
            beaconSeqAdvance = ( ca_uint32_max - this->lastBeaconNumber ) + beaconNumber;
        }
        this->lastBeaconNumber = beaconNumber;

        // throw out sequence numbers just prior to, or the same as, the last one received 
        // (this situation is probably caused by a temporary duplicate route )
        if ( beaconSeqAdvance == 0 ||  beaconSeqAdvance > ca_uint32_max - 256 ) {
            logBeaconDiscard ( beaconSeqAdvance, currentTime );
            return false;
        }

        // throw out sequence numbers that jump forward by only a few numbers 
        // (this situation is probably caused by a duplicate route 
        // or a beacon due to input queue overun)
        if ( beaconSeqAdvance > 1 &&  beaconSeqAdvance < 4 ) {
            logBeaconDiscard ( beaconSeqAdvance, currentTime );
            return false;
        }
    }

    // compute the beacon period (if we have seen at least two beacons)
    bool netChange = false;
    double currentPeriod = currentTime - this->timeStamp;

    if ( this->averagePeriod < 0.0 ) {
        double totalRunningTime;

        this->beaconAnomalyNotify ( guard );

        /*
         * this is the 2nd beacon seen. We cant tell about
         * the change in period at this point so we just
         * initialize the average period and return.
         */
        this->averagePeriod = currentPeriod;

        logBeacon ( "fp", currentPeriod, currentTime );


        /*
         * ignore beacons seen for the first time shortly after
         * init, but do not ignore beacons arriving with a short
         * period because the IOC was rebooted soon after the 
         * client starts up.
         */
        totalRunningTime = this->timeStamp - programBeginTime;
        if ( currentPeriod <= totalRunningTime ) {
            netChange = true;
        }
    }
    else {

        /*
         * Is this an IOC seen because of a restored
         * network segment? 
         *
         * It may be possible to get false triggers here 
         * if the client is busy, but this does not cause
         * problems because the echo response will tell us 
         * that the server is available
         */
        if ( currentPeriod >= this->averagePeriod * 1.25 ) {

            /* 
             * trigger on any missing beacon 
             * if connected to this server
             */    
            this->beaconAnomalyNotify ( guard );

            if ( currentPeriod >= this->averagePeriod * 3.25 ) {
                /* 
                 * trigger on any 3 contiguous missing beacons 
                 * if not connected to this server
                 */
                netChange = true;
            }
            logBeacon ( "bah", currentPeriod, currentTime );
        }

        /*
         * Is this an IOC seen because of an IOC reboot
         * (beacon come at a higher rate just after the
         * IOC reboots). Lower tolarance here because we
         * dont have to worry about lost beacons.
         *
         * It may be possible to get false triggers here 
         * if the client is busy, but this does not cause
         * problems because the echo response will tell us 
         * that the server is available
         */
        else if ( currentPeriod <= this->averagePeriod * 0.80 ) {
            this->beaconAnomalyNotify ( guard );
            netChange = true;
            logBeacon ( "bal", currentPeriod, currentTime );
        }
        else if ( this->pIIU ) {
            // update state of health for active virtual circuits 
            // if the beacon looks ok
            this->pIIU->beaconArrivalNotify ( guard );
            logBeacon ( "vb", currentPeriod, currentTime );
        }

        // update a running average period
        this->averagePeriod = currentPeriod * 0.125 + 
            this->averagePeriod * 0.875;
    }

    this->timeStamp = currentTime;

    return netChange;
}
const RawValue::Data *OldDataReader::find(
    const stdString &channel_name, const epicsTime *start)
{
    this->channel_name = channel_name;
    OldDirectoryFileIterator dfi = index.find(channel_name);
    if (!dfi.isValid())
    {
        LOG_MSG ("OldDataReader: Cannot find '%s' in index\n",
                 channel_name.c_str());
        return 0;
    }
    if (start)
    {   // look for time, start at end
        header = getHeader(index.getDirname(),
                           dfi.entry.data.last_file,
                           dfi.entry.data.last_offset);
        if (!header)
        {
            LOG_MSG("OldDataReader: No data for '%s'\n",
                    channel_name.c_str());
            return 0;
        }
        ///
        stdString txt;
        epicsTime2string(epicsTime(header->data.begin_time), txt);
        printf("header: %s\n", txt.c_str());
        ///
        while (epicsTime(header->data.begin_time) > *start)
        {
            if (!header->read_prev())
            {
                header = 0;
                LOG_MSG("OldDataReader: No data for '%s'\n",
                        channel_name.c_str());
                return 0;
            }
            epicsTime2string(epicsTime(header->data.begin_time), txt);
            printf("header: %s\n", txt.c_str());
        }
        // Have header <= *start
    }
    else
    {   // Start at first buffer
        header = getHeader(index.getDirname(),
                           dfi.entry.data.first_file,
                           dfi.entry.data.first_offset);
        if (!header)
        {
            LOG_MSG("OldDataReader: No data for '%s'\n",
                    channel_name.c_str());
            return 0;
        }
    }
    dbr_type = header->data.dbr_type;
    dbr_count = header->data.dbr_count;
    ctrl_info.read(header->datafile,
                   header->data.ctrl_info_offset);
    raw_value_size = RawValue::getSize(dbr_type, dbr_count);
    data = RawValue::allocate(dbr_type, dbr_count, 1);
    val_idx = 0;
    type_changed = false;
    ctrl_info_changed = false;
    if (start)
    {
        // Binary search for best matching sample.
        size_t low = 0, high = header->data.num_samples - 1;
        FileOffset offset0 =
            header->offset + sizeof(DataHeader::DataHeaderData);
        FileOffset offset;
        epicsTime stamp;
        ///
        stdString start_txt;
        epicsTime2string(*start, start_txt);
        printf("Start: %s\n", start_txt.c_str());
        ///
        while (true)
        {
            // Pick middle value, rounded up
            val_idx = low+high;
            if (val_idx & 1)
                ++val_idx;
            val_idx /= 2;
            
            offset = offset0 + val_idx * raw_value_size;
            RawValue::read(this->dbr_type, this->dbr_count,
                           raw_value_size, data,
                           header->datafile, offset);
            stamp = RawValue::getTime(data);
            ///
            stdString stamp_txt;
            epicsTime2string(stamp, stamp_txt);
            printf("Index %u: %s\n", (unsigned int)val_idx, stamp_txt.c_str());
            ///
            if (high-low <= 1)
            {   // The intervall can't shrink further,
                // idx = (low+high)/2 == high.
                // Which value's best?
                LOG_ASSERT(val_idx == high);
                if (stamp > *start)
                {
                    val_idx = low;
                    return next();
                }
                // else: val_idx == high is good & already in data
                break;
            }
            if (stamp == *start)
                break;
            else if (stamp > *start)
                high = val_idx;
            else
                low = val_idx;
        }   
        ++val_idx;
        return data;
    }
    else
        return next();
}    
epicsTime DataWriter::getLastStamp()
{
    if (header)
        return epicsTime(header->data.end_time);
    return nullTime;
}
static void ntpshmupdate(void*, epicsUInt32 event)
{
    if(event!=ntpShm.event) {
        incFail(); return;
    }

    epicsTimeStamp evrts;
    if(!ntpShm.evr->getTimeStamp(&evrts, 0)) // read current wall clock time
    {
        // no valid device time
        incFail(); return;
    }

    struct timeval cputs;
    if(gettimeofday(&cputs, 0))
    {
        // no valid cpu time?
        incFail(); return;
    }

    struct timeval evrts_posix;
    evrts_posix.tv_sec = evrts.secPastEpoch + POSIX_TIME_AT_EPICS_EPOCH;
    evrts_posix.tv_usec = evrts.nsec / 1000;
    // correct for bias in truncation
    if(evrts.nsec % 1000 >= 500) {
        evrts_posix.tv_usec += 1;
        if(evrts_posix.tv_usec>=1000000) {
            evrts_posix.tv_sec += 1;
            evrts_posix.tv_usec = 0;
        }
    }

    // volatile operations aren't really enough, but will have to do.
    volatile shmSegment* seg=ntpShm.seg;

    seg->valid = 0;
    SYNC();
    int c1 = seg->count++;
    seg->stampSec = evrts_posix.tv_sec;
    seg->stampUsec = evrts_posix.tv_usec;
    seg->rxSec = cputs.tv_sec;
    seg->rxUsec = cputs.tv_usec;
    int c2 = seg->count++;
    if(c1+1!=c2) {
        fprintf(stderr, "ntpshmupdate: possible collision with another writer!\n");
        incFail(); return;
    }
    seg->valid = 1;
    SYNC();

    epicsMutexMustLock(ntpShm.ntplock);
    ntpShm.lastValid = true;
    ntpShm.numOk++;
    ntpShm.lastStamp = evrts;
    ntpShm.lastRx = epicsTime(cputs);
    epicsMutexUnlock(ntpShm.ntplock);

    scanIoRequest(ntpShm.lastUpdate);

    if(!ntpShm.notify_1strx) {
        fprintf(stderr, "First update ready for NTPD\n");
        ntpShm.notify_1strx = 1;
    }

    return; // normal exit
}