public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
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


  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox