From: George Anzinger <george@mvista.com>
To: "Hu, Boris" <boris.hu@intel.com>
Cc: drepper@redhat.com, "Li, Adam" <adam.li@intel.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] One possible bugfix for CLOCK_REALTIME timer.
Date: Fri, 04 Jun 2004 10:22:09 -0700 [thread overview]
Message-ID: <40C0AFC1.1020109@mvista.com> (raw)
In-Reply-To: <37FBBA5F3A361C41AB7CE44558C3448E045DCE7D@PDSMSX403.ccr.corp.intel.com>
Hu, Boris wrote:
> Here is one update version. wall_to_monotonic copy has been moved to
> k_itimer. Thanks.
As far as it goes... the update of the k_timer wall_to_monotonic should be the
same as that which is used to do the correction. I.e. it should be done within
the same lock region.
I will be out of town till Tuesday or Wed. next week....
George
>
> diff -urN -X dontdiff linux-2.6.6/include/linux/posix-timers.h
> linux-2.6.6.dev/include/linux/posix-timers.h
> --- linux-2.6.6/include/linux/posix-timers.h 2004-06-04
> 15:48:33.000000000 +0800
> +++ linux-2.6.6.dev/include/linux/posix-timers.h 2004-06-04
> 10:40:10.000000000 +0800
> @@ -1,9 +1,14 @@
> #ifndef _linux_POSIX_TIMERS_H
> #define _linux_POSIX_TIMERS_H
>
> +#include <linux/spinlock.h>
> +#include <linux/list.h>
> +
> struct k_clock {
> int res; /* in nano seconds */
> - int (*clock_set) (struct timespec * tp);
> + struct list_head abs_timer_list;
> + spinlock_t abs_timer_lock;
> + int (*clock_set) (struct timespec * tp);
> int (*clock_get) (struct timespec * tp);
> int (*nsleep) (int flags,
> struct timespec * new_setting,
> diff -urN -X dontdiff linux-2.6.6/include/linux/sched.h
> linux-2.6.6.dev/include/linux/sched.h
> --- linux-2.6.6/include/linux/sched.h 2004-06-04 15:48:33.000000000
> +0800
> +++ linux-2.6.6.dev/include/linux/sched.h 2004-06-04
> 10:39:53.000000000 +0800
> @@ -342,6 +342,8 @@
> struct task_struct *it_process; /* process to send signal to */
> struct timer_list it_timer;
> struct sigqueue *sigq; /* signal queue entry. */
> + struct list_head abs_timer_entry; /* clock abs_timer_list */
> + struct timespec wall_to_monotonic_prev;
> };
>
>
> diff -urN -X dontdiff linux-2.6.6/kernel/posix-timers.c
> linux-2.6.6.dev/kernel/posix-timers.c
> --- linux-2.6.6/kernel/posix-timers.c 2004-06-04 15:48:33.000000000
> +0800
> +++ linux-2.6.6.dev/kernel/posix-timers.c 2004-06-04
> 15:48:20.000000000 +0800
> @@ -7,6 +7,9 @@
> *
> * Copyright (C) 2002 2003 by MontaVista
> Software.
> *
> + * 2004-06-01 Fix CLOCK_REALTIME clock/timer TIMER_ABSTIME bug.
> + * Copyright (C) 2004 Boris Hu
> + *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> * the Free Software Foundation; either version 2 of the License, or
> (at
> @@ -95,7 +98,7 @@
> # define set_timer_inactive(tmr) \
> do { \
> (tmr)->it_timer.entry.prev = (void
> *)TIMER_INACTIVE; \
> - } while (0)
> + } while (0)
> #else
> # define timer_active(tmr) BARFY // error to use outside of SMP
> # define set_timer_inactive(tmr) do { } while (0)
> @@ -200,7 +203,9 @@
> */
> static __init int init_posix_timers(void)
> {
> - struct k_clock clock_realtime = {.res = CLOCK_REALTIME_RES };
> + struct k_clock clock_realtime = {.res = CLOCK_REALTIME_RES,
> + .abs_timer_lock = SPIN_LOCK_UNLOCKED
>
> + };
> struct k_clock clock_monotonic = {.res = CLOCK_REALTIME_RES,
> .clock_get = do_posix_clock_monotonic_gettime,
> .clock_set = do_posix_clock_monotonic_settime
> @@ -212,7 +217,6 @@
> posix_timers_cache = kmem_cache_create("posix_timers_cache",
> sizeof (struct k_itimer), 0, 0,
> 0, 0);
> idr_init(&posix_timers_id);
> -
> return 0;
> }
>
> @@ -360,6 +364,11 @@
> set_timer_inactive(timr);
> timer_notify_task(timr);
> unlock_timer(timr, flags);
> + if (CLOCK_REALTIME == timr->it_clock) {
> +
> spin_lock(&posix_clocks[CLOCK_REALTIME].abs_timer_lock);
> + list_del_init(&timr->abs_timer_entry);
> +
> spin_unlock(&posix_clocks[CLOCK_REALTIME].abs_timer_lock);
> + }
> }
>
>
> @@ -388,6 +397,7 @@
> return;
> }
> posix_clocks[clock_id] = *new_clock;
> + INIT_LIST_HEAD(&posix_clocks[clock_id].abs_timer_list);
> }
>
> static struct k_itimer * alloc_posix_timer(void)
> @@ -402,6 +412,7 @@
> kmem_cache_free(posix_timers_cache, tmr);
> tmr = 0;
> }
> + INIT_LIST_HEAD(&tmr->abs_timer_entry);
> return tmr;
> }
>
> @@ -787,6 +798,7 @@
> {
> struct k_clock *clock = &posix_clocks[timr->it_clock];
> u64 expire_64;
> + unsigned long seq;
>
> if (old_setting)
> do_timer_gettime(timr, old_setting);
> @@ -813,6 +825,11 @@
> #else
> del_timer(&timr->it_timer);
> #endif
> + if (CLOCK_REALTIME == timr->it_clock) {
> + spin_lock(&clock->abs_timer_lock);
> + list_del_init(&timr->abs_timer_entry);
> + spin_unlock(&clock->abs_timer_lock);
> + }
> timr->it_requeue_pending = (timr->it_requeue_pending + 2) &
> ~REQUEUE_PENDING;
> timr->it_overrun_last = 0;
> @@ -834,7 +851,6 @@
> tstojiffie(&new_setting->it_interval, clock->res, &expire_64);
> timr->it_incr = (unsigned long)expire_64;
>
> -
> /*
> * For some reason the timer does not fire immediately if
> expires is
> * equal to jiffies, so the timer notify function is called
> directly.
> @@ -843,8 +859,21 @@
> if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE))
> {
> if (timr->it_timer.expires == jiffies)
> timer_notify_task(timr);
> - else
> + else {
> add_timer(&timr->it_timer);
> + if (flags & TIMER_ABSTIME &&
> + timr->it_clock == CLOCK_REALTIME) {
> + do {
> + seq =
> read_seqbegin(&xtime_lock);
> + timr->wall_to_monotonic_prev =
> + wall_to_monotonic;
> + } while (read_seqretry(&xtime_lock,
> seq));
> + spin_lock(&clock->abs_timer_lock);
> + list_add_tail(&(timr->abs_timer_entry),
> +
> &(clock->abs_timer_list));
> + spin_unlock(&clock->abs_timer_lock);
> + }
> + }
> }
> return 0;
> }
> @@ -875,10 +904,10 @@
> if (!timr)
> return -EINVAL;
>
> - if (!posix_clocks[timr->it_clock].timer_set)
> + if (!posix_clocks[timr->it_clock].timer_set)
> error = do_timer_settime(timr, flags, &new_spec, rtn);
> else
> - error = posix_clocks[timr->it_clock].timer_set(timr,
> + error = posix_clocks[timr->it_clock].timer_set(timr,
> flags,
>
> &new_spec, rtn);
> unlock_timer(timr, flag);
> @@ -911,6 +940,11 @@
> #else
> del_timer(&timer->it_timer);
> #endif
> + if (CLOCK_REALTIME == timer->it_clock) {
> +
> spin_lock(&posix_clocks[CLOCK_REALTIME].abs_timer_lock);
> + list_del_init(&timer->abs_timer_entry);
> +
> spin_unlock(&posix_clocks[CLOCK_REALTIME].abs_timer_lock);
> + }
> return 0;
> }
>
> @@ -1086,10 +1120,10 @@
> {
> struct timespec new_tp;
>
> - if ((unsigned) which_clock >= MAX_CLOCKS ||
> + if ((unsigned) which_clock >= MAX_CLOCKS ||
> !posix_clocks[which_clock].res)
> return -EINVAL;
> - if (copy_from_user(&new_tp, tp, sizeof (*tp)))
> + if (copy_from_user(&new_tp, tp, sizeof (*tp)))
> return -EFAULT;
> if (posix_clocks[which_clock].clock_set)
> return posix_clocks[which_clock].clock_set(&new_tp);
> @@ -1159,7 +1193,55 @@
>
> void clock_was_set(void)
> {
> + struct k_clock *clock = &posix_clocks[CLOCK_REALTIME];
> + struct k_itimer *timr, *tmp;
> + struct timespec delta;
> + u64 exp = 0;
> + unsigned long seq;
> +
> wake_up_all(&nanosleep_abs_wqueue);
> +
> + /*
> + * Check if there exist TIMER_ABSTIME timers to correct.
> + */
> + if (list_empty(&clock->abs_timer_list))
> + return;
> +
> + spin_lock(&clock->abs_timer_lock);
> + list_for_each_entry_safe(timr, tmp,
> + &clock->abs_timer_list,
> + abs_timer_entry) {
> + do {
> + seq = read_seqbegin(&xtime_lock);
> + delta.tv_sec =
> + wall_to_monotonic.tv_sec
> + - timr->wall_to_monotonic_prev.tv_sec;
> + delta.tv_nsec =
> + wall_to_monotonic.tv_nsec
> + - timr->wall_to_monotonic_prev.tv_nsec;
> + } while (read_seqretry(&xtime_lock, seq));
> +
> + while (delta.tv_nsec >= NSEC_PER_SEC) {
> + delta.tv_sec ++;
> + delta.tv_nsec -= NSEC_PER_SEC;
> + }
> + while (delta.tv_nsec < 0) {
> + delta.tv_sec --;
> + delta.tv_nsec += NSEC_PER_SEC;
> + }
> + do {
> + seq = read_seqbegin(&xtime_lock);
> + timr->wall_to_monotonic_prev =
> wall_to_monotonic;
> + } while (read_seqretry(&xtime_lock, seq));
> +
> + tstojiffie(&delta, clock->res, &exp);
> + if (del_timer(&timr->it_timer)) { /* the timer has not
> run */
> + timr->it_timer.expires += exp;
> + add_timer(&timr->it_timer);
> + } else
> + list_del_init(&timr->abs_timer_entry);
> + }
> + spin_unlock(&clock->abs_timer_lock);
> }
>
> long clock_nanosleep_restart(struct restart_block *restart_block);
>
>
>>Hu, Boris wrote:
>>
>>>Thanks for your detailed comments. :)
>>>
>>>
>>>
>>>>Hu, Boris wrote:
>>>>
>>>>
>>>>><<posix-abs_timer-bugfix.diff>> George,
>>>>>
>>>>>There is one bug of CLOCK_REALTIME timer reported by Adam at
>>>>>http://sources.redhat.com/ml/libc-alpha/2004-05/msg00177.html.
>>>>>
>>>>>Here is one possible bugfix and it is against linux-2.6.6. All
>>>>>TIMER_ABSTIME cloks will be collected in k_clock struct and updated
>>>
>>>in
>>>
>>>
>>>>>sys_clock_settime. Could you review it? Thanks.
>>>>
>>>>Thanks for the poke :). Could you make the following changes:
>>>>
>>>>First, put the list in the posix timer structure (k_itimer), not in
>>>>timer_list.
>>>> This means one more dereference when doing things, but it does not
>>>
>>>push
>>>
>>>
>>>>into
>>>>the timer_list structure which is mostly used for other things.
>>>
>>>
>>>Done.
>>>
>>>
>>>
>>>>Second, I don't see the timer being removed from the list (should
>>>
>>>happen
>>>
>>>
>>>>when
>>>>ever it is inactive). Timers that repeat should be out of the list
>>>
>>>while
>>>
>>>
>>>>waiting for the signal to be picked up and put back in when
>
> add_timer
>
>>>is
>>>
>>>
>>>>again
>>>>called.
>>>
>>>
>>>I tried to add the removed codes to set_timer_inactive() but it
>
> would
>
>>>trigger a strange oops. I am still investigating on it. Is there any
>>>recommending places except set_timer_inactive()?
>>
>>Hm, set_timer_inactive() is called from the timer create routine.
>
> Should
>
>>not
>>need to remove it here... Also, this function is used for SMP issues
>
> and,
>
>>in
>>some cases (do_timer_settime is one) it is not called if not on an SMP
>>system.
>>Also, it seems not to be called from sys_timer_delete(). This last
>
> would
>
>>be a
>>real problem as we are about to return the memory the list runs
>
> through it.
>
>>So, I think you will just have to find the places were we delete a
>
> timer,
>
>>that
>>and the timer call back function should do it.
>>
>>
>>>
>>>>Also, you should test to see if the clock is one that can be set
>
> prior
>
>>>to
>>>
>>>
>>>>putting the timer in the abs timer list. We must not correct timers
>>>
>>>on
>>>
>>>
>>>>CLOCK_MONOTONIC.
>>>
>>>
>>>
>>>Done.
>>>
>>>
>>>
>>>>Now, for the correction. Sys_clock_settime() is the wrong place for
>>>
>>>this
>>>
>>>
>>>>as the
>>>>clock can also be set a number of other ways. The right place is in
>>>>clock_was_set(), which is called if time is set in any of the
>
> several
>
>>>ways.
>>>
>>>
>>>>The
>>>>next thing is to determine how far the clock was moved. I think the
>>>
>>>best
>>>
>>>
>>>>way to
>>>>do this is to keep a copy of the wall_to_monotonic var in a private
>>>>location.
>>>>This should be set to be exactly wall_to_monotonic when the system
>
> is
>
>>>>booted (in
>>>>the same function you are setting up the clock lists) and at the end
>>>
>>>of
>>>
>>>
>>>>clock_was_set(). When clock_was_set() is called the difference
>>>
>>>between
>>>
>>>
>>>>this
>>>>value and wall_to_monotonic is exactly how far the clock was moved.
>>>
>>>(Be
>>>
>>>
>>>>careful
>>>>on the sign of this movement.)
>>>>
>>>
>>>
>>>Done.
>>>
>>>
>>>
>>>>Finally, be careful about races. Timers can expire while
>>>
>>>clock_was_set()
>>>
>>>
>>>>is
>>>>running. The removal code should take the timer lock as well as the
>>>>abs_time
>>>>list lock (at least I think this would be wise, but I could be wrong
>>>
>>>here).
>>>
>>>
>>>IMHO, we need not take the timer locks. We del_timer() first and if
>
> the
>
>>>timer has expired, we simply removed it from the abs_timer_list
>
> which is
>
>>>protected by abs_timer_lock.
>>
>>Me thinks you will need to do a bit more to convince me that locks are
>
> not
>
>>needed here. Lets see if I can explain my concerns.
>>
>>First, I think the clock_was_set() function needs to serialize it self
>
> so
>
>>only
>>one cpu/ task can be in it at a time. This, I think, can/is done with
>
> the
>
>>abs
>>list lock.
>>
>>Second there is the possibility that a timer in the list will already
>
> be
>
>>set via
>>the correct time. To avoid this possibility I suggest (this is a
>
> change
>
>>from my
>>suggestion of yesterday) putting the current value of
>
> wall_to_monotonic in
>
>>the
>>k_timer structure when the timer is calculated. This value must be
>>obtained
>>under the xtime read lock (which we already take to calculate the
>
> timer).
>
>>In
>>this way of doing things, clock_was_set() would take the xtime write
>
> lock,
>
>>possibly for each entry in the abs list. It would use the
>>wall_to_monotonic
>>time in the structure rather than keeping a local copy, and it would
>>update that
>>time once the correction was made.
>>
>>We still haven't covered the case where time is set while a timer is
>
> being
>
>>set.
>> I.e. where the expire time is calculated but the result has not yet
>
> been
>
>>put
>>in the timer structure and add_timer has not yet been called. It is
>
> here
>
>>that
>>the timer lock would seem to be the right thing to do. We would
>
> require
>
>>that
>>the timer be put in the abs list while the xtime read lock is held
>>(careful here
>>as this is now a sequence lock and we only want to add the timer to
>
> the
>
>>list
>>once). This is complicated. We must take the locks in the same order
>
> so
>
>>we can
>>not take the timer lock while holding the abs list lock. The, IMHO,
>>simple
>>thing to do is to have clock_was_set() copy the whole abs list (this
>
> is
>
>>just a
>>simple pointer manipulation). Then it can scan this list and move
>
> each
>
>>entry to
>>the abs list as it updates the timers. The timer lock would be taken
>
> for
>
>>each
>>timer during this update. This is to allow timers that are on the way
>
> to
>
>>add_timer to get there. This code should not remove timers from the
>
> abs
>
>>list,
>>or rather, each timer it finds in the moved list should be put back in
>
> the
>
>>abs
>>list even if it is not in the system timer list (it just means that
>>someone else
>>is removing it). Both the removal from the moved list and the insert
>
> into
>
>>the
>>abs list should be done under the same abs list lock but it must be
>>dropped
>>while taking the timer lock.
>>
>>There is a possible race here with the timer delete code. Here is how
>
> I
>
>>would
>>solve this. First, with the list being moved, you need only be
>
> concerned
>
>>with
>>the first entry in the list (as you will remove it as part of
>
> processing
>
>>and
>>then do the next first entry). So, first lock the abs list. Then
>
> find
>
>>the
>>timer ID for the first entry. Unlock the abs list, and lock the timer
>>using the
>>ID. The existing lock code will take care of possible races WRT
>
> existence.
>
>>Once the timer is locked, re lock the abs list and if the given timer
>
> is
>
>>still
>>the first entry, a.) remove it b.) if the system delete timer fails,
>
> just
>
>>take
>>the abs list lock and reinsert the timer, else under the xtime
>
> readlock
>
>>compare
>>wall_to_monotonic with the timers value c.) and put it in the abs list
>
> and
>
>>the
>>add_timer list.
>>
>>Note that the case of an expired timer that is still in the abs list
>
> is
>
>>handled
>>by just reinserting the timer. This means that the expire call back
>
> code
>
>>needs
>>to check for a clock reset that may have made the expire invalid.
>>
>>I am sure there are other ways of doing this, but the main locking
>
> issues
>
>>are:
>>
>>1.) Getting the timer's value pegged to a given clock set value (done
>
> by
>
>>copying
>>wall_to_monotonic to the k_timer struct)., This must be done under
>
> the
>
>>xtime
>>read lock.
>>
>>2.) Covering the race between the timer adjustment code and possible
>
> POSIX
>
>>timer
>>deletion (done by NOT assuming the timer is there just because we
>
> found it
>
>>in
>>the abs timer list, although we do pin it down long enough to get it's
>
> ID
>
>>by
>>locking this list). This also requires us to take the timer lock
>
> which
>
>>means we
>>have to drop the abs list lock.
>>
>>3.) Covering the race between the timer expiring during the system
>
> clock
>
>>setting
>>processing. Done by having the timer call back code verify that the
>
> same
>
>>value
>>of wall_to_monotonic is still in play.
>>
>>We note that the time used for NOW in the repeating timer update needs
>
> to
>
>>also
>>satisfy 1. above.
>>
>>And in passing, note that the overrun count will show something going
>
> on
>
>>when
>>the clock is moved forward and not when it is move backward.
>>
>>
>>>
>>>>And a minor issue, the community seems to prefer the C comment style
>>>
>>>to
>>>
>>>
>>>>the C++
>>>>style of comments...
>>>>
>>>
>>>
>>>Done.
>>>
>>>
>>>
>>>>Thanks for your effort in this matter.
>>>>
>>>>George
>>>>
>>>>
>>>>>diff -urN -X rt.ia32/base/dontdiff
>>>>>linux-2.6.6/include/linux/posix-timers.h
>>>>>linux-2.6.6.dev/include/linux/posix-timers.h
>>>>>--- linux-2.6.6/include/linux/posix-timers.h 2004-05-10
>>>>>10:32:29.000000000 +0800
>>>>>+++ linux-2.6.6.dev/include/linux/posix-timers.h 2004-06-02
>>>>>10:30:57.000000000 +0800
>>>>>@@ -1,9 +1,14 @@
>>>>>#ifndef _linux_POSIX_TIMERS_H
>>>>>#define _linux_POSIX_TIMERS_H
>>>>>
>>>>>+#include <linux/list.h>
>>>>>+#include <linux/spinlock.h>
>>>>>+
>>>>>struct k_clock {
>>>>> int res; /* in nano seconds */
>>>>>- int (*clock_set) (struct timespec * tp);
>>>>>+ struct list_head abs_timer_list;
>>>>>+ spinlock_t abs_timer_lock;
>>>>>+ int (*clock_set) (struct timespec * tp);
>>>>> int (*clock_get) (struct timespec * tp);
>>>>> int (*nsleep) (int flags,
>>>>> struct timespec * new_setting,
>>>>>diff -urN -X rt.ia32/base/dontdiff
>
> linux-2.6.6/include/linux/timer.h
>
>>>>>linux-2.6.6.dev/include/linux/timer.h
>>>>>--- linux-2.6.6/include/linux/timer.h 2004-05-10
>>>
>>>10:32:54.000000000
>>>
>>>
>>>>>+0800
>>>>>+++ linux-2.6.6.dev/include/linux/timer.h 2004-06-02
>>>>>19:16:08.000000000 +0800
>>>>>@@ -9,6 +9,7 @@
>>>>>
>>>>>struct timer_list {
>>>>> struct list_head entry;
>>>>>+ struct list_head abs_timer_entry;
>>>>> unsigned long expires;
>>>>>
>>>>> spinlock_t lock;
>>>>>diff -urN -X rt.ia32/base/dontdiff
>
> linux-2.6.6/kernel/posix-timers.c
>
>>>>>linux-2.6.6.dev/kernel/posix-timers.c
>>>>>--- linux-2.6.6/kernel/posix-timers.c 2004-05-10
>>>
>>>10:32:37.000000000
>>>
>>>
>>>>>+0800
>>>>>+++ linux-2.6.6.dev/kernel/posix-timers.c 2004-06-02
>>>>>19:12:31.000000000 +0800
>>>>>@@ -7,6 +7,9 @@
>>>>> *
>>>>> * Copyright (C) 2002 2003 by
>
> MontaVista
>
>>>>>Software.
>>>>> *
>>>>>+ * 2004-06-01 Fix CLOCK_REALTIME clock/timer TIMER_ABSTIME bug.
>>>>>+ * Copyright (C) 2004 Boris Hu
>>>>>+ *
>>>>> * This program is free software; you can redistribute it and/or
>>>
>>>modify
>>>
>>>
>>>>> * it under the terms of the GNU General Public License as
>>>
>>>published by
>>>
>>>
>>>>> * the Free Software Foundation; either version 2 of the License,
>>>
>>>or
>>>
>>>
>>>>>(at
>>>>>@@ -200,7 +203,9 @@
>>>>> */
>>>>>static __init int init_posix_timers(void)
>>>>>{
>>>>>- struct k_clock clock_realtime = {.res = CLOCK_REALTIME_RES };
>>>>>+ struct k_clock clock_realtime = {.res = CLOCK_REALTIME_RES,
>>>>>+ .abs_timer_lock = SPIN_LOCK_UNLOCKED
>>>>>
>>>>>+ };
>>>>> struct k_clock clock_monotonic = {.res = CLOCK_REALTIME_RES,
>>>>> .clock_get = do_posix_clock_monotonic_gettime,
>>>>> .clock_set = do_posix_clock_monotonic_settime
>>>>>@@ -388,6 +393,7 @@
>>>>> return;
>>>>> }
>>>>> posix_clocks[clock_id] = *new_clock;
>>>>>+ INIT_LIST_HEAD(&posix_clocks[clock_id].abs_timer_list);
>>>>>}
>>>>>
>>>>>static struct k_itimer * alloc_posix_timer(void)
>>>>>@@ -843,8 +849,15 @@
>>>>> if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE))
>>>>>{
>>>>> if (timr->it_timer.expires == jiffies)
>>>>> timer_notify_task(timr);
>>>>>- else
>>>>>+ else {
>>>>> add_timer(&timr->it_timer);
>>>>>+ if (flags & TIMER_ABSTIME) {
>>>>>+ spin_lock(&clock->abs_timer_lock);
>>>>>+
>>>>>list_add_tail(&(timr->it_timer.abs_timer_entry),
>>>>>+
>>>>>&(clock->abs_timer_list));
>>>>>+
>>>
>>>spin_unlock(&clock->abs_timer_lock);
>>>
>>>
>>>>>+ }
>>>>>+ }
>>>>> }
>>>>> return 0;
>>>>>}
>>>>>@@ -1085,16 +1098,61 @@
>>>>>sys_clock_settime(clockid_t which_clock, const struct timespec
>>>
>>>__user
>>>
>>>
>>>>>*tp)
>>>>>{
>>>>> struct timespec new_tp;
>>>>>+ struct timespec before, now;
>>>>>+ struct k_clock *clock;
>>>>>+ long ret;
>>>>>+ struct timer_list *timer, *tmp;
>>>>>+ struct timespec delta;
>>>>>+ u64 exp = 0;
>>>>>
>>>>>- if ((unsigned) which_clock >= MAX_CLOCKS ||
>>>>>+ if ((unsigned) which_clock >= MAX_CLOCKS ||
>>>>> !posix_clocks[which_clock].res)
>>>>> return -EINVAL;
>>>>>- if (copy_from_user(&new_tp, tp, sizeof (*tp)))
>>>>>+
>>>>>+ clock = &posix_clocks[which_clock];
>>>>>+
>>>>>+ if (copy_from_user(&new_tp, tp, sizeof (*tp)))
>>>>> return -EFAULT;
>>>>> if (posix_clocks[which_clock].clock_set)
>>>>> return posix_clocks[which_clock].clock_set(&new_tp);
>>>>>
>>>>>- return do_sys_settimeofday(&new_tp, NULL);
>>>>>+ do_posix_gettime(clock, &before);
>>>>>+
>>>>>+ ret = do_sys_settimeofday(&new_tp, NULL);
>>>>>+
>>>>>+ /*
>>>>>+ * Check if there exist TIMER_ABSTIME timers to update.
>>>>>+ */
>>>>>+ if (which_clock != CLOCK_REALTIME ||
>>>>>+ list_empty(&clock->abs_timer_list))
>>>>>+ return ret;
>>>>>+
>>>>>+ do_posix_gettime(clock, &now);
>>>>>+ delta.tv_sec = before.tv_sec - now.tv_sec;
>>>>>+ delta.tv_nsec = before.tv_nsec - now.tv_nsec;
>>>>>+ while (delta.tv_nsec >= NSEC_PER_SEC) {
>>>>>+ delta.tv_sec ++;
>>>>>+ delta.tv_nsec -= NSEC_PER_SEC;
>>>>>+ }
>>>>>+ while (delta.tv_nsec < 0) {
>>>>>+ delta.tv_sec --;
>>>>>+ delta.tv_nsec += NSEC_PER_SEC;
>>>>>+ }
>>>>>+
>>>>>+ tstojiffie(&delta, clock->res, &exp);
>>>>>+
>>>>>+ spin_lock(&(clock->abs_timer_lock));
>>>>>+ list_for_each_entry_safe(timer, tmp,
>>>>>+ &clock->abs_timer_list,
>>>>>+ abs_timer_entry) {
>>>>>+ if (timer && del_timer(timer)) { //the timer has
>>>
>>>not
>>>
>>>
>>>>>run
>>>>>+ timer->expires += exp;
>>>>>+ add_timer(timer);
>>>>>+ } else
>>>>>+ list_del(&timer->abs_timer_entry);
>>>>>+ }
>>>>>+ spin_unlock(&(clock->abs_timer_lock));
>>>>>+ return ret;
>>>>>}
>>>>>
>>>>>asmlinkage long
>>>>>
>>>>>Good Luck !
>>>>>Boris Hu (Hu Jiangtao)
>>>>>Intel China Software Center
>>>>>86-021-5257-4545#1277
>>>>>iNET: 8-752-1277
>>>>>************************************
>>>>>There are my thoughts, not my employer's.
>>>>>************************************
>>>>>"gpg --recv-keys --keyserver wwwkeys.pgp.net 0FD7685F"
>>>>>{0FD7685F:CFD6 6F5C A2CB 7881 725B CEA0 956F 9F14 0FD7 685F}
>>>>>
>>>>>
>>>>
>>>>--
>>>>George Anzinger george@mvista.com
>>>>High-res-timers: http://sourceforge.net/projects/high-res-timers/
>>>>Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml
>>>
>>>
>>>
>>>
>>--
>>George Anzinger george@mvista.com
>>High-res-timers: http://sourceforge.net/projects/high-res-timers/
>>Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml
>
>
>
--
George Anzinger george@mvista.com
High-res-timers: http://sourceforge.net/projects/high-res-timers/
Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml
next prev parent reply other threads:[~2004-06-04 17:28 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-06-04 9:21 [PATCH] One possible bugfix for CLOCK_REALTIME timer Hu, Boris
2004-06-04 17:22 ` George Anzinger [this message]
-- strict thread matches above, loose matches on Subject: below --
2004-07-16 3:53 Hu, Boris
2004-06-10 8:34 Hu, Boris
2004-06-11 21:59 ` George Anzinger
2004-06-07 5:51 Hu, Boris
2004-06-10 1:06 ` George Anzinger
2004-06-03 9:56 Hu, Boris
2004-06-04 0:36 ` George Anzinger
2004-06-02 12:00 Hu, Boris
2004-06-02 22:05 ` George Anzinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=40C0AFC1.1020109@mvista.com \
--to=george@mvista.com \
--cc=adam.li@intel.com \
--cc=boris.hu@intel.com \
--cc=drepper@redhat.com \
--cc=ganzinger@mvista.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.