gpsd-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [gpsd-dev] Updated docs on NTP segment management


From: Eric S. Raymond
Subject: Re: [gpsd-dev] Updated docs on NTP segment management
Date: Wed, 18 Feb 2015 18:19:06 -0500
User-agent: Mutt/1.5.23 (2014-03-12)

Gary E. Miller <address@hidden>:
> > The SHM export code I wrote using this technique seems to work.
> 
> 'seems to work' does not give me warm and fuzzy feelings.  Several had
> similar thoughts on the gpsmon PPS, and we know how that turned out.

You should have seen my detailed reply to Hal Murray on this by now.

What I invented for the job turned out to be a belt-and-suspenders
variation on a fairly well-known (and sound) technique called
"optimistic locking" (I was told this in comments when I blogged about
it).

It'll work unless both (a) the memory-barrier instructions don't
barrier, and (b) the bitblt instruction that memcpy compiles to is
interruptible.

Maybe this will prove enlightening:

shmexport.c:

void shm_update(struct gps_context_t *context, struct gps_data_t *gpsdata)
/* export an update to all listeners */
{
    if (context->shmexport != NULL)
    {
        static int tick;
        volatile struct shmexport_t *shared = (struct shmexport_t 
*)context->shmexport;

        ++tick;
        /*
         * Following block of instructions must not be reordered, otherwise
         * havoc will ensue.
         *
         * This is a simple optimistic-concurrency technique.  We write
         * the second bookend first, then the data, then the first bookend.
         * Reader copies what it sees in normal order; that way, if we
         * start to write the segment during the read, the second bookend will
         * get clobbered first and the data can be detected as bad.
         */
        shared->bookend2 = tick;
        memory_barrier();
        memcpy((void *)((char *)context->shmexport + offsetof(struct 
shmexport_t, gpsdata)),
               (void *)gpsdata,
               sizeof(struct gps_data_t));
        memory_barrier();
#ifndef USE_QT
        shared->gpsdata.gps_fd = SHM_PSEUDO_FD;
#else
        shared->gpsdata.gps_fd = (void *)(intptr_t)SHM_PSEUDO_FD;
#endif /* USE_QT */
        memory_barrier();
        shared->bookend1 = tick;
    }
}

libgps_shm.c:

int gps_shm_read(struct gps_data_t *gpsdata)
/* read an update from the shared-memory segment */
{
    /*@ -compdestroy */
    if (gpsdata->privdata == NULL)
        return -1;
    else
    {
        int before, after;
        void *private_save = gpsdata->privdata;
        volatile struct shmexport_t *shared = (struct shmexport_t 
*)PRIVATE(gpsdata)->shmseg;
        struct gps_data_t noclobber;

        /*
         * Following block of instructions must not be reordered,
         * otherwise havoc will ensue.  The memory_barrier() call
         * should prevent reordering of the data accesses.
         *
         * This is a simple optimistic-concurrency technique.  We wrote
         * the second bookend first, then the data, then the first bookend.
         * Reader copies what it sees in normal order; that way, if we
         * start to write the segment during the read, the second bookend will
         * get clobbered first and the data can be detected as bad.
         */
        before = shared->bookend1;
        memory_barrier();
        (void)memcpy((void *)&noclobber,
                     (void *)&shared->gpsdata,
                     sizeof(struct gps_data_t));
        memory_barrier();
        after = shared->bookend2;

        if (before != after)
            return 0;
        else {
            (void)memcpy((void *)gpsdata,
                         (void *)&noclobber,
                         sizeof(struct gps_data_t));
            /address@hidden@*/gpsdata->privdata = private_save;
            PRIVATE(gpsdata)->tick = after;
            if ((gpsdata->set & REPORT_IS)!=0) {
                if (gpsdata->fix.mode >= 2)
                    gpsdata->status = STATUS_FIX;
                else
                    gpsdata->status = STATUS_NO_FIX;
                gpsdata->set = STATUS_SET;
            }
            return (int)sizeof(struct gps_data_t);
        }
    }
    /*@ +compdestroy */
}



-- 
                <a href="http://www.catb.org/~esr/";>Eric S. Raymond</a>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]