Beispiel #1
0
struct timespec
dtotimespec (double sec)
{
  double min_representable = TYPE_MINIMUM (time_t);
  double max_representable =
    ((TYPE_MAXIMUM (time_t) * (double) TIMESPEC_RESOLUTION
      + (TIMESPEC_RESOLUTION - 1))
     / TIMESPEC_RESOLUTION);

  if (! (min_representable < sec))
    return make_timespec (TYPE_MINIMUM (time_t), 0);
  else if (! (sec < max_representable))
    return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_RESOLUTION - 1);
  else
    {
      time_t s = sec;
      double frac = TIMESPEC_RESOLUTION * (sec - s);
      long ns = frac;
      ns += ns < frac;
      s += ns / TIMESPEC_RESOLUTION;
      ns %= TIMESPEC_RESOLUTION;

      if (ns < 0)
        {
          s--;
          ns += TIMESPEC_RESOLUTION;
        }

      return make_timespec (s, ns);
    }
}
Beispiel #2
0
struct timespec
dtotimespec (double sec)
{
  if (! (TYPE_MINIMUM (time_t) < sec))
    return make_timespec (TYPE_MINIMUM (time_t), 0);
  else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t)))
    return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_RESOLUTION - 1);
  else
    {
      time_t s = sec;
      double frac = TIMESPEC_RESOLUTION * (sec - s);
      long ns = frac;
      ns += ns < frac;
      s += ns / TIMESPEC_RESOLUTION;
      ns %= TIMESPEC_RESOLUTION;

      if (ns < 0)
        {
          s--;
          ns += TIMESPEC_RESOLUTION;
        }

      return make_timespec (s, ns);
    }
}
Beispiel #3
0
static void *
tf (void *arg)
{
  pthread_rwlock_t *r = arg;

  /* Timeout: 0.3 secs.  */
  struct timespec ts_start;
  xclock_gettime (CLOCK_REALTIME, &ts_start);
  const struct timespec ts_timeout = timespec_add (ts_start,
                                                   make_timespec (0, 300000000));

  TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
  puts ("child: timedwrlock failed with ETIMEDOUT");

  TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout);

  struct timespec ts_invalid;
  xclock_gettime (CLOCK_REALTIME, &ts_invalid);
  ts_invalid.tv_sec += 10;
  /* Note that the following operation makes ts invalid.  */
  ts_invalid.tv_nsec += 1000000000;

  TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);

  puts ("child: timedwrlock failed with EINVAL");

  return NULL;
}
Beispiel #4
0
struct atimer *
start_atimer (enum atimer_type type, struct timespec timestamp,
	      atimer_callback fn, void *client_data)
{
  struct atimer *t;
  sigset_t oldset;

  /* Round TIME up to the next full second if we don't have
     itimers.  */
#ifndef HAVE_SETITIMER
  if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t))
    timestamp = make_timespec (timestamp.tv_sec + 1, 0);
#endif /* not HAVE_SETITIMER */

  /* Get an atimer structure from the free-list, or allocate
     a new one.  */
  if (free_atimers)
    {
      t = free_atimers;
      free_atimers = t->next;
    }
  else
    t = xmalloc (sizeof *t);

  /* Fill the atimer structure.  */
  memset (t, 0, sizeof *t);
  t->type = type;
  t->fn = fn;
  t->client_data = client_data;

  block_atimers (&oldset);

  /* Compute the timer's expiration time.  */
  switch (type)
    {
    case ATIMER_ABSOLUTE:
      t->expiration = timestamp;
      break;

    case ATIMER_RELATIVE:
      t->expiration = timespec_add (current_timespec (), timestamp);
      break;

    case ATIMER_CONTINUOUS:
      t->expiration = timespec_add (current_timespec (), timestamp);
      t->interval = timestamp;
      break;
    }

  /* Insert the timer in the list of active atimers.  */
  schedule_atimer (t);
  unblock_atimers (&oldset);

  /* Arrange for a SIGALRM at the time the next atimer is ripe.  */
  set_alarm ();

  return t;
}
Beispiel #5
0
static void
set_alarm (void)
{
  if (atimers)
    {
#ifdef HAVE_SETITIMER
      struct itimerval it;
#endif
      struct timespec now, interval;

#ifdef HAVE_ITIMERSPEC
      if (0 <= timerfd || alarm_timer_ok)
	{
	  struct itimerspec ispec;
	  ispec.it_value = atimers->expiration;
	  ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0;
# ifdef HAVE_TIMERFD
	  if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0)
	    {
	      add_timer_wait_descriptor (timerfd);
	      return;
	    }
# endif
	  if (alarm_timer_ok
	      && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0)
	    return;
	}
#endif

      /* Determine interval till the next timer is ripe.
	 Don't set the interval to 0; this disables the timer.  */
      now = current_timespec ();
      interval = (timespec_cmp (atimers->expiration, now) <= 0
		  ? make_timespec (0, 1000 * 1000)
		  : timespec_sub (atimers->expiration, now));

#ifdef HAVE_SETITIMER

      memset (&it, 0, sizeof it);
      it.it_value = make_timeval (interval);
      setitimer (ITIMER_REAL, &it, 0);
#else /* not HAVE_SETITIMER */
      alarm (max (interval.tv_sec, 1));
#endif /* not HAVE_SETITIMER */
    }
}
Beispiel #6
0
struct timespec
timespec_add (struct timespec a, struct timespec b)
{
  time_t rs = a.tv_sec;
  time_t bs = b.tv_sec;
  int ns = a.tv_nsec + b.tv_nsec;
  int nsd = ns - TIMESPEC_RESOLUTION;
  int rns = ns;
  time_t tmin = TYPE_MINIMUM (time_t);
  time_t tmax = TYPE_MAXIMUM (time_t);

  if (0 <= nsd)
    {
      rns = nsd;
      if (bs < tmax)
        bs++;
      else if (rs < 0)
        rs++;
      else
        goto high_overflow;
    }

  /* INT_ADD_WRAPV is not appropriate since time_t might be unsigned.
     In theory time_t might be narrower than int, so plain
     INT_ADD_OVERFLOW does not suffice.  */
  if (! INT_ADD_OVERFLOW (rs, bs) && tmin <= rs + bs && rs + bs <= tmax)
    rs += bs;
  else
    {
      if (rs < 0)
        {
          rs = tmin;
          rns = 0;
        }
      else
        {
        high_overflow:
          rs = tmax;
          rns = TIMESPEC_RESOLUTION - 1;
        }
    }

  return make_timespec (rs, rns);
}
Beispiel #7
0
struct timespec
timespec_add (struct timespec a, struct timespec b)
{
    time_t rs = a.tv_sec;
    time_t bs = b.tv_sec;
    int ns = a.tv_nsec + b.tv_nsec;
    int nsd = ns - TIMESPEC_RESOLUTION;
    int rns = ns;

    if (0 <= nsd)
    {
        rns = nsd;
        if (rs == TYPE_MAXIMUM (time_t))
        {
            if (0 <= bs)
                goto high_overflow;
            bs++;
        }
        else
            rs++;
    }

    if (INT_ADD_OVERFLOW (rs, bs))
    {
        if (rs < 0)
        {
            rs = TYPE_MINIMUM (time_t);
            rns = 0;
        }
        else
        {
high_overflow:
            rs = TYPE_MAXIMUM (time_t);
            rns = TIMESPEC_RESOLUTION - 1;
        }
    }
    else
        rs += bs;

    return make_timespec (rs, rns);
}
Beispiel #8
0
struct timespec
timespec_sub (struct timespec a, struct timespec b)
{
  time_t rs = a.tv_sec;
  time_t bs = b.tv_sec;
  int ns = a.tv_nsec - b.tv_nsec;
  int rns = ns;

  if (ns < 0)
    {
      rns = ns + TIMESPEC_RESOLUTION;
      if (rs == TYPE_MINIMUM (time_t))
        {
          if (bs <= 0)
            goto low_overflow;
          bs--;
        }
      else
        rs--;
    }

  if (INT_SUBTRACT_OVERFLOW (rs, bs))
    {
      if (rs < 0)
        {
        low_overflow:
          rs = TYPE_MINIMUM (time_t);
          rns = 0;
        }
      else
        {
          rs = TYPE_MAXIMUM (time_t);
          rns = TIMESPEC_RESOLUTION - 1;
        }
    }
  else
    rs -= bs;

  return make_timespec (rs, rns);
}
Beispiel #9
0
static void
debug_timer_callback (struct atimer *t)
{
  struct timespec now = current_timespec ();
  struct atimer_result *r = (struct atimer_result *) t->client_data;
  int result = timespec_cmp (now, r->expected);

  if (result < 0)
    /* Too early.  */
    r->intime = 0;
  else if (result >= 0)
    {
#ifdef HAVE_SETITIMER
      struct timespec delta = timespec_sub (now, r->expected);
      /* Too late if later than expected + 0.02s.  FIXME:
	 this should depend from system clock resolution.  */
      if (timespec_cmp (delta, make_timespec (0, 20000000)) > 0)
	r->intime = 0;
      else
#endif /* HAVE_SETITIMER */
	r->intime = 1;
    }
}
Beispiel #10
0
static enum profiler_cpu_running
setup_cpu_timer (Lisp_Object sampling_interval)
{
  struct sigaction action;
  struct itimerval timer;
  struct timespec interval;
  int billion = 1000000000;

  if (! RANGED_INTEGERP (1, sampling_interval,
			 (TYPE_MAXIMUM (time_t) < EMACS_INT_MAX / billion
			  ? ((EMACS_INT) TYPE_MAXIMUM (time_t) * billion
			     + (billion - 1))
			  : EMACS_INT_MAX)))
    return NOT_RUNNING;

  current_sampling_interval = XINT (sampling_interval);
  interval = make_timespec (current_sampling_interval / billion,
			    current_sampling_interval % billion);
  emacs_sigaction_init (&action, deliver_profiler_signal);
  sigaction (SIGPROF, &action, 0);

#ifdef HAVE_ITIMERSPEC
  if (! profiler_timer_ok)
    {
      /* System clocks to try, in decreasing order of desirability.  */
      static clockid_t const system_clock[] = {
#ifdef CLOCK_THREAD_CPUTIME_ID
	CLOCK_THREAD_CPUTIME_ID,
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
	CLOCK_PROCESS_CPUTIME_ID,
#endif
#ifdef CLOCK_MONOTONIC
	CLOCK_MONOTONIC,
#endif
	CLOCK_REALTIME
      };
      int i;
      struct sigevent sigev;
      sigev.sigev_value.sival_ptr = &profiler_timer;
      sigev.sigev_signo = SIGPROF;
      sigev.sigev_notify = SIGEV_SIGNAL;

      for (i = 0; i < ARRAYELTS (system_clock); i++)
	if (timer_create (system_clock[i], &sigev, &profiler_timer) == 0)
	  {
	    profiler_timer_ok = 1;
	    break;
	  }
    }

  if (profiler_timer_ok)
    {
      struct itimerspec ispec;
      ispec.it_value = ispec.it_interval = interval;
      if (timer_settime (profiler_timer, 0, &ispec, 0) == 0)
	return TIMER_SETTIME_RUNNING;
    }
#endif

#ifdef HAVE_SETITIMER
  timer.it_value = timer.it_interval = make_timeval (interval);
  if (setitimer (ITIMER_PROF, &timer, 0) == 0)
    return SETITIMER_RUNNING;
#endif

  return NOT_RUNNING;
}
Beispiel #11
0
	r->intime = 0;
      else
#endif /* HAVE_SETITIMER */
	r->intime = 1;
    }
}

DEFUN ("debug-timer-check", Fdebug_timer_check, Sdebug_timer_check, 0, 0, 0,
       doc: /* Run internal self-tests to check timers subsystem.
Return t if all self-tests are passed, nil otherwise.  */)
  (void)
{
  int i, ok;
  struct atimer *timer;
  struct atimer_result *results[MAXTIMERS];
  struct timespec t = make_timespec (0, 0);

  /* Arm MAXTIMERS relative timers to trigger with 0.1s intervals.  */
  for (i = 0; i < MAXTIMERS; i++)
    {
      results[i] = xmalloc (sizeof (struct atimer_result));
      t = timespec_add (t, make_timespec (0, 100000000));
      results[i]->expected = timespec_add (current_timespec (), t);
      results[i]->intime = -1;
      timer = start_atimer (ATIMER_RELATIVE, t,
			    debug_timer_callback, results[i]);
    }

#ifdef HAVE_TIMERFD
  /* Wait for 1s but process timers.  */
  wait_reading_process_output (1, 0, 0, false, Qnil, NULL, 0);
Beispiel #12
0
int
xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
	   struct timespec *timeout, sigset_t *sigmask)
{
  fd_set all_rfds, all_wfds;
  struct timespec tmo;
  struct timespec *tmop = timeout;

  GMainContext *context;
  bool have_wfds = wfds != NULL;
  GPollFD gfds_buf[128];
  GPollFD *gfds = gfds_buf;
  int gfds_size = ARRAYELTS (gfds_buf);
  int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1;
  bool context_acquired = false;
  int i, nfds, tmo_in_millisec, must_free = 0;
  bool need_to_dispatch;

  context = g_main_context_default ();
  context_acquired = g_main_context_acquire (context);
  /* FIXME: If we couldn't acquire the context, we just silently proceed
     because this function handles more than just glib file descriptors.
     Note that, as implemented, this failure is completely silent: there is
     no feedback to the caller.  */

  if (rfds) all_rfds = *rfds;
  else FD_ZERO (&all_rfds);
  if (wfds) all_wfds = *wfds;
  else FD_ZERO (&all_wfds);

  n_gfds = (context_acquired
	    ? g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
				    gfds, gfds_size)
	    : -1);

  if (gfds_size < n_gfds)
    {
      /* Avoid using SAFE_NALLOCA, as that implicitly refers to the
	 current thread.  Using xnmalloc avoids thread-switching
	 problems here.  */
      gfds = xnmalloc (n_gfds, sizeof *gfds);
      must_free = 1;
      gfds_size = n_gfds;
      n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
				     gfds, gfds_size);
    }

  for (i = 0; i < n_gfds; ++i)
    {
      if (gfds[i].events & G_IO_IN)
        {
          FD_SET (gfds[i].fd, &all_rfds);
          if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
        }
      if (gfds[i].events & G_IO_OUT)
        {
          FD_SET (gfds[i].fd, &all_wfds);
          if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
          have_wfds = true;
        }
    }

  if (must_free)
    xfree (gfds);

  if (n_gfds >= 0 && tmo_in_millisec >= 0)
    {
      tmo = make_timespec (tmo_in_millisec / 1000,
			   1000 * 1000 * (tmo_in_millisec % 1000));
      if (!timeout || timespec_cmp (tmo, *timeout) < 0)
	tmop = &tmo;
    }

  fds_lim = max_fds + 1;
  nfds = thread_select (pselect, fds_lim,
			&all_rfds, have_wfds ? &all_wfds : NULL, efds,
			tmop, sigmask);
  if (nfds < 0)
    retval = nfds;
  else if (nfds > 0)
    {
      for (i = 0; i < fds_lim; ++i)
        {
          if (FD_ISSET (i, &all_rfds))
            {
              if (rfds && FD_ISSET (i, rfds)) ++retval;
              else ++our_fds;
            }
          else if (rfds)
            FD_CLR (i, rfds);

          if (have_wfds && FD_ISSET (i, &all_wfds))
            {
              if (wfds && FD_ISSET (i, wfds)) ++retval;
              else ++our_fds;
            }
          else if (wfds)
            FD_CLR (i, wfds);

          if (efds && FD_ISSET (i, efds))
            ++retval;
        }
    }

  /* If Gtk+ is in use eventually gtk_main_iteration will be called,
     unless retval is zero.  */
#ifdef USE_GTK
  need_to_dispatch = retval == 0;
#else
  need_to_dispatch = true;
#endif
  if (need_to_dispatch && context_acquired)
    {
      int pselect_errno = errno;
      /* Prevent g_main_dispatch recursion, that would occur without
         block_input wrapper, because event handlers call
         unblock_input.  Event loop recursion was causing Bug#15801.  */
      block_input ();
      while (g_main_context_pending (context))
        g_main_context_dispatch (context);
      unblock_input ();
      errno = pselect_errno;
    }

  if (context_acquired)
    g_main_context_release (context);

  /* To not have to recalculate timeout, return like this.  */
  if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0))
    {
      retval = -1;
      errno = EINTR;
    }

  return retval;
}
Beispiel #13
0
int
xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
	   struct timespec const *timeout, sigset_t const *sigmask)
{
  fd_set all_rfds, all_wfds;
  struct timespec tmo;
  struct timespec const *tmop = timeout;

  GMainContext *context;
  int have_wfds = wfds != NULL;
  GPollFD gfds_buf[128];
  GPollFD *gfds = gfds_buf;
  int gfds_size = ARRAYELTS (gfds_buf);
  int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1;
  int i, nfds, tmo_in_millisec;
  bool need_to_dispatch;
  USE_SAFE_ALLOCA;

  context = g_main_context_default ();

  if (rfds) all_rfds = *rfds;
  else FD_ZERO (&all_rfds);
  if (wfds) all_wfds = *wfds;
  else FD_ZERO (&all_wfds);

  n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
				 gfds, gfds_size);
  if (gfds_size < n_gfds)
    {
      SAFE_NALLOCA (gfds, sizeof *gfds, n_gfds);
      gfds_size = n_gfds;
      n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
				     gfds, gfds_size);
    }

  for (i = 0; i < n_gfds; ++i)
    {
      if (gfds[i].events & G_IO_IN)
        {
          FD_SET (gfds[i].fd, &all_rfds);
          if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
        }
      if (gfds[i].events & G_IO_OUT)
        {
          FD_SET (gfds[i].fd, &all_wfds);
          if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
          have_wfds = 1;
        }
    }

  SAFE_FREE ();

  if (tmo_in_millisec >= 0)
    {
      tmo = make_timespec (tmo_in_millisec / 1000,
			   1000 * 1000 * (tmo_in_millisec % 1000));
      if (!timeout || timespec_cmp (tmo, *timeout) < 0)
	tmop = &tmo;
    }

  fds_lim = max_fds + 1;
  nfds = pselect (fds_lim, &all_rfds, have_wfds ? &all_wfds : NULL,
		  efds, tmop, sigmask);

  if (nfds < 0)
    retval = nfds;
  else if (nfds > 0)
    {
      for (i = 0; i < fds_lim; ++i)
        {
          if (FD_ISSET (i, &all_rfds))
            {
              if (rfds && FD_ISSET (i, rfds)) ++retval;
              else ++our_fds;
            }
          else if (rfds)
            FD_CLR (i, rfds);

          if (have_wfds && FD_ISSET (i, &all_wfds))
            {
              if (wfds && FD_ISSET (i, wfds)) ++retval;
              else ++our_fds;
            }
          else if (wfds)
            FD_CLR (i, wfds);

          if (efds && FD_ISSET (i, efds))
            ++retval;
        }
    }

  /* If Gtk+ is in use eventually gtk_main_iteration will be called,
     unless retval is zero.  */
#ifdef USE_GTK
  need_to_dispatch = retval == 0;
#else
  need_to_dispatch = true;
#endif
  if (need_to_dispatch)
    {
      int pselect_errno = errno;
      /* Prevent g_main_dispatch recursion, that would occur without
         block_input wrapper, because event handlers call
         unblock_input.  Event loop recursion was causing Bug#15801.  */
      block_input ();
      while (g_main_context_pending (context))
        g_main_context_dispatch (context);
      unblock_input ();
      errno = pselect_errno;
    }

  /* To not have to recalculate timeout, return like this.  */
  if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0))
    {
      retval = -1;
      errno = EINTR;
    }

  return retval;
}