Blame refclock_shm.c

Packit 96c956
/*
Packit 96c956
  chronyd/chronyc - Programs for keeping computer clocks accurate.
Packit 96c956
Packit 96c956
 **********************************************************************
Packit 96c956
 * Copyright (C) Miroslav Lichvar  2009
Packit 96c956
 * 
Packit 96c956
 * This program is free software; you can redistribute it and/or modify
Packit 96c956
 * it under the terms of version 2 of the GNU General Public License as
Packit 96c956
 * published by the Free Software Foundation.
Packit 96c956
 * 
Packit 96c956
 * This program is distributed in the hope that it will be useful, but
Packit 96c956
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 96c956
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 96c956
 * General Public License for more details.
Packit 96c956
 * 
Packit 96c956
 * You should have received a copy of the GNU General Public License along
Packit 96c956
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit 96c956
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Packit 96c956
 * 
Packit 96c956
 **********************************************************************
Packit 96c956
Packit 96c956
  =======================================================================
Packit 96c956
Packit 96c956
  SHM refclock driver.
Packit 96c956
Packit 96c956
  */
Packit 96c956
Packit 96c956
#include "config.h"
Packit 96c956
Packit 96c956
#include "sysincl.h"
Packit 96c956
Packit 96c956
#include "refclock.h"
Packit 96c956
#include "logging.h"
Packit 96c956
#include "util.h"
Packit 96c956
Packit 96c956
#define SHMKEY 0x4e545030
Packit 96c956
Packit 96c956
struct shmTime {
Packit 96c956
  int    mode; /* 0 - if valid set
Packit 96c956
                *       use values, 
Packit 96c956
                *       clear valid
Packit 96c956
                * 1 - if valid set 
Packit 96c956
                *       if count before and after read of values is equal,
Packit 96c956
                *         use values 
Packit 96c956
                *       clear valid
Packit 96c956
                */
Packit 96c956
  volatile int count;
Packit 96c956
  time_t clockTimeStampSec;
Packit 96c956
  int    clockTimeStampUSec;
Packit 96c956
  time_t receiveTimeStampSec;
Packit 96c956
  int    receiveTimeStampUSec;
Packit 96c956
  int    leap;
Packit 96c956
  int    precision;
Packit 96c956
  int    nsamples;
Packit 96c956
  volatile int valid;
Packit 96c956
  int    clockTimeStampNSec;
Packit 96c956
  int    receiveTimeStampNSec;
Packit 96c956
  int    dummy[8]; 
Packit 96c956
};
Packit 96c956
Packit 96c956
static int shm_initialise(RCL_Instance instance) {
Packit 96c956
  const char *options[] = {"perm", NULL};
Packit 96c956
  int id, param, perm;
Packit 96c956
  char *s;
Packit 96c956
  struct shmTime *shm;
Packit 96c956
Packit 96c956
  RCL_CheckDriverOptions(instance, options);
Packit 96c956
Packit 96c956
  param = atoi(RCL_GetDriverParameter(instance));
Packit 96c956
  s = RCL_GetDriverOption(instance, "perm");
Packit 96c956
  perm = s ? strtol(s, NULL, 8) & 0777 : 0600;
Packit 96c956
Packit 96c956
  id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | perm);
Packit 96c956
  if (id == -1) {
Packit 96c956
    LOG_FATAL("shmget() failed : %s", strerror(errno));
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
   
Packit 96c956
  shm = (struct shmTime *)shmat(id, 0, 0);
Packit 96c956
  if ((long)shm == -1) {
Packit 96c956
    LOG_FATAL("shmat() failed : %s", strerror(errno));
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  RCL_SetDriverData(instance, shm);
Packit 96c956
  return 1;
Packit 96c956
}
Packit 96c956
Packit 96c956
static void shm_finalise(RCL_Instance instance)
Packit 96c956
{
Packit 96c956
  shmdt(RCL_GetDriverData(instance));
Packit 96c956
}
Packit 96c956
Packit 96c956
static int shm_poll(RCL_Instance instance)
Packit 96c956
{
Packit 96c956
  struct timespec receive_ts, clock_ts;
Packit 96c956
  struct shmTime t, *shm;
Packit 96c956
  double offset;
Packit 96c956
Packit 96c956
  shm = (struct shmTime *)RCL_GetDriverData(instance);
Packit 96c956
Packit 96c956
  t = *shm;
Packit 96c956
  
Packit 96c956
  if ((t.mode == 1 && t.count != shm->count) ||
Packit 96c956
    !(t.mode == 0 || t.mode == 1) || !t.valid) {
Packit 96c956
    DEBUG_LOG("SHM sample ignored mode=%d count=%d valid=%d",
Packit 96c956
        t.mode, t.count, t.valid);
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  shm->valid = 0;
Packit 96c956
Packit 96c956
  receive_ts.tv_sec = t.receiveTimeStampSec;
Packit 96c956
  clock_ts.tv_sec = t.clockTimeStampSec;
Packit 96c956
Packit 96c956
  if (t.clockTimeStampNSec / 1000 == t.clockTimeStampUSec &&
Packit 96c956
      t.receiveTimeStampNSec / 1000 == t.receiveTimeStampUSec) {
Packit 96c956
    receive_ts.tv_nsec = t.receiveTimeStampNSec;
Packit 96c956
    clock_ts.tv_nsec = t.clockTimeStampNSec;
Packit 96c956
  } else {
Packit 96c956
    receive_ts.tv_nsec = 1000 * t.receiveTimeStampUSec;
Packit 96c956
    clock_ts.tv_nsec = 1000 * t.clockTimeStampUSec;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  UTI_NormaliseTimespec(&clock_ts);
Packit 96c956
  UTI_NormaliseTimespec(&receive_ts);
Packit 96c956
  offset = UTI_DiffTimespecsToDouble(&clock_ts, &receive_ts);
Packit 96c956
Packit 96c956
  return RCL_AddSample(instance, &receive_ts, offset, t.leap);
Packit 96c956
}
Packit 96c956
Packit 96c956
RefclockDriver RCL_SHM_driver = {
Packit 96c956
  shm_initialise,
Packit 96c956
  shm_finalise,
Packit 96c956
  shm_poll
Packit 96c956
};