int main()

in benchmarks/cyclictest/cyclictest.c [837:1114]


int main(int argc, char *argv[])
{
  int i;
  int ret;
  struct thread_param_s **params = NULL;
  struct thread_stats_s **stats = NULL;
  struct sigevent event;
  struct timer_notify_s tnotify;
  uint32_t maxtimeout_timer;
  uint32_t reqtimeout_timer;

  running = true;
  config.clock = CLOCK_MONOTONIC;
  config.distance = 500;
  config.duration = 0;
  config.histogram = 0;
  config.histofall = 0;
  config.interval = 1000;
  config.loops = 0;
  config.threads = 1;
  config.prio = 0;
  config.policy = SCHED_FIFO;
  config.meas_method = M_GETTIME;
  config.wait_method = W_NANOSLEEP;
  config.timer_dev = NULL;
  config.quiet = false;

  if (!parse_args(argc, argv))
    {
      print_help();
      return ERROR;
    }

  if (!check_args_logic())
    {
      print_help();
      return ERROR;
    }

  /* Timer must be configured */

  if (config.wait_method == W_DEVTIMER || config.meas_method == M_TIMER_API)
    {
      timerfd = open(config.timer_dev, O_RDWR);
      if (timerfd < 0)
        {
          perror("Failed to open the device timer");
          return ERROR;
        }

      /* Configure the timer notification */

      polltimer[0].fd     = timerfd;
      polltimer[0].events = POLLIN;

      /* Fill in the notify struct
       * We do not want any signalling. But we must configure it,
       * because without it the timer will not start.
       */

      memset(&event, 0, sizeof(event));
      event.sigev_notify = SIGEV_NONE;

      tnotify.periodic = true;
      tnotify.pid      = getpid();
      tnotify.event    = event;

      /* Now set timeout of the timer.
       * This depends on several factors.
       *
       * If wait_method == W_DEVTIMER, the timeout is set to config.interval
       * (to achieve periodic operation). The extra time is measured by
       * NANOSLEEP or the timer itself. If the timer is used, the timer
       * zeroes itself when the timeout is reached, so we just get
       * the timer value after poll has stopped blocking.
       *
       * If wait_method != W_DEVTIMER, we must set the timeout to at least
       * the double of the maximum of all thread intervals
       * (if you're not sure, please consult Claude Shannon).
       *
       * This raises the question: what if wait_method == W_DEVTIMER
       * and meas_method == W_TIMER_API and the thread wakes up later
       * then the timer's timeout? The solution is to have a different
       * timer which runs slower and can measure overruns.
       * But this would overcomplicate things.
       */

      if (config.wait_method == W_DEVTIMER)
        {
          reqtimeout_timer = config.interval;
        }
      else if (config.wait_method == W_NANOSLEEP)
        {
          /* Multiply by 3 instead of 2, just to be sure */

          reqtimeout_timer = 3 * (config.interval +
                             (config.threads - 1) * config.distance);
        }

      ret = ioctl(timerfd, TCIOC_MAXTIMEOUT,
                  (unsigned long)((uintptr_t)&maxtimeout_timer));
      if (ret < 0)
        {
          perror("TCIOC_MAXTIMEOUT");
          goto errtimer;
        }

      if (reqtimeout_timer > maxtimeout_timer)
        {
          fprintf(stderr, "The timer cannot measure such periods!\n");
          goto errtimer;
        }

      ret = ioctl(timerfd, TCIOC_SETTIMEOUT,
                  (unsigned long)reqtimeout_timer);
      if (ret < 0)
        {
          perror("TCIOC_SETTIMEOUT");
          goto errtimer;
        }

      ret = ioctl(timerfd, TCIOC_NOTIFICATION,
                  (unsigned long)((uintptr_t)&tnotify));
      if (ret < 0)
        {
          perror("TCIOC_NOTIFICATION");
          goto errtimer;
        }

      /*  If the timer is used only for measurement, start it here, otherwise
       *  start it only in one thread.
       */

      if (config.wait_method != W_DEVTIMER)
        {
          ret = ioctl(timerfd, TCIOC_START);
          if (ret < 0)
            {
              perror("TCIOC_START");
              goto errtimer;
            }
        }
    }

  params = calloc(config.threads, sizeof(struct thread_param_s *));
  if (params == NULL)
    {
      perror("params");
      ret = ERROR;
      goto main_error;
    }

  stats  = calloc(config.threads, sizeof(struct thread_stats_s *));
  if (stats == NULL)
    {
      perror("stats");
      ret = ERROR;
      goto main_error;
    }

  for (i = 0; i < config.threads; ++i)
    {
      params[i] = malloc(sizeof(struct thread_param_s));
      if (params == NULL)
        {
          perror("params[i]");
          ret = ERROR;
          goto main_error;
        }

      stats[i]  = malloc(sizeof(struct thread_stats_s));
      if (params == NULL)
        {
          perror("stats[i]");
          ret = ERROR;
          goto main_error;
        }

      stats[i]->hist_array = calloc(config.histogram, sizeof(long));
      if (stats[i]->hist_array == NULL)
        {
          perror("hist_array");
          ret = ERROR;
          goto main_error;
        }

      init_thread_param(params[i], config.interval, config.loops,
                 config.policy, config.prio, stats[i], config.clock);

      pthread_create(&stats[i]->id, NULL, testthread, params[i]);
      config.interval += config.distance;
      if (config.prio > 1)
        {
          config.prio--;
        }
    }

  while (running)
    {
      /* Periodically update the output */

      usleep(100 * 1000);
      int ended = 0;
      for (i = 0; i < config.threads; ++i)
        {
          if (!config.quiet)
            {
              print_stat(params[i], i);
            }

          if (stats[i]->ended)
            {
              ended += 1;
            }
        }

      if (ended == config.threads)
        {
          running = false;
        }
      else if (!config.quiet)
        {
          printf("\x1B[%dA", config.threads);
        }
    }

  for (i = 0; i < config.threads; ++i)
    {
      pthread_join(stats[i]->id, NULL);
    }

  if (config.histogram)
    {
      print_hist(params, config.threads);
    }

  ret = OK;
  if (config.wait_method == W_DEVTIMER || config.meas_method == M_TIMER_API)
    {
      ret = ioctl(timerfd, TCIOC_STOP);
      if (ret < 0)
        {
          perror("TCIOC_STOP");
          ret = ERROR;
        }

      close(timerfd);
    }

main_error:
  if (stats != NULL)
    {
      for (i = 0; i < config.threads; ++i)
        {
          if (params[i] != NULL)
            {
              free(params[i]);
            }

          if (stats[i] != NULL)
            {
              if (stats[i]->hist_array != NULL)
                {
                  free(stats[i]->hist_array);
                }

              free(stats[i]);
            }
        }
    }

  free(stats);
  return ret;

errtimer:
  close(timerfd);
  return ERROR;
}