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

Re: Some quick questions



On Mon, 26 Feb 1996, Stephen Masterman wrote:

> Second, I am under the impression that there is a POSIX system call called
> nanosleep() which allows a process to sleep an amount of time specified in
> units of microseconds (don't know why its nanosleep and not microsleep).
> Does anyone know what package this might be in?  I don't have a man page for
> it so I assume I don't have the function.

The following article appeared in comp.os.linux.development.system 
regarding nanosleep.

Gerry
gerry@blue.intele.net

----Forwarded----
From: mskuhn@unrza3.dialin.rrze.uni-erlangen.de (Markus Kuhn)
Newsgroups: comp.os.linux.development.system
Subject: New real-time system call: nanosleep
Date: 21 Feb 1996 15:14:00 +0100
Organization: Markus Kuhn, 91080 Uttenreuth, Germany
Reply-To: mskuhn@cip.informatik.uni-erlangen.de

Since Linux alpha test kernel 1.3.67, there exists a new system call
for pausing execution of a process that has advantages over the old
sleep() and usleep() functions. Below follow the new manpage and a
test and demonstration software which is supposed to run even without
the most recent libc.

Please let me know if you have any questions or problems with it or
whether it works fine in your real-time applications.

Markus


---------------------------------------------------------------------------



NANOSLEEP(2)        Linux Programmer's Manual        NANOSLEEP(2)


NAME
       nanosleep - pause execution for a specified time

SYNOPSIS
       #include <time.h>

       int nanosleep(const struct timespec *req, struct timespec rem);

DESCRIPTION
       nanosleep delays the execution of the program for at least
       the time specified in req.  The function can  return  ear-
       lier  if  a  signal  has been delivered to the process. In
       this case, it returns -1, sets errno to EINTR and,  writes
       the  remaining  time  into the structure pointed to by rem
       unless rem is NULL.  The value of *rem can then be used to
       call nanosleep again and complete the specified pause.

       The  structure  timespec  is  used to specify intervals of
       time  with  nanosecond  precision.  It  is  specified   in
       <time.h> and has the form

              struct timespec
              {
                      time_t  tv_sec;         /* seconds */
                      long    tv_nsec;        /* nanoseconds */
              };

       The  value of the nanoseconds field must be in the range 0
       to 999 999 999.

       Compared to sleep(3)  and  usleep(3),  nanosleep  has  the
       advantage of not affecting any signals, it is standardized
       by POSIX, it provides higher  timing  resolution,  and  it
       allows to continue an interrupted pause more easily.

ERRORS
       In the case of an error or exception, the nanosleep system
       call returns -1 instead of 0 and sets errno to one of  the
       following values:

       EINTR   The  pause  has  been interrupted by a non-blocked
               signal that was  delivered  to  the  process.  The
               remaining  sleep time has been written into rem so
               that the process can easily call  nanosleep  again
               and continue with the pause.

       EINVAL  The  value  in  the  tv_nsec  field was not in the
               range 0 to 999 999 999 or tv_sec was negative.

BUGS
       The current implementation of nanosleep is  based  on  the
       normal  kernel  timer mechanism, which has a resolution of
       1/HZ = 10 ms. Therefore, nanosleep pauses  always  for  at
       least  the specified time, however it can take up to 10 ms
       longer than specified until the  process  becomes  runable
       again. For the same reason, the value returned in the case
       of an arriving signal in rem is  usually  rounded  to  the
       next larger multiple of 10 ms.

       As  some  real-time applications require much more precise
       pauses (e.g., in order to control some time-critical hard-
       ware),  nanosleep is also capeable of short high-precision
       pauses. If the process is scheduled under a real-time pol-
       icy like SCHED_FIFO or SCHED_RR, then pauses of up to 2 ms
       will be performed as busy waits  with  microsecond  preci-
       sion.

STANDARDS
       POSIX.1b

SEE ALSO
       sleep(3),     usleep(3),     sched_setscheduler(2),    and
       timer_create(2).



Linux 1.3.67                1996-02-21                          1




---------------------------------------------------------------------------

/*
 * ns-demo.c -- a tiny test tool for the nanosleep() system call
 *
 * Markus Kuhn -- 1996-02-18
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#if 0
#include <sched.h>
#endif
#include <linux/unistd.h>     /* for _syscallX macros/related stuff */

/* the following lines are only compiled as a quick fix if you still
 * have an old set of libc include files */

/* quick 'n dirty replacement of <sys/mman.h> */
#if !defined(_POSIX_MEMLOCK) && defined(__NR_mlockall)
#define MCL_CURRENT    1               /* lock all current mappings */
#define MCL_FUTURE     2               /* lock all future mappings */
_syscall1(int, mlockall, int, flags);
_syscall0(int, munlockall);
int mlockall(int flags);
int munlockall(void);
#define _POSIX_MEMLOCK
#endif
#if !defined(_POSIX_MEMLOCK_RANGE) && defined(__NR_mlock)
_syscall2(int, mlock, const void *, addr, size_t, len);
_syscall2(int, munlock, const void *, addr, size_t, len);
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
#define _POSIX_MEMLOCK_RANGE
#endif
/* quick 'n dirty replacement of <sched.h> */
#if !defined(_POSIX_PRIORITY_SCHEDULING) && defined(__NR_sched_setscheduler)
struct sched_param {
  int sched_priority;
};
#define SCHED_OTHER    0
#define SCHED_FIFO     1
#define SCHED_RR       2
#define SCHED_MIN      0
#define SCHED_MAX     31
_syscall2(int, sched_setparam, pid_t, pid, const struct sched_param *, 
param);
_syscall2(int, sched_getparam, pid_t, pid, struct sched_param *, param);
_syscall3(int, sched_setscheduler, pid_t, pid, int, policy,
          const struct sched_param *, param);
_syscall1(int, sched_getscheduler, pid_t, pid);
_syscall0(int, sched_yield);
_syscall1(int, sched_get_priority_max, int, policy);
_syscall1(int, sched_get_priority_min, int, policy);
_syscall2(int, sched_rr_get_interval, pid_t, pid, struct timespec *, 
interval);
int sched_setparam(pid_t pid, const struct sched_param *param);
int sched_getparam(pid_t pid, struct sched_param *param);
int sched_setscheduler(pid_t pid, int policy, const struct sched_param 
*param);
int sched_getscheduler(pid_t pid);
int sched_yield(void);
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
int sched_rr_get_interval(pid_t pid, struct timespec *interval);
#define _POSIX_PRIORITY_SCHEDULING
#endif
/* quick 'n dirty replacement for <time.h> extensions */
#if 0
struct timespec {
  time_t  tv_sec;         /* seconds */
  long    tv_nsec;        /* nanoseconds */
};
#endif
_syscall2(int, nanosleep, const struct timespec *, rqtp,
          struct timespec *, rmtp);
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

/* dummy signal handler */
void do_nothing() {
  return;
}

int main(int argc, char **argv)
{
  long delay, bias;
  struct timeval start, stop;
  struct timespec t, t1;
  int i, r;
  unsigned long j;
  struct sched_param my_priority;
  struct sigaction sig;

  /* disable paging for this real-time test */
  if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
    if (errno == EPERM) {
      fprintf(stderr, "This is a real-time test and must run as root.\n");
      exit(1);
    }
    perror("mlockall(MCL_CURRENT | MCL_FUTURE)");
  }

  /* switch to real-time scheduling for this test */
  if (argc == 1) {
    my_priority.sched_priority = 30;
    if (sched_setscheduler(getpid(), SCHED_FIFO, &my_priority)) {
      perror("sched_setscheduler(..., SCHED_FIFO, ...)");
    }
  }

  /* prepare SIGQUIT (= Ctrl-\) for EINTR tests */
  sig.sa_handler = do_nothing;
  sigemptyset(&sig.sa_mask);
  sig.sa_flags = 0;
  sigaction(SIGQUIT, &sig, NULL);

  /* calibrate test loop */
  t.tv_sec = 0;
  t.tv_nsec = 1;
  for (i = 0; i < 4; i++) {
    gettimeofday(&start, NULL);
    r = nanosleep(&t, &t1);
    if (r && errno != EINTR)
      perror("nanosleep");
    gettimeofday(&stop, NULL);
    bias = (stop.tv_sec - start.tv_sec) * 1000000L +
      stop.tv_usec - start.tv_usec;
    printf("t%d",i);
    while (rand() > RAND_MAX >> 15);
  }
  putchar('\n');

  /* test loop */    
  for (j = 0; j < 4000000000UL; j = (double) j * 1.7 + 100) {
    t.tv_sec = j / 1000000000L;
    t.tv_nsec = j % 1000000000L;
    printf("nanosleep(%ld.%09ld s) = ",
           (long) t.tv_sec, t.tv_nsec);
    for (i = 0; i < 3; i++) {
      gettimeofday(&start, NULL);
      r = nanosleep(&t, &t1);
      if (r && errno != EINTR)
        perror("nanosleep");
      gettimeofday(&stop, NULL);
      delay = (stop.tv_sec - start.tv_sec) * 1000000L +
        stop.tv_usec - start.tv_usec;
      printf("%9ld µs  ", delay-bias);
      if (r && errno == EINTR)
        printf("\nInterrupted, remaining time: %ld s, %ld ns\n",
               (long) t1.tv_sec, t1.tv_nsec);
      /* wait for a random time in order to avoid that the
       * measurement syncs with the HZ interrupt */
      while (rand() > RAND_MAX >> 15);
    }
    putchar('\n');
    fflush(stdout);
  }

  return 0;
}

---------------------------------------------------------------------------

-- 
Markus Kuhn, Computer Science student -- University of Erlangen,
Internet Mail: <mskuhn@cip.informatik.uni-erlangen.de> - Germany
WWW Home: <http://wwwcip.informatik.uni-erlangen.de/user/mskuhn>


Reply to: