* Re: [PATCH] Fix for sys_nanosleep() in 2.4.16
2001-11-29 6:56 [PATCH] Fix for sys_nanosleep() in 2.4.16 Michael Arras
@ 2001-11-29 10:04 ` Christoph Hellwig
2001-11-29 23:41 ` george anzinger
1 sibling, 0 replies; 3+ messages in thread
From: Christoph Hellwig @ 2001-11-29 10:04 UTC (permalink / raw)
To: Michael Arras; +Cc: linux-kernel, torvalds, marcelo
In article <3C05DC1D.7071FC6B@yahoo.com> you wrote:
> Greetings,
>
> For many of us, the kernel thread scheduling resolution is
> 10ms (see getitimer(2)). By adding 1 jiffy to the time to
> sleep in sys_nanosleep(), threads are sleeping 10ms too long.
> timespec_to_jiffies() does a good job at returning the
> appropriate number of jiffies to sleep. There is no need to
> add one for good measure.
Please take a look at:
http://www.kernel.org/pub/linux/kernel/people/andrea/kernels/v2.4/2.4.15aa1/00_nanosleep-5
instead.
Linus & Marcelo: any chance to get that into the tree? (patch is inlined below)
Christoph
--
Of course it doesn't work. We've performed a software upgrade.
diff -urN 2.4.6pre6/include/linux/time.h nanosleep/include/linux/time.h
--- 2.4.6pre6/include/linux/time.h Thu Jun 14 18:07:48 2001
+++ nanosleep/include/linux/time.h Thu Jun 28 11:47:14 2001
@@ -48,6 +48,27 @@
value->tv_sec = jiffies / HZ;
}
+static __inline__ int
+timespec_before(struct timespec a, struct timespec b)
+{
+ if (a.tv_sec == b.tv_sec)
+ return a.tv_nsec < b.tv_nsec;
+ return a.tv_sec < b.tv_sec;
+}
+
+/* computes `a - b' and write the result in `result', assumes `a >= b' */
+static inline void
+timespec_less(struct timespec a, struct timespec b, struct timespec * result)
+{
+ if (a.tv_nsec < b.tv_nsec)
+ {
+ a.tv_sec--;
+ a.tv_nsec += 1000000000;
+ }
+
+ result->tv_sec = a.tv_sec - b.tv_sec;
+ result->tv_nsec = a.tv_nsec - b.tv_nsec;
+}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
@@ -89,6 +110,27 @@
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
+
+/* computes `a - b' and write the result in `result', assumes `a >= b' */
+static inline void
+timeval_less(struct timeval a, struct timeval b, struct timeval * result)
+{
+ if (a.tv_usec < b.tv_usec)
+ {
+ a.tv_sec--;
+ a.tv_usec += 1000000;
+ }
+
+ result->tv_sec = a.tv_sec - b.tv_sec;
+ result->tv_usec = a.tv_usec - b.tv_usec;
+}
+
+static __inline__ void
+timeval_to_timespec(struct timeval tv, struct timespec * ts)
+{
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = (long) tv.tv_usec * 1000;
+}
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
diff -urN 2.4.6pre6/kernel/timer.c nanosleep/kernel/timer.c
--- 2.4.6pre6/kernel/timer.c Thu Jun 28 11:38:09 2001
+++ nanosleep/kernel/timer.c Thu Jun 28 11:48:47 2001
@@ -798,6 +798,7 @@
{
struct timespec t;
unsigned long expire;
+ struct timeval before, after;
if(copy_from_user(&t, rqtp, sizeof(struct timespec)))
return -EFAULT;
@@ -822,11 +823,20 @@
expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
current->state = TASK_INTERRUPTIBLE;
+ get_fast_time(&before);
expire = schedule_timeout(expire);
+ get_fast_time(&after);
if (expire) {
if (rmtp) {
- jiffies_to_timespec(expire, &t);
+ struct timespec elapsed;
+
+ timeval_less(after, before, &after);
+ timeval_to_timespec(after, &elapsed);
+ if (timespec_before(elapsed, t))
+ timespec_less(t, elapsed, &t);
+ else
+ t.tv_nsec = t.tv_sec = 0;
if (copy_to_user(rmtp, &t, sizeof(struct timespec)))
return -EFAULT;
}
^ permalink raw reply [flat|nested] 3+ messages in thread