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: