Re: [PATCH v2] clarify usage expectations for cnt32_to_63()

Nicolas Pitre
2008-11-10T21:35:05Z

On Sun, 9 Nov 2008, Andrew Morton wrote:

> On Sun, 09 Nov 2008 23:20:00 -0500 (EST) Nicolas Pitre <nico@cam.org> wrote:
>
> > On Sun, 9 Nov 2008, Mathieu Desnoyers wrote:
> >
> > > * Nicolas Pitre (nico@cam.org) wrote:
> > > > Do you really have such instances where multiple call sites are needed?
> > > > That sounds even more confusing to me than the current model. Better
> > > > encapsulate the usage of this macro within some function which has a
> > > > stronger meaning, such as sched_clock(), and call _that_ from multiple
> > > > sites instead.
> > >
> > > I see a few reasons for it :
> > >
> > > - If we want to inline the whole read function so we don't pay the extra
> > > runtime cost of a function call, this would become required.
> >
> > You can inline it as you want as long as it remains in the same .c file.
> > The static variable is still shared amongst all call sites in that case.
>
> Please don't rely upon deep compiler behaviour like that. It is
> unobvious to the reader and it might break if someone uses it incorrectly,
> or if the compiler implementation changes, or if a non-gcc compiler is
> used, etc.

If a compiler doesn't reference the same storage for a static variable
used by a function that gets inlined in the same compilation unit then
it is utterly broken.

> It is far better to make the management of the state explicit and at
> the control of the caller. Get the caller to allocate the state and
> pass its address into this function. Simple, clear, explicit and
> robust.

Sigh... What about this compromize then?

diff --git a/include/linux/cnt32_to_63.h b/include/linux/cnt32_to_63.h
index 7605fdd..74ce767 100644
--- a/include/linux/cnt32_to_63.h
+++ b/include/linux/cnt32_to_63.h
@@ -32,8 +32,9 @@ union cnt32_to_63 {

/**
- * cnt32_to_63 - Expand a 32-bit counter to a 63-bit counter
+ * __cnt32_to_63 - Expand a 32-bit counter to a 63-bit counter
* @cnt_lo: The low part of the counter
+ * @cnt_hi_p: Pointer to storage for the extended part of the counter
*
* Many hardware clock counters are only 32 bits wide and therefore have
* a relatively short period making wrap-arounds rather frequent. This
@@ -75,16 +76,31 @@ union cnt32_to_63 {
* clear-bit instruction. Otherwise caller must remember to clear the top
* bit explicitly.
*/
-#define cnt32_to_63(cnt_lo) \
+#define __cnt32_to_63(cnt_lo, cnt_hi_p) \
({ \
- static u32 __m_cnt_hi; \
union cnt32_to_63 __x; \
- __x.hi = __m_cnt_hi; \
+ __x.hi = *(cnt_hi_p); \
smp_rmb(); \
__x.lo = (cnt_lo); \
if (unlikely((s32)(__x.hi ^ __x.lo) < 0)) \
- __m_cnt_hi = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \
+ *(cnt_hi_p) = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \
__x.val; \
})

+/**
+ * cnt32_to_63 - Expand a 32-bit counter to a 63-bit counter
+ * @cnt_lo: The low part of the counter
+ *
+ * This is the same as __cnt32_to_63() except that the storage for the
+ * extended part of the counter is implicit. Because this uses a static
+ * variable, a user of this code must not be an inline function unless
+ * that function is contained in a single .c file for a given counter.
+ * All usage requirements for __cnt32_to_63() also apply here as well.
+ */
+#define cnt32_to_63(cnt_lo) \
+({ \
+ static u32 __m_cnt_hi; \
+ __cnt32_to_63(cnt_lo, &__m_cnt_hi); \
+})
+
#endif

Nicolas