I am working on POSIX timers where there is defined a CLOCK_MONOTONIC.
The most reasonable implementation of this clock is that it is "uptime"
or jiffies. The problem is that it is most definitely not MONOTONIC
when it rolls back to 0 :( Thus the need for 64-bits.
As it turns out, the only code that needs to know about the high order
bits is the code that increments jiffies and the POSIX timer code.
Every thing else can continue to use the current definition with no
problem.
The solution needs to account for the Endianess of the platform. Here
are the possible solutions I have come up with:
1.) Define jiffies in the arch section of the code using asm. Looks
like this for x86:
__asm__( ".global jiffies\n\t"
".global jiffiesll\n"
".global jiffiesh\n"
"jiffiesll:\n"
"jiffies: \n\t"
".long 0\n"
"jiffiesh: \n\t"
".long 0");
The up side of this method is that none of the current using code needs
to be aware of the change. We just remove "unsigned long volatile
jiffies;" from timer.c.
The down side of this method is that all platforms must do something
similar.
2.) Use a C structure that depends on ENDIAN defines:
#if defined(__LITTLE_ENDIAN)
union {
long long jiffiesll;
struct {
int jiffiesl
int jiffiesh
} jiffieparts;
}jiffiesu;
#elif defined(__BIG_ENDIAN)
union {
long long jiffies64;
struct {
int jiffiesh
int jiffiesl
} jiffieparts;
}jiffiesu;
#else
#error "I'm probably missing #include <asm/byteorder.h>"
#endif
#define jiffies jiffiesu.jiffieparts.jiffiesl
#define jiffiesll jiffiesu.jiffies64
The down side with this method is that jiffies can not be used as a
local or structure
element, i.e. it is now a reserved name in the kernel.
3.) Define jiffies as 64 bit and use C casts to get to the low order
part:
u64 jiffies_u64;
#define jiffies (unsigned long volatile)jiffies_u64
Here again the down side is that jiffies can not be used as a local or
structure
element, i.e. it is now a reserved name in the kernel.
I am sure there are other ways to approach this and I would like to hear
them.
Approach 1.) requires that all platforms be changed at the same time.
Approaches 2.) and 3.) require that we find all occurrences of jiffies
should not be "defined" to something else. The Ibm tick less patch
found most of these, but I am sure there are more lurking in drivers.
Comments?
George
On Mon, 22 Oct 2001 08:12:24 -0700,
george anzinger <[email protected]> wrote:
>I am working on POSIX timers where there is defined a CLOCK_MONOTONIC.
>The most reasonable implementation of this clock is that it is "uptime"
>or jiffies. The problem is that it is most definitely not MONOTONIC
>when it rolls back to 0 :( Thus the need for 64-bits.
If you want to leave existing kernel code alone so it still uses 32 bit
jiffies, just maintain a separate high order 32 bit field which is only
used by the code that really needs it. On 32 bit machines, the jiffie
code does
old_jiffies = jiffies++;
if (jiffies < old_jiffies)
++high_jiffies;
You will need a spin lock around that on 32 bit systems, but that is
true for anything that tries to do 64 bit counter updates on a 32 bit
system. None of your suggestions will work on ix86, it does not
support atomic updates on 64 bit fields in hardware.
Keith Owens wrote:
>
> On Mon, 22 Oct 2001 08:12:24 -0700,
> george anzinger <[email protected]> wrote:
> >I am working on POSIX timers where there is defined a CLOCK_MONOTONIC.
> >The most reasonable implementation of this clock is that it is "uptime"
> >or jiffies. The problem is that it is most definitely not MONOTONIC
> >when it rolls back to 0 :( Thus the need for 64-bits.
>
> If you want to leave existing kernel code alone so it still uses 32 bit
> jiffies, just maintain a separate high order 32 bit field which is only
> used by the code that really needs it. On 32 bit machines, the jiffie
> code does
>
> old_jiffies = jiffies++;
> if (jiffies < old_jiffies)
> ++high_jiffies;
>
> You will need a spin lock around that on 32 bit systems, but that is
> true for anything that tries to do 64 bit counter updates on a 32 bit
> system. None of your suggestions will work on ix86, it does not
> support atomic updates on 64 bit fields in hardware.
cmpxchg8b does, but it's a bit indirect.
--
Brian Gerst
On Tue, 23 Oct 2001 02:05:54 -0400,
Brian Gerst <[email protected]> wrote:
>Keith Owens wrote:
>> You will need a spin lock around that on 32 bit systems, but that is
>> true for anything that tries to do 64 bit counter updates on a 32 bit
>> system.
>
>cmpxchg8b does, but it's a bit indirect.
Not on 386, only on 486 and above. Besides, you want to avoid arch
specific asm code.
Keith Owens wrote:
>
> On Mon, 22 Oct 2001 08:12:24 -0700,
> george anzinger <[email protected]> wrote:
> >I am working on POSIX timers where there is defined a CLOCK_MONOTONIC.
> >The most reasonable implementation of this clock is that it is "uptime"
> >or jiffies. The problem is that it is most definitely not MONOTONIC
> >when it rolls back to 0 :( Thus the need for 64-bits.
>
> If you want to leave existing kernel code alone so it still uses 32 bit
> jiffies, just maintain a separate high order 32 bit field which is only
> used by the code that really needs it. On 32 bit machines, the jiffie
> code does
>
> old_jiffies = jiffies++;
> if (jiffies < old_jiffies)
> ++high_jiffies;
>
> You will need a spin lock around that on 32 bit systems, but that is
> true for anything that tries to do 64 bit counter updates on a 32 bit
> system. None of your suggestions will work on ix86, it does not
> support atomic updates on 64 bit fields in hardware.
As it turns out I already have a spinlock on the update jiffies code.
The reason one would want to use a 64-bit integer is that the compiler
does a MUCH better job of the ++, i.e. it just does an add carry. No
if, no jmp. I suppose I need to lock the read also, but it is not done
often and will hardly ever block.
I am beginning to think that defining a u64 and casting, i.e.:
#define jiffies (unsigned long volitial)jiffies_u64
is the way to go.
George
In article <[email protected]>,
george anzinger <[email protected]> wrote:
>
>I am beginning to think that defining a u64 and casting, i.e.:
>
>#define jiffies (unsigned long volitial)jiffies_u64
>
>is the way to go.
..except for gcc being bad at even 64->32-bit casts like the above. It
will usually still load the full 64-bit value, and then only use the low
bits.
The efficient and sane way to do it is:
/*
* The 64-bit value is not volatile - you MUST NOT read it
* without holding the spinlock
*/
u64 jiffies_64;
/*
* Most people don't necessarily care about the full 64-bit
* value, so we can just get the "unstable" low bits without
* holding the lock. For historical reasons we also mark
* it volatile so that busy-waiting doesn't get optimized
* away in old drivers.
*/
#if defined(__LITTLE_ENDIAN) || (BITS_PER_LONG > 32)
#define jiffies (((volatile unsigned long *)&jiffies_64)[0])
#else
#define jiffies (((volatile unsigned long *)&jiffies_64)[1])
#endif
which looks ugly, but the ugliness is confined to that one place, and
none of the users will ever have to care..
Linus
Linus Torvalds wrote:
>
> In article <[email protected]>,
> george anzinger <[email protected]> wrote:
> >
> >I am beginning to think that defining a u64 and casting, i.e.:
> >
> >#define jiffies (unsigned long volitial)jiffies_u64
> >
> >is the way to go.
>
> ..except for gcc being bad at even 64->32-bit casts like the above. It
> will usually still load the full 64-bit value, and then only use the low
> bits.
>
> The efficient and sane way to do it is:
>
> /*
> * The 64-bit value is not volatile - you MUST NOT read it
> * without holding the spinlock
> */
Given that the spinlock would have to be spin_lock_irq (jiffies is
updated in clock interrupt code), is there a way to avoid the lock? The
following code does it for UP systems, given it is not rearranged. Is
there something like this that will work for
SMP systems?
(assumeing the defines below):
do {
jiffies_f = jiffies;
jiffies_64_f = jiffies_64;
}
while ( jiffies_f != jiffies);
If all things are in order, this will work on UP. Order could be
enforced by using locked instructions for the jiffies access...
George
> u64 jiffies_64;
>
> /*
> * Most people don't necessarily care about the full 64-bit
> * value, so we can just get the "unstable" low bits without
> * holding the lock. For historical reasons we also mark
> * it volatile so that busy-waiting doesn't get optimized
> * away in old drivers.
> */
> #if defined(__LITTLE_ENDIAN) || (BITS_PER_LONG > 32)
> #define jiffies (((volatile unsigned long *)&jiffies_64)[0])
> #else
> #define jiffies (((volatile unsigned long *)&jiffies_64)[1])
> #endif
>
> which looks ugly, but the ugliness is confined to that one place, and
> none of the users will ever have to care..
>
> Linus